Hello Yann, All,

Thanks for the detailed analysis!

Le 22/05/2021 à 03:08, Yann Sionneau a écrit :
> Hello,
> 
> I think my previous analysis showing the r31 and r13 computations are OK still
> hold but my conclusion that the issue is with relocation is false.

By enabling some debug option in uClibc-ng I tried to understand the working vs
crashing case:

I noticed a similar result regarding the "_dl_elf_main" address.

https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/ldso/ldso/dl-startup.c#n364

In the crashing case (#if):
transfering control to application @ 0xb0224

In the working case (#else):
transfering control to application @ 0x1009a4b4

> 
> I attach a small patch that seems to greatly improve the situation (but I 
> think
> it's not the final patch yet, some other things might need changes)
> 
> I think the issue is due to the fact that now (since
> https://github.com/buildroot/buildroot/commit/f9b539bf4054d55da69280b19f4b99a91cbe6e0b)
> gcc is calling gas using -msecureplt, enable the secureplt.

I didn't tried to revert this patch and enable BR2_PIC_PIE in Buildroot at the
same time.

> 
> Previous PLT was code written on-the-fly from the uClibc relocation handler
> (which has the drawback of needing writable PLT):
> https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/ldso/ldso/powerpc/elfinterp.c#n237
> 
> New PLT, instead of just having a relocation pointing to it contains real code
> like this:
> 
> 000b56a0 <00000000.plt_pic32.__uClibc_main>:
>    b56a0:       81 7e 03 7c     lwz     r11,892(r30)
>    b56a4:       7d 69 03 a6     mtctr   r11
>    b56a8:       4e 80 04 20     bctr
>    b56ac:       60 00 00 00     nop
> 
> This is where the crash is, the lwz triggers a segfault because r30 is not
> initialized.
> 
> The new PLT uses r30 as got pointer.
> 
> by just adding a "r30 = r31" in crt1.S I get buildroot to boot. (see attached 
> patch)
> 
> We can see that in glibc start.S r30 is indeed set:
> https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/powerpc32/start.S;h=39ce1a18ff6fe19cf0f5c0d8344f46cbb1fff998;hb=HEAD#l80

Indeed, I noticed r30 being used by Glibc.

> 
> Also see the comment above.
> 
> So I think the right direction is keeping PPC_REL16 code and adding the 
> missing
> r30 got pointer.
> 
> I must still be missing something because for instance ldd crashes.
> 
> What do you think?

I guess we can follow Glibc developers and only support the HAVE_ASM_PPC_REL16
case. I don't think anyone is building a toolchain with an old binutils missing
ppc REL16 support.

Best regards,
Romain

> 
> Le 21/05/2021 à 16:48, Yann Sionneau a écrit :
>>
>> Hello,
>>
>> I've stayed silent so far but I've done some investigation on this one.
>>
>> It's not yet clear to me why there is this code path:
>>
>> |#ifdef __PIC__ # ifdef HAVE_ASM_PPC_REL16 bcl 20,31,1f 1: mflr r31 addis
>> r31,r31,_GLOBAL_OFFSET_TABLE_-1b@ha addi r31,r31,_GLOBAL_OFFSET_TABLE_-1b@l #
>> else bl _GLOBAL_OFFSET_TABLE_-4@local mflr r31 # endif #endif |||
>>
>> If I understood correctly, the "new" (so I guess "better ?") way of doing is
>> by using the PPC_REL16 reloc.
>>
>> Code seems bigger, and uses 2 relocs, compared to the other code path which
>> uses just 1 reloc.
>>
>> So, why is the 1st better ?
>>
>> I am betting here that : it's because by using 2 16-bit relocs, you can 
>> indeed
>> address 32 bit and reach the .got even if it is very far away from the 
>> current
>> code.
>>
>> If you are stuck with only 16 bits ... it can fail.
>>
>> So, I am guessing (please if someone can confirm) that your fix will work in
>> most cases ... but can fail when got is too far away to fit in the 16 bit
>> reloc targeting the "bl" insn immediate.
>>
>> I think it would be better to understand why the first code path does not 
>> work
>> well.
>>
>> Here is the current state of my investigations:
>>
>> I compiled both versions (with and without ppc_rel16) to compare what's
>> happening in both cases.
>>
>> busybox_unstripped in the no_rel16 (#else) case:
>> https://salamandar.fr/lufi/r/4TrBm3U7q5#z3J3Z3G24BTPJnQKD/EzGhAk/n3YHZSZF3hNde2tU98=
>>
>> busybox_unstripped in the ppc_rel16 (#if) case:
>> https://salamandar.fr/lufi/r/pQ79KBb5wU#HFlcBZIVngZFVzvObe/afqeNgMEbMtwDk9ajmplFRtA=
>>
>> In the working case (#else):
>>
>> #################
>>
>> the _start symbol contains:
>>
>>    b022c:       48 03 fd f9     bl      f0024 <__TMC_END__+0x10>
>>    b0230:       7f e8 02 a6     mflr    r31
>>    b0234:       81 bf ff f0     lwz     r13,-16(r31)
>>
>> to load the r13 reg with SDA (Small Data Area) pointer.
>>
>> 0xf0024 is in the got which contains:
>>
>> 000f0014 <.got>:
>>         ...
>>    f0024:       4e 80 00 21     blrl
>>
>> 000f0028 <_GLOBAL_OFFSET_TABLE_>:
>>    f0028:       00 0e ff 34     .long 0xeff34
>>         ...
>> so basically we jump to the got, we execute "blrl" which IIUC jumps back to
>> our _start but with LR (link register) == 0xf0028 (nextpc)
>>
>> then mflr (move from link register) makes it so that r31 == 0xf0028
>>
>> Then we lwz r13 = * (0xf0028 - 16) == * 0xf0018
>>
>> 0xf0018 is in the .got too and seems to be the target of a R_PPC_RELATIVE
>> relocation which I *think* will end up with the 0xf0028 value which is the
>> address of "_GLOBAL_OFFSET_TABLE_" symbol.
>>
>> In http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf we can read p.76:
>>
>> "In a shared object,_SDA_BASE_is defined to have the same value
>> as_GLOBAL_OFFSET_TABLE_"
>>
>> So it seems all is indeed OK.
>>
>> |##############################################|
>>
>> |Now, in the crashing case (HAVE_ASM_PPC_REL16 = 1):|
>>
>> ||||
>>
>> the _start symbol contains:
>>
>>    b022c:       42 9f 00 05     bcl     20,4*cr7+so,b0230 <_start+0xc>
>>    b0230:       7f e8 02 a6     mflr    r31
>>    b0234:       3f ff 00 05     addis   r31,r31,5
>>    b0238:       3b ff f8 6c     addi    r31,r31,-1940
>>    b023c:       81 bf ff f4     lwz     r13,-12(r31)
>>
>> So we branch to 0xb0230 (nextpc) to move link register to r31 which ends up
>> with the value 0xb0230.
>>
>> we do r31 = r31 + 0x10000 * 5 = 0x100230
>>
>> we do r31 = r31 - 1940 = 0xffa9c
>>
>> Then we load r13 = *(0xffa9c - 12) = *(0xffa90)
>>
>> 0xffa90 seems to be the target of a R_PPC_RELATIVE relocation that targets
>> 0xffa9c which is the address of the _GLOBAL_OFFSET_TABLE_ symbol.
>>
>> The code seems correct, I am guessing the relocation handling might be the
>> cause of the problem?
>>
>> It might be interesting to compare glibc and uclibc-ng for PowerPC for the
>> handling of R_PPC_RELATIVE reloc.
>>
>> Sorry I don't have any quick fix, I'm just sharing my thoughts on the issue.
>>
>> Cheers!
>>
>> Yann
>>
>> On 21/05/2021 10:34, Waldemar Brodkorb wrote:
>>> Hi Romain,
>>>
>>> can you confirm that attached patch works for you?
>>> I tested with non-PIE and PIE and both seems to work.
>>>
>>> best regards
>>>  Waldemar
>>>
>>> Romain Naour wrote,
>>>
>>>> Hi Waldemar,
>>>>
>>>> Le 19/05/2021 à 00:09, Waldemar Brodkorb a écrit :
>>>>> Hi Romain,
>>>>> Romain Naour wrote,
>>>>>
>>>>>> Hello,
>>>>>>
>>>>>> Recently in Buildroot the option BR2_PIC_PIE has been enabled by default 
>>>>>> along
>>>>>> with other hardening features [1]. Since then some ppc defconfig such
>>>>>> qemu_ppc_e500mc_defconfig are failing to boot due to a segfault in init 
>>>>>> program.
>>>>>>
>>>>>> The segfault appear very early in __uClibc_main while starting any 
>>>>>> binaries,
>>>>>> an issue located in crt1.S (powerpc)[2].
>>>>>>
>>>>>> After some trial and error, removing HAVE_ASM_PPC_REL16 from CFLAGS [3]
>>>>>> allow to generate a working system again. But this is actually wrong 
>>>>>> since
>>>>>> instead we should consider HAVE_ASM_PPC_REL16 always true nowadays.
>>>>> What if the assembly inside HAVE_ASM_PPC_REL16 isn't pie safe?
>>>> Good question.
>>>>
>>>> I guess it should work with pie (see PIEFLAG_NAME:=-fpie)
>>>> https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Rules.mak?h=v1.0.38#n480
>>>>
>>>> I did a try with Glibc without any problem with BR2_PIC_PIE enabled.
>>>>
>>>> Best regards,
>>>> Romain
>>>>
>>>>>> Indeed, Glibc removed HAVE_ASM_PPC_REL16 since version 2.22 [4] since 
>>>>>> "the
>>>>>> minimum binutils supports rel16 relocs". Binutils 2.22 supports 
>>>>>> R_PPC_REL16 as
>>>>>> default.
>>>>>>
>>>>>> uClibc-ng should remove HAVE_ASM_PPC_REL16 but keep the code as it was 
>>>>>> defined.
>>>>>> But this doesn't fix the initial issue.
>>>>>>
>>>>>> Any idea ?
>>>>>>
>>>>>> [1]
>>>>>> https://git.buildroot.net/buildroot/commit/?id=810ba387bec3c5b6904e8893fb4cb6f9d3717466
>>>>>> [2]
>>>>>> https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/libc/sysdeps/linux/powerpc/crt1.S?id=2bf4991c4dd7b50b74656011dea9c40464ff390c#n47
>>>>>> [3]
>>>>>> https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Rules.mak?id=2bf4991c4dd7b50b74656011dea9c40464ff390c#n486
>>>>>> [4]
>>>>>> https://sourceware.org/git/?p=glibc.git;a=commit;h=59261ad3eb345e0d7b9f5c73e1a09d046991cea5
>>>>> best regards
>>>>>  Waldemar
>>>>>
>>>>
>>>> _______________________________________________
>>>> devel mailing list
>>>> devel@uclibc-ng.org
>>>> https://mailman.uclibc-ng.org/cgi-bin/mailman/listinfo/devel
>>
>> _______________________________________________
>> devel mailing list
>> devel@uclibc-ng.org
>> https://mailman.uclibc-ng.org/cgi-bin/mailman/listinfo/devel
> 
> _______________________________________________
> devel mailing list
> devel@uclibc-ng.org
> https://mailman.uclibc-ng.org/cgi-bin/mailman/listinfo/devel
> 

_______________________________________________
devel mailing list
devel@uclibc-ng.org
https://mailman.uclibc-ng.org/cgi-bin/mailman/listinfo/devel

Reply via email to