Re: [PATCH v2] dl: Use "adr" assembler command to get proper load address on ARM
From: Lukasz Majewski <lukma@denx.de>
Date: 2021-10-15 13:00:04
On Fri, 15 Oct 2021 05:21:23 -0700 "H.J. Lu" [off-list ref] wrote:
On Fri, Oct 15, 2021 at 5:09 AM Szabolcs Nagy via Libc-alpha [off-list ref] wrote:quoted
The 10/15/2021 09:54, Lukasz Majewski wrote:quoted
This change is a partial revert of commit bca0f5cbc9257c13322b99e55235c4f21ba0bd82 "arm: Simplify elf_machine_{load_address,dynamic}" which imposed usage of __ehdr_start linker variable to get the address of loaded program. The elf_machine_load_address() function is declared in the sysdeps/arm/dl-machine.h header. It is called from (very early) _dl_start() entry point for the program. It shall return the load address of the dynamic linker program. With this revert the 'adr' assembler instruction is used instead of a place holder: arm-poky-linux-gnueabi-objdump -t ld-linux-armhf.so.3 | grep ehdr 00000000 l .note.gnu.build-id 00000000 __ehdr_start which is pre-set by binutils. The problem starts when one runs 'prelink' on the rootfs created with for example OE/Yocto. Then the _ehdr_start stays as 0x0, but the ELF header's sections have different addresses - for example 0x41000000 instead of the originally set 0x0. This is crucial when /sbin/init is executed. Value set in __ehdr_start symbol is not updated. This causes the program to crash very early when ld-linux-armhf.so.3's _dl_start is executed, as calculated offset for loader relocation is going to hit the kernel space (0xf7xxyyyy). It looks like the correct way to obtain the _dl_start offset on ARM is to use assembler instruction 'adr' at execution time (so the prelink assigned offset is taken into consideration) instead of __ehdr_start. With this patch we only modify the elf_machine_load_address() function, as it is called very early, before the ld-linux-armhf.so.3 is performing relocation (also its own one).i'd use an explanation like: __ehdr_start is a linker created symbol that points to the elf header. The elf header is at the beginning of the elf file and normally its virtual address is 0 in a shared library. This means the runtime address of __ehdr_start is the load address of the module. However if prelinking is applied to ld.so then all virtual addresses are moved by an offset so the runtime address of the elf header becomes the load address + prelink offset. The kernel does not treat prelinked ld.so specially so the load address is not 0, it still has to be computed, but simply using __ehdr_start no longer gives a correct value for that. This issue affects all targets with prelinking support, but so far we only got reports from OE/Yocto builds for arm that has prelinked ld.so. but i think a better fix is possible than revert:I think either prelink should be fixed not to prelink ld.so or Yocto should be fixed not to prelink ld.so.
Could you explain why? Was the relocation of ld.so (I guess that ld.so = ld-linux-arm.so) a bug from the very beginning and it was apparent just now? From my point of view - the original change to use __ehdr_start broke working setups, so it is a regression and shall be fixed in glibc. Anyway, it would be beneficial to have input from other glibc developers how to proceed with this issue. Best regards, Lukasz Majewski -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
Attachments
- (unnamed) [application/pgp-signature] 488 bytes