[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