[glibc] arm: Fix main-in-dso with non-BFD linkers (BZ 34098)

Adhemerval Zanella via Glibc-cvs <[email protected]> Wed, 3 Jun 2026 12:29:56 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=e951752cd0b13e8ec7eae6287b232a3babd28799

commit e951752cd0b13e8ec7eae6287b232a3babd28799
Author: Adhemerval Zanella <[email protected]>
Date:   Tue Jun 2 15:05:47 2026 -0300

    arm: Fix main-in-dso with non-BFD linkers (BZ 34098)
    
    Commit c2d6afb4a010 changed the PIC && !SHARED path of start.S (used by
    crt1.o and rcrt1.o) to load main via a R_ARM_REL32 data relocation.  When
    main is provided by a shared object, BFD ld synthesizes a canonical PLT
    entry for it, but other linkers (e.g. mold) do not, producing a broken
    binary that crashes at startup.
    
    Follow the aarch64 approach and reference main through a local __wrap_main
    that tail-calls it with a branch relocation, which every linker turns into
    a PLT entry.
    
    Checked on armv7a-linux-gnueabihf with and without --enable-default-pie.

Diff:
---
 sysdeps/arm/start.S | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/sysdeps/arm/start.S b/sysdeps/arm/start.S
index 3401daf89d..6b154dc7d3 100644
--- a/sysdeps/arm/start.S
+++ b/sysdeps/arm/start.S
@@ -105,7 +105,7 @@ _start:
 	/* Let the libc call main and exit with its return code.  */
 	bl __libc_start_main(PLT)
 # else
-	ldr a1, .L_main_rel	/* Load the relative offset of main. */
+	ldr a1, .L_main_rel	/* Load the relative offset of __wrap_main. */
 	adr a4, .L_main_rel	/* Load the actual runtime address of the label. */
 	add a1, a4, a1		/* Add them together to get the absolute address. */
 
@@ -136,13 +136,24 @@ _start:
 	.word main(GOT)
 # else
 .L_main_rel:
-	.word main - .L_main_rel
+	.word __wrap_main - .L_main_rel
 # endif
 #endif
 
        .cantunwind
        .fnend
 
+#if defined PIC && !defined SHARED
+/* When main is not defined in the executable but in a shared library then
+   a wrapper is needed, because crt1.o and rcrt1.o share this code and the
+   latter (static PIE) must avoid GOT relocations before __libc_start_main
+   is called.  The branch to main is turned into a PLT entry by every linker,
+   unlike a REL32 data relocation against main.  */
+	.type __wrap_main, %function
+__wrap_main:
+	b main
+#endif
+
 /* Define a symbol for the first piece of initialized data.  */
 	.data
 	.globl __data_start