diff options
author | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2021-01-11 09:04:53 +0000 |
---|---|---|
committer | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2021-01-13 13:35:00 +0000 |
commit | 86a4d3fa7d1bda3c02cf713cf289d6f893970117 (patch) | |
tree | 337a32e22b4157895cc701d3097acb76a2628103 | |
parent | 2ef23b520597f4ea1790a669b83e608f24f4cf12 (diff) | |
download | glibc-86a4d3fa7d1bda3c02cf713cf289d6f893970117.tar.gz glibc-86a4d3fa7d1bda3c02cf713cf289d6f893970117.tar.xz glibc-86a4d3fa7d1bda3c02cf713cf289d6f893970117.zip |
elf: work around a gcc bug in elf_get_dynamic_info
Since commit 2f056e8a5dd4dc0f075413f931e82cede37d1057 "aarch64: define PI_STATIC_AND_HIDDEN", building glibc with gcc-8 on aarch64 fails with /BLD/elf/librtld.os: in function `elf_get_dynamic_info': /SRC/elf/get-dynamic-info.h:70:(.text+0xad8): relocation truncated to fit: R_AARCH64_ADR_PREL_PG_HI21 against symbol `_rtld_local' defined in .data section in /BLD/elf/librtld.os This is a gcc bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98618 The bug is fixed on gcc-10 and not yet backported. gcc-9 is affected, but the issue happens to not trigger in glibc, gcc-8 and older seems to miscompile rtld.os. Rewriting the affected code in elf_get_dynamic_info seems to make the issue go away on <= gcc-9. The change makes the logic a bit clearer too (by separating the index computation and array update) and drops an older gcc workaround (since gcc 4.6 is no longer supported). Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
-rw-r--r-- | elf/get-dynamic-info.h | 41 |
1 files changed, 18 insertions, 23 deletions
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index 4f9aac63de..d8ec32377d 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -30,8 +30,6 @@ auto inline void __attribute__ ((unused, always_inline)) elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) { - ElfW(Dyn) *dyn = l->l_ld; - ElfW(Dyn) **info; #if __ELF_NATIVE_CLASS == 32 typedef Elf32_Word d_tag_utype; #elif __ELF_NATIVE_CLASS == 64 @@ -39,39 +37,36 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) #endif #if !defined RTLD_BOOTSTRAP && !defined STATIC_PIE_BOOTSTRAP - if (dyn == NULL) + if (l->l_ld == NULL) return; #endif - info = l->l_info; + ElfW(Dyn) **info = l->l_info; - while (dyn->d_tag != DT_NULL) + for (ElfW(Dyn) *dyn = l->l_ld; dyn->d_tag != DT_NULL; dyn++) { + d_tag_utype i; + if ((d_tag_utype) dyn->d_tag < DT_NUM) - info[dyn->d_tag] = dyn; + i = dyn->d_tag; else if (dyn->d_tag >= DT_LOPROC && dyn->d_tag < DT_LOPROC + DT_THISPROCNUM) - { - /* This does not violate the array bounds of l->l_info, but - gcc 4.6 on sparc somehow does not see this. */ - DIAG_PUSH_NEEDS_COMMENT; - DIAG_IGNORE_NEEDS_COMMENT (4.6, - "-Warray-bounds"); - info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn; - DIAG_POP_NEEDS_COMMENT; - } + i = dyn->d_tag - DT_LOPROC + DT_NUM; else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM) - info[VERSYMIDX (dyn->d_tag)] = dyn; + i = VERSYMIDX (dyn->d_tag); else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM) - info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM] = dyn; + i = DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM; else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM) - info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn; + i = DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM; else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM) - info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn; - ++dyn; + i = DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM; + else + continue; + + info[i] = dyn; } #define DL_RO_DYN_TEMP_CNT 8 |