bug: GOLD handling of Sparc PLTREL
David Miller
davem@davemloft.net
Tue Feb 9 06:03:00 GMT 2010
From: David Miller <davem@davemloft.net>
Date: Mon, 08 Feb 2010 22:01:21 -0800 (PST)
> # ifdef ELF_MACHINE_PLTREL_OVERLAP
> # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
...
> (##RELOC here is RELA)
And for reference here is the code that gets passed those ranges,
from elf/do-rel.h:
auto inline void __attribute__ ((always_inline))
elf_dynamic_do_rel (struct link_map *map,
ElfW(Addr) reladdr, ElfW(Addr) relsize,
int lazy)
{
const ElfW(Rel) *r = (const void *) reladdr;
const ElfW(Rel) *end = (const void *) (reladdr + relsize);
ElfW(Addr) l_addr = map->l_addr;
#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP
/* We never bind lazily during ld.so bootstrap. Unfortunately gcc is
not clever enough to see through all the function calls to realize
that. */
if (lazy)
{
/* Doing lazy PLT relocations; they need very little info. */
for (; r < end; ++r)
elf_machine_lazy_rel (map, l_addr, r);
}
else
#endif
{
const ElfW(Sym) *const symtab =
(const void *) D_PTR (map, l_info[DT_SYMTAB]);
ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL
? 0 : map->l_info[RELCOUNT_IDX]->d_un.d_val);
const ElfW(Rel) *relative = r;
r = r + MIN (nrelative, relsize / sizeof (ElfW(Rel)));
#ifndef RTLD_BOOTSTRAP
/* This is defined in rtld.c, but nowhere in the static libc.a; make
the reference weak so static programs can still link. This
declaration cannot be done when compiling rtld.c (i.e. #ifdef
RTLD_BOOTSTRAP) because rtld.c contains the common defn for
_dl_rtld_map, which is incompatible with a weak decl in the same
file. */
# ifndef SHARED
weak_extern (GL(dl_rtld_map));
# endif
if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
# if !defined DO_RELA || defined ELF_MACHINE_REL_RELATIVE
/* Rela platforms get the offset from r_addend and this must
be copied in the relocation address. Therefore we can skip
the relative relocations only if this is for rel
relocations or rela relocations if they are computed as
memory_loc += l_addr... */
if (l_addr != 0)
# else
/* ...or we know the object has been prelinked. */
if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)])
# endif
#endif
for (; relative < r; ++relative)
DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);
#ifdef RTLD_BOOTSTRAP
/* The dynamic linker always uses versioning. */
assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
#else
if (map->l_info[VERSYMIDX (DT_VERSYM)])
#endif
{
const ElfW(Half) *const version =
(const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
for (; r < end; ++r)
{
ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
&map->l_versions[ndx],
(void *) (l_addr + r->r_offset));
}
}
#ifndef RTLD_BOOTSTRAP
else
for (; r < end; ++r)
elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
(void *) (l_addr + r->r_offset));
#endif
}
}
More information about the Binutils
mailing list