[PATCH] elf/get-dynamic-info.h: fix early GNU_HASH processing on ia64
Mike Frysinger
vapier@gentoo.org
Mon Dec 28 05:13:00 GMT 2015
On 26 Dec 2015 19:32, slyich@gmail.com wrote:
> The following code when being
> called with l = _rtld_local._dl_rtld_map
> info = l->l_info
>
> elf_get_dynamic_info(struct link_map *l,ElfW(Dyn) *dyn) {
> ...
> info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
> + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
> ...
>
> led to generation of the follwoing assembly code:
>
> [MMI] ld8 r14=[r32];; # r14 = dyn->d_tag
> shladd r15=r14,3,r0 # r15 = dyn->d_tag * 8
> addl r14=163312,r1;; # r14 = gp + @ltoffx(_rtld_local#+0x380000000)
> [MMI] ld8 r14=[r14];;
> adds r14=992,r14 # r14 = [abs_reloc] + 992
> nop.i 0x0;;
> [MMI] nop.m 0x0
> sub r14=r14,r15
> nop.i 0x0;;
> [MIB] st8 [r14]=r32 # [[abs_reloc] + 992] = dyn
> nop.i 0x0
> br.ret.sptk.many b0;;
>
> This 'abs_reloc' is a relocation of R_IA64_REL64LSB type.
>
> objdump -r -R ld.so:
> DYNAMIC RELOCATION RECORDS
> OFFSET TYPE VALUE
> ...
> 0000000000052910 REL64LSB *ABS*+0x0000000380052a60
>
> After gcc's preprocessor and constant propagation phase
> the code
>
> info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
> + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
>
> became equivalent equivalent to:
>
> _rtld_local._dl_rtld_map.l_info[(0x6ffffeff - dyn->d_tag) + 66]
>
> (0x6ffffeff + 66) * 8 + 2520 = 0x3800003e0
> # 2520 is offset of '_rtld_local._dl_rtld_map.l_info'
> # 0x3e0 = 992
>
> To workaround generation of that huge offset and relocation
> I've moved index computation into a separate variable to trick
> gcc into simpler code.
i don't think this change is what we want -- you're modifying common code
in a non-obvious way to trick gcc on a specific arch to generate "better"
code. future versions of gcc (or reasonable code shuffling here) could
easily break this behavior.
from reading your analysis, it seems to come down to:
- ia64 gcc generates a reloc (R_IA64_REL64LSB) in elf_get_dynamic_info
(specifically, the DT_GNU_HASH type)
- that reloc type isn't processed until after in ELF_DYNAMIC_RELOCATE()
- ELF_DYNAMIC_RELOCATE() relies on the DT info being initialized in
elf_get_dynamic_info in order to process the relocs
- elf_get_dynamic_info crashes because reloc is uninitialized
this scenario can come up with any of the cases in elf_get_dynamic_info,
not just ones in the DT_ADDRRNG range. so even this minor reworking of
the code for these values does nothing for the others.
i don't think we can really split up the elf_get_dynamic_info logic into
an "early" and "late" phase as there might be DT sections we need even in
the "early" phase :/.
since we understand the source of the problem now -- rather than gcc being
horribly broken and generating bad code, it's just generating relocs in a
way that upset the ldso bootstrap -- i don't have a problem including this
workaround in Gentoo. funnily enough, i wrote the same patch almost two
years ago in gcc/60558. i just didn't want to deploy anything in case the
glibc crash was a harbinger.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://sourceware.org/pipermail/libc-alpha/attachments/20151228/993a8eb3/attachment.sig>
More information about the Libc-alpha
mailing list