> Date: Wed, 12 Aug 2015 15:48:57 +0200 (CEST)
> From: Mark Kettenis <mark.kette...@xs4all.nl>
> 
> 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.

ping?

This will also make my life easier with the secure-plt changes that
are in the pipeline.

> 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