I spent some time today figuting out why the binutils update broke ld
-Z on powerpc.  Turns out to be a fairly thorny issue.

The new binutils discard empty setions.  As a result the .gotpad0 and
.gotpad1 sections have disappeared.  And a s a consequence the
__got_start and __got_end symbols are now "absolute" symbols as the
section they referenced to is no longer there.  For example, an older
libc has:

   845: 000eeb68     0 NOTYPE  GLOBAL DEFAULT   17 __got_start

whereas -current has:

   810: 000eeb58     0 NOTYPE  GLOBAL DEFAULT  ABS __got_start

On powerpc, crt0.o has weak references to __got_start and __got_end.
When building a binary with ld -Z, these are resolved to the absolute
symbols from libc.  At runtime we then use these values, relocated as
if they were addresses within the binary itself, to change protections
and flush the instruction cache.  This is very likely to result in a
segmentation fault.

There is probably a linker bug here, as it doesn't make any sense for
the linker to pick the address of these symbols from libc and stick it
into the binary.  But I'm not sure about this.  And it isn't all that
obvious what the fix would be.  Is the bug that the symbols end up as
absolute?  Or is the problem that it sibsequently resolves these to
the values from libc.so?

It does point out a fundamental weakness about the approach we've
taken with the __plt_start/end and __got_start/end synbols.  They work
fine of you use something like dlsym(3) to lookup the value for a
specific object, but if you rely on the default symbol resolution, it
isn't clear if you get the right version.  Therefore I think that the
powerpc crt0.o code shouldn't be doing what it is doing.  The diff
below removes that code.

This diff has a downside though.  The GOT on -static -nopie binaries
will no longer be read-only.  I don't think that is a big loss, as
-static -pie binaries are the default now and those do get a read-only
GOT.

If we think a read-only GOT for -static binaries is still important,
there are a few other potential options to achive this that don't need
to rely on __got_start/end.


Index: powerpc/md_init.h
===================================================================
RCS file: /cvs/src/lib/csu/powerpc/md_init.h,v
retrieving revision 1.3
diff -u -p -r1.3 md_init.h
--- powerpc/md_init.h   26 Dec 2014 13:52:01 -0000      1.3
+++ powerpc/md_init.h   12 Aug 2015 13:08:28 -0000
@@ -64,88 +64,20 @@
 #include <sys/syscall.h>       /* for SYS_mprotect */
 
 #define STR(x) __STRING(x)
+
 #define        MD_CRT0_START                                                   
\
 __asm(                                                                 \
 "      .text                                                           \n" \
 "      .section        \".text\"                                       \n" \
 "      .align 2                                                        \n" \
-"      .size   __got_start, 0                                          \n" \
-"      .type   __got_start, @object                                    \n" \
-"      .size   __got_end, 0                                            \n" \
-"      .type   __got_end, @object                                      \n" \
-"      .weak   __got_start                                             \n" \
-"      .weak   __got_end                                               \n" \
 "      .globl  _start                                                  \n" \
 "      .type   _start, @function                                       \n" \
 "      .globl  __start                                                 \n" \
 "      .type   __start, @function                                      \n" \
 "_start:                                                               \n" \
 "__start:                                                              \n" \
-"      # move argument registers to saved registers for startup flush  \n" \
-"      # ...except r6 (auxv) as ___start() doesn't need it             \n" \
-"      mr %r25, %r3                                                    \n" \
-"      mr %r24, %r4                                                    \n" \
-"      mr %r23, %r5                                                    \n" \
-"      mr %r22, %r7                                                    \n" \
-"      mflr    %r27    /* save off old link register */                \n" \
-"      bl      1f                                                      \n" \
-"      # this instruction never gets executed but can be used          \n" \
-"      # to find the virtual address where the page is loaded.         \n" \
-"      bl _GLOBAL_OFFSET_TABLE_@local-4                                \n" \
-"1:                                                                    \n" \
-"      mflr    %r6             # this stores where we are (+4)         \n" \
-"      lwz     %r18, 0(%r6)    # load the instruction at offset_sym    \n" \
-"                              # it contains an offset to the location \n" \
-"                              # of the GOT.                           \n" \
-"                                                                      \n" \
-"      rlwinm %r18,%r18,0,8,30 # mask off the offset portion of the instr. \n" 
\
-"                                                                      \n" \
-"      /*                                                              \n" \
-"       * these adds effectively calculate the value the               \n" \
-"       * bl _GLOBAL_OFFSET_TABLE_@local-4                             \n" \
-"       * operation that would be below would calculate.               \n" \
-"       */                                                             \n" \
-"      add     %r28, %r18, %r6                                         \n" \
-"                                                                      \n" \
-"      addi    %r3,%r28,4              # calculate the actual got addr \n" \
-"      lwz     %r0,__got_start@got(%r3)                                \n" \
-"      cmpwi   %r0,0                                                   \n" \
-"      beq     4f                                                      \n" \
-"      cmpw    %r0,%r28                                                \n" \
-"      bne     4f                                                      \n" \
-"      lwz     %r4,__got_end@got(%r3)                                  \n" \
-"      cmpwi   %r4,0                                                   \n" \
-"      beq     2f                                                      \n" \
-"                                                                      \n" \
-"      sub     %r4, %r4, %r0                                           \n" \
-"      b 3f                                                            \n" \
-"2:                                                                    \n" \
-"      li      %r4, 4                                                  \n" \
-"3:                                                                    \n" \
-"                                                                      \n" \
-"      /* mprotect GOT to eliminate W+X regions in static binaries */  \n" \
-"      li      %r0, " STR(SYS_mprotect) "                              \n" \
-"      mr      %r3, %r28                                               \n" \
-"      li      %r5, 5  /* (PROT_READ|PROT_EXEC) */                     \n" \
-"      sc                                                              \n" \
-"                                                                      \n" \
-"4:                                                                    \n" \
-"      li      %r0, 0                                                  \n" \
-"      # flush the blrl instruction out of the data cache              \n" \
-"      dcbf    %r6, %r18                                               \n" \
-"      sync                                                            \n" \
-"      isync                                                           \n" \
-"      # make certain that the got table addr is not in the icache     \n" \
-"      icbi    %r6, %r18                                               \n" \
-"      sync                                                            \n" \
-"      isync                                                           \n" \
-"      mtlr %r27                                                       \n" \
-"      # move argument registers back from saved registers             \n" \
-"      # putting cleanup in r6 instead of r7                           \n" \
-"      mr %r3, %r25                                                    \n" \
-"      mr %r4, %r24                                                    \n" \
-"      mr %r5, %r23                                                    \n" \
-"      mr %r6, %r22                                                    \n" \
+"      # put cleanup in r6 instead of r7                               \n" \
+"      mr %r6, %r7                                                     \n" \
 "      b ___start                                                      \n" \
 )
 

Reply via email to