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.

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.

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

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?

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
From 20dccd825e63575d6bd2cb182c1eb202e1993fd1 Mon Sep 17 00:00:00 2001
From: Yann Sionneau <y...@sionneau.net>
Date: Fri, 21 May 2021 21:56:42 +0200
Subject: [PATCH] powerpc: fix PIE+secureplt builds

---
 Rules.mak                         | 1 +
 libc/sysdeps/linux/powerpc/crt1.S | 1 +
 2 files changed, 2 insertions(+)

diff --git a/Rules.mak b/Rules.mak
index 1fa09be23..95bcfae56 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -485,6 +485,7 @@ ifeq ($(TARGET_ARCH),powerpc)
 	PPC_HAS_REL16:=$(shell printf "\t.text\n\taddis 11,30,_GLOBAL_OFFSET_TABLE_-.@ha\n" | $(CC) -c -x assembler -o /dev/null -  2> /dev/null && echo -n y || echo -n n)
 	CPU_CFLAGS-$(PPC_HAS_REL16)+= -DHAVE_ASM_PPC_REL16
 	CPU_CFLAGS-$(CONFIG_E500) += "-D__NO_MATH_INLINES"
+	ASFLAGS += -mregnames
 
 endif
 
diff --git a/libc/sysdeps/linux/powerpc/crt1.S b/libc/sysdeps/linux/powerpc/crt1.S
index 27bfc5a5a..9f511fce3 100644
--- a/libc/sysdeps/linux/powerpc/crt1.S
+++ b/libc/sysdeps/linux/powerpc/crt1.S
@@ -53,6 +53,7 @@ _start:
 1:	mflr	r31
 	addis	r31,r31,_GLOBAL_OFFSET_TABLE_-1b@ha
 	addi	r31,r31,_GLOBAL_OFFSET_TABLE_-1b@l
+	addi	r30,r31,0
 # else
 	bl	_GLOBAL_OFFSET_TABLE_-4@local
 	mflr	r31
-- 
2.25.1


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

Reply via email to