summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorJan Klötzke <jan.kloetzke@kernkonzept.com>2025-03-18 07:41:47 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2025-03-22 09:11:30 +0100
commit03ca3d2fd4853c50f6bacbc3ff312d01a6ab9ad2 (patch)
tree2ee4294df1a0308124e91438fc409c2a4dc500cd /ldso
parentb99b7756228faecb8d506dba64bdb4970a965d5a (diff)
Use __ehdr_start to compute load address
So far, uclibc relied on the informal behaviour of GNU ld to put the link address of the _DYNAMIC symbol in the first GOT entry. This does not work with LLVM lld which does not follow this convention. Consequently, glibc has abandoned its usage in favour of using __ehdr_start as magic symbol to infer the load address [1]. Note that this implies that the link time address of __ehdr_start is *always* 0! So far, this seems to be the case on all platforms. [1] https://sourceware.org/bugzilla/show_bug.cgi?id=28203 Signed-off-by: Marcus Haehnel <marcus.haehnel@kernkonzept.com>
Diffstat (limited to 'ldso')
-rw-r--r--ldso/ldso/aarch64/dl-sysdep.h25
-rw-r--r--ldso/ldso/arm/dl-sysdep.h69
-rw-r--r--ldso/ldso/i386/dl-sysdep.h27
-rw-r--r--ldso/ldso/riscv32/dl-sysdep.h22
-rw-r--r--ldso/ldso/x86_64/dl-sysdep.h45
5 files changed, 48 insertions, 140 deletions
diff --git a/ldso/ldso/aarch64/dl-sysdep.h b/ldso/ldso/aarch64/dl-sysdep.h
index 6d9d2c1fb..3466920d9 100644
--- a/ldso/ldso/aarch64/dl-sysdep.h
+++ b/ldso/ldso/aarch64/dl-sysdep.h
@@ -54,28 +54,21 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
|| (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \
| (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY))
-/* Return the link-time address of _DYNAMIC. Conveniently, this is the
- first element of the GOT. */
-extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
-static __always_inline ElfW(Addr) __attribute__ ((unused))
-elf_machine_dynamic (void)
-{
- return _GLOBAL_OFFSET_TABLE_[0];
-}
-
/* Return the run-time load address of the shared object. */
static __always_inline ElfW(Addr) __attribute__ ((unused))
elf_machine_load_address (void)
{
- /* To figure out the load address we use the definition that for any symbol:
- dynamic_addr(symbol) = static_addr(symbol) + load_addr
-
- _DYNAMIC sysmbol is used here as its link-time address stored in
- the special unrelocated first GOT entry. */
+ extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
+ return (ElfW(Addr)) &__ehdr_start;
+}
- extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
- return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic ();
+/* Return the link-time address of _DYNAMIC. */
+static __always_inline ElfW(Addr) __attribute__ ((unused))
+elf_machine_dynamic (void)
+{
+ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
+ return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
}
static __always_inline void
diff --git a/ldso/ldso/arm/dl-sysdep.h b/ldso/ldso/arm/dl-sysdep.h
index 0f783e1c4..93e36b694 100644
--- a/ldso/ldso/arm/dl-sysdep.h
+++ b/ldso/ldso/arm/dl-sysdep.h
@@ -96,43 +96,6 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
| (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
#endif /* __FDPIC__ */
-/* Return the link-time address of _DYNAMIC. Conveniently, this is the
- first element of the GOT. We used to use the PIC register to do this
- without a constant pool reference, but GCC 4.2 will use a pseudo-register
- for the PIC base, so it may not be in r10. */
-static __always_inline Elf32_Addr __attribute__ ((unused))
-elf_machine_dynamic (void)
-{
- Elf32_Addr dynamic;
-#if !defined __thumb__
- __asm__ ("ldr %0, 2f\n"
- "1: ldr %0, [pc, %0]\n"
- "b 3f\n"
- "2: .word _GLOBAL_OFFSET_TABLE_ - (1b+8)\n"
- "3:" : "=r" (dynamic));
-#else
- int tmp;
- __asm__ (".align 2\n"
- "bx pc\n"
- "nop\n"
- ".arm\n"
- "ldr %0, 2f\n"
- "1: ldr %0, [pc, %0]\n"
- "b 3f\n"
- "2: .word _GLOBAL_OFFSET_TABLE_ - (1b+8)\n"
- "3:"
- ".align 2\n"
- "orr %1, pc, #1\n"
- "bx %1\n"
- ".force_thumb\n"
- : "=r" (dynamic), "=&r" (tmp));
-#endif
-
- return dynamic;
-}
-
-extern char __dl_start[] __asm__("_dl_start");
-
#ifdef __FDPIC__
/* We must force strings used early in the bootstrap into the data
segment. */
@@ -148,28 +111,16 @@ extern char __dl_start[] __asm__("_dl_start");
static __always_inline Elf32_Addr __attribute__ ((unused))
elf_machine_load_address (void)
{
-#if defined(__FDPIC__)
- return 0;
-#else
- Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
- Elf32_Addr pcrel_addr;
-#if defined __OPTIMIZE__ && !defined __thumb__
- __asm__ ("adr %0, _dl_start" : "=r" (pcrel_addr));
-#else
- /* A simple adr does not work in Thumb mode because the offset is
- negative, and for debug builds may be too large. */
- int tmp;
- __asm__ ("adr %1, 1f\n\t"
- "ldr %0, [%1]\n\t"
- "add %0, %0, %1\n\t"
- "b 2f\n\t"
- ".align 2\n\t"
- "1: .word _dl_start - 1b\n\t"
- "2:"
- : "=r" (pcrel_addr), "=r" (tmp));
-#endif
- return pcrel_addr - got_addr;
-#endif
+ extern const Elf32_Ehdr __ehdr_start attribute_hidden;
+ return (Elf32_Addr) &__ehdr_start;
+}
+
+/* Return the link-time address of _DYNAMIC. */
+static __always_inline Elf32_Addr __attribute__ ((unused))
+elf_machine_dynamic (void)
+{
+ extern Elf32_Dyn _DYNAMIC[] attribute_hidden;
+ return (Elf32_Addr) _DYNAMIC - elf_machine_load_address ();
}
static __always_inline void
diff --git a/ldso/ldso/i386/dl-sysdep.h b/ldso/ldso/i386/dl-sysdep.h
index b95328df4..8fc80a145 100644
--- a/ldso/ldso/i386/dl-sysdep.h
+++ b/ldso/ldso/i386/dl-sysdep.h
@@ -35,28 +35,21 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent
|| (type) == R_386_TLS_TPOFF) * ELF_RTYPE_CLASS_PLT) \
| (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
-/* Return the link-time address of _DYNAMIC. Conveniently, this is the
- first element of the GOT, a special entry that is never relocated. */
-extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
-static __always_inline Elf32_Addr __attribute__ ((unused, const))
-elf_machine_dynamic (void)
-{
- /* This produces a GOTOFF reloc that resolves to zero at link time, so in
- fact just loads from the GOT register directly. By doing it without
- an asm we can let the compiler choose any register. */
- return _GLOBAL_OFFSET_TABLE_[0];
-}
-
-extern Elf32_Dyn bygotoff[] __asm__ ("_DYNAMIC") attribute_hidden;
/* Return the run-time load address of the shared object. */
static __always_inline Elf32_Addr attribute_unused
elf_machine_load_address (void)
{
- /* Compute the difference between the runtime address of _DYNAMIC as seen
- by a GOTOFF reference, and the link-time address found in the special
- unrelocated first GOT entry. */
- return (Elf32_Addr) &bygotoff - elf_machine_dynamic ();
+ extern const Elf32_Ehdr __ehdr_start attribute_hidden;
+ return (Elf32_Addr) &__ehdr_start;
+}
+
+/* Return the link-time address of _DYNAMIC. */
+static __always_inline Elf32_Addr __attribute__ ((unused, const))
+elf_machine_dynamic (void)
+{
+ extern Elf32_Dyn _DYNAMIC[] attribute_hidden;
+ return (Elf32_Addr) _DYNAMIC - elf_machine_load_address ();
}
static __always_inline void
diff --git a/ldso/ldso/riscv32/dl-sysdep.h b/ldso/ldso/riscv32/dl-sysdep.h
index e0a59fddd..02296b148 100644
--- a/ldso/ldso/riscv32/dl-sysdep.h
+++ b/ldso/ldso/riscv32/dl-sysdep.h
@@ -59,22 +59,20 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
| (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
-/* Return the link-time address of _DYNAMIC. */
-static inline ElfW(Addr)
-elf_machine_dynamic (void)
-{
- extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__ ((visibility ("hidden")));
- return _GLOBAL_OFFSET_TABLE_;
-}
-
-
/* Return the run-time load address of the shared object. */
static __always_inline ElfW(Addr) __attribute__ ((unused))
elf_machine_load_address (void)
{
- ElfW(Addr) load_addr;
- __asm__ ("lla %0, _DYNAMIC" : "=r" (load_addr));
- return load_addr - elf_machine_dynamic ();
+ extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
+ return (ElfW(Addr)) &__ehdr_start;
+}
+
+/* Return the link-time address of _DYNAMIC. */
+static inline ElfW(Addr)
+elf_machine_dynamic (void)
+{
+ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
+ return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
}
static __always_inline void
diff --git a/ldso/ldso/x86_64/dl-sysdep.h b/ldso/ldso/x86_64/dl-sysdep.h
index ccf9a8851..58447a951 100644
--- a/ldso/ldso/x86_64/dl-sysdep.h
+++ b/ldso/ldso/x86_64/dl-sysdep.h
@@ -52,48 +52,21 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent
* ELF_RTYPE_CLASS_PLT) \
| (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY))
-/* 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 __always_inline Elf64_Addr __attribute__ ((unused))
-elf_machine_dynamic (void)
-{
- Elf64_Addr addr;
-
- /* This works because we have our GOT address available in the small PIC
- model. */
- addr = (Elf64_Addr) &_DYNAMIC;
-
- return addr;
-}
-
/* Return the run-time load address of the shared object. */
static __always_inline Elf64_Addr __attribute__ ((unused))
elf_machine_load_address (void)
{
- register Elf64_Addr addr, tmp;
-
- /* The easy way is just the same as on x86:
- leaq _dl_start, %0
- leaq _dl_start(%%rip), %1
- subq %0, %1
- but this does not work with binutils since we then have
- a R_X86_64_32S relocation in a shared lib.
-
- Instead we store the address of _dl_start in the data section
- and compare it with the current value that we can get via
- an RIP relative addressing mode. */
-
- __asm__ ("movq 1f(%%rip), %1\n"
- "0:\tleaq _dl_start(%%rip), %0\n\t"
- "subq %1, %0\n\t"
- ".section\t.data\n"
- "1:\t.quad _dl_start\n\t"
- ".previous\n\t"
- : "=r" (addr), "=r" (tmp) : : "cc");
+ extern const Elf64_Ehdr __ehdr_start attribute_hidden;
+ return (Elf64_Addr) &__ehdr_start;
+}
- return addr;
+/* Return the link-time address of _DYNAMIC. */
+static __always_inline Elf64_Addr __attribute__ ((unused))
+elf_machine_dynamic (void)
+{
+ extern Elf64_Dyn _DYNAMIC[] attribute_hidden;
+ return (Elf64_Addr) _DYNAMIC - elf_machine_load_address ();
}
static __always_inline void