s390: Simplify elf_machine_{load_address, dynamic} [BZ #31799]

If an executable is static PIE and has a non-zero load address
(compare to elf/tst-pie-address-static), it segfaults as
elf_machine_load_address() returns 0x0 and elf_machine_dynamic()
returns the run-time instead of link-time address of _DYNAMIC.

Now rely on __ehdr_start and _DYNAMIC as also done on other
architectures.

Checked back to old arch-levels that this approach works fine:
- 31bit: -march=g5
- 64bit: -march=z900

Note, that there is no static-PIE support on 31bit, but this
approach cleans it also up.

Furthermore this cleanup in glibc does not change anything
regarding the first GOT-element as the s390 ABI
(https://github.com/IBM/s390x-abi) explicitely defines:
The doubleword at _GLOBAL_OFFSET_TABLE_[0] is set by the linkage
editor to hold the address of the dynamic structure, referenced
with the symbol _DYNAMIC. This allows a program, such as the dynamic
linker, to find its own dynamic structure without having yet processed
its relocation entries. This is especially important for the dynamic
linker, because it must initialize itself without relying on other
programs to relocate its memory image.
This commit is contained in:
Stefan Liebler 2024-12-06 12:50:09 +01:00
parent e4e49583d9
commit 97b74cbbb0
2 changed files with 22 additions and 50 deletions

View File

@ -50,39 +50,22 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
}
/* Return the link-time address of _DYNAMIC. Conveniently, this is the
first element of the GOT. This must be inlined in a function which
uses global data. */
static inline Elf32_Addr
elf_machine_dynamic (void)
{
register Elf32_Addr *got;
__asm__( " bras %0,2f\n"
"1: .long _GLOBAL_OFFSET_TABLE_-1b\n"
"2: al %0,0(%0)"
: "=&a" (got) : : "0" );
return *got;
}
/* Return the run-time load address of the shared object. */
static inline Elf32_Addr
elf_machine_load_address (void)
{
Elf32_Addr addr;
/* Starting from binutils-2.23, the linker will define the magic symbol
__ehdr_start to point to our own ELF header. */
extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
return (ElfW(Addr)) &__ehdr_start;
}
__asm__( " bras 1,2f\n"
"1: .long _GLOBAL_OFFSET_TABLE_ - 1b\n"
" .long (_dl_start - 1b - 0x80000000) & 0x00000000ffffffff\n"
"2: l %0,4(1)\n"
" ar %0,1\n"
" al 1,0(1)\n"
" sl %0,_dl_start@GOT(1)"
: "=&d" (addr) : : "1" );
return addr;
/* Return the link-time address of _DYNAMIC. */
static inline Elf32_Addr
elf_machine_dynamic (void)
{
extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
}
/* Set up the loaded object described by L so its unrelocated PLT

View File

@ -44,33 +44,22 @@ elf_machine_matches_host (const Elf64_Ehdr *ehdr)
&& ehdr->e_ident[EI_CLASS] == ELFCLASS64;
}
/* Return the link-time address of _DYNAMIC. Conveniently, this is the
first element of the GOT. This must be inlined in a function which
uses global data. */
static inline Elf64_Addr
elf_machine_dynamic (void)
{
register Elf64_Addr *got;
__asm__ ( " larl %0,_GLOBAL_OFFSET_TABLE_\n"
: "=&a" (got) : : "0" );
return *got;
}
/* Return the run-time load address of the shared object. */
static inline Elf64_Addr
elf_machine_load_address (void)
{
Elf64_Addr addr;
/* Starting from binutils-2.23, the linker will define the magic symbol
__ehdr_start to point to our own ELF header. */
extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
return (ElfW(Addr)) &__ehdr_start;
}
__asm__( " larl %0,_dl_start\n"
" larl 1,_GLOBAL_OFFSET_TABLE_\n"
" lghi 2,_dl_start@GOT\n"
" slg %0,0(2,1)"
: "=&d" (addr) : : "1", "2" );
return addr;
/* Return the link-time address of _DYNAMIC. */
static inline Elf64_Addr
elf_machine_dynamic (void)
{
extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
}
/* Set up the loaded object described by L so its unrelocated PLT