Don't use the symbol name to lookup the symbol value when we can use

the symbol index defined by the relocation. The elf_lookup() support
function is to be used by elf_reloc() when symbol lookups need to be
done. The elf_lookup() function operates on the symbol index and
will do a symbol name based lookup when such is required, otherwise
it uses the symbol index directly. This solves the problem seen on
ia64 where the symbol hash table does not contain local symbols and
a symbol name based lookup would fail for those symbols.

Don't pass the symbol name to elf_reloc(), as it isn't used any more.
This commit is contained in:
Marcel Moolenaar 2002-04-25 01:22:16 +00:00
parent bacab7d655
commit d297ad160e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=95410
9 changed files with 168 additions and 86 deletions

View File

@ -38,13 +38,13 @@
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
elf_reloc(linker_file_t lf, const void *data, int type)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
Elf_Word rtype;
Elf_Word rtype, symidx;
const Elf_Rel *rel;
const Elf_Rela *rela;
@ -54,12 +54,14 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
where = (Elf_Addr *) (relocbase + rel->r_offset);
addend = *where;
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
break;
case ELF_RELOC_RELA:
rela = (const Elf_Rela *)data;
where = (Elf_Addr *) (relocbase + rela->r_offset);
addend = rela->r_addend;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
break;
default:
panic("elf_reloc: unknown relocation mode %d\n", type);
@ -71,9 +73,8 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_ALPHA_REFQUAD:
addr = (Elf_Addr)
linker_file_lookup_symbol(lf, sym, 1);
if (addr == NULL)
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
if (*where != addr)
@ -81,9 +82,8 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_ALPHA_GLOB_DAT:
addr = (Elf_Addr)
linker_file_lookup_symbol(lf, sym, 1);
if (addr == NULL)
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
if (*where != addr)
@ -92,9 +92,8 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
case R_ALPHA_JMP_SLOT:
/* No point in lazy binding for kernel modules. */
addr = (Elf_Addr)
linker_file_lookup_symbol(lf, sym, 1);
if (addr == NULL)
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)
*where = addr;

View File

@ -32,13 +32,13 @@
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
elf_reloc(linker_file_t lf, const void *data, int type)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
Elf_Word rtype;
Elf_Word rtype, symidx;
const Elf_Rel *rel;
const Elf_Rela *rela;
@ -48,12 +48,14 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
where = (Elf_Addr *) (relocbase + rel->r_offset);
addend = *where;
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
break;
case ELF_RELOC_RELA:
rela = (const Elf_Rela *)data;
where = (Elf_Addr *) (relocbase + rela->r_offset);
addend = rela->r_addend;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
break;
default:
panic("unknown reloc type %d\n", type);
@ -65,9 +67,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_386_32: /* S + A */
if (sym == NULL)
return -1;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
@ -76,9 +76,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_386_PC32: /* S + A - P */
if (sym == NULL)
return -1;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend - (Elf_Addr)where;
@ -96,9 +94,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_386_GLOB_DAT: /* S */
if (sym == NULL)
return -1;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)

View File

@ -32,13 +32,13 @@
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
elf_reloc(linker_file_t lf, const void *data, int type)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
Elf_Word rtype;
Elf_Word rtype, symidx;
const Elf_Rel *rel;
const Elf_Rela *rela;
@ -48,12 +48,14 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
where = (Elf_Addr *) (relocbase + rel->r_offset);
addend = *where;
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
break;
case ELF_RELOC_RELA:
rela = (const Elf_Rela *)data;
where = (Elf_Addr *) (relocbase + rela->r_offset);
addend = rela->r_addend;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
break;
default:
panic("unknown reloc type %d\n", type);
@ -65,9 +67,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_386_32: /* S + A */
if (sym == NULL)
return -1;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
@ -76,9 +76,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_386_PC32: /* S + A - P */
if (sym == NULL)
return -1;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend - (Elf_Addr)where;
@ -96,9 +94,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_386_GLOB_DAT: /* S */
if (sym == NULL)
return -1;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)

View File

@ -41,24 +41,24 @@ Elf_Addr link_elf_get_gp(linker_file_t);
extern Elf_Addr fptr_storage[];
static Elf_Addr
lookup_fdesc(linker_file_t lf, const char *sym)
lookup_fdesc(linker_file_t lf, Elf_Word symidx)
{
Elf_Addr addr;
int i;
static int eot = 0;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 0);
if (addr == NULL) {
addr = elf_lookup(lf, symidx, 0);
if (addr == 0) {
for (i = 0; i < lf->ndeps; i++) {
addr = lookup_fdesc(lf->deps[i], sym);
if (addr != NULL)
addr = lookup_fdesc(lf->deps[i], symidx);
if (addr != 0)
return (addr);
}
return (NULL);
return (0);
}
if (eot)
return (NULL);
return (0);
/*
* Lookup and/or construct OPD
@ -77,17 +77,17 @@ lookup_fdesc(linker_file_t lf, const char *sym)
printf("%s: fptr table full\n", __func__);
eot = 1;
return (NULL);
return (0);
}
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
elf_reloc(linker_file_t lf, const void *data, int type)
{
Elf_Addr relocbase = (Elf_Addr)lf->address;
Elf_Addr *where;
Elf_Addr addend, addr;
Elf_Word rtype;
Elf_Word rtype, symidx;
const Elf_Rel *rel;
const Elf_Rela *rela;
@ -96,6 +96,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
rel = (const Elf_Rel *)data;
where = (Elf_Addr *)(relocbase + rel->r_offset);
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
switch (rtype) {
case R_IA64_DIR64LSB:
case R_IA64_FPTR64LSB:
@ -111,6 +112,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
rela = (const Elf_Rela *)data;
where = (Elf_Addr *)(relocbase + rela->r_offset);
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
addend = rela->r_addend;
break;
default:
@ -121,35 +123,28 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
case R_IA64_NONE:
break;
case R_IA64_DIR64LSB: /* word64 LSB S + A */
if (sym == NULL)
return -1;
addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
return (-1);
*where = addr + addend;
break;
case R_IA64_FPTR64LSB: /* word64 LSB @fptr(S + A) */
if (sym == NULL)
return -1;
if (addend != 0) {
printf("%s: addend ignored for OPD relocation\n",
__func__);
}
addr = lookup_fdesc(lf, sym);
addr = lookup_fdesc(lf, symidx);
if (addr == 0)
return -1;
return (-1);
*where = addr;
break;
case R_IA64_REL64LSB: /* word64 LSB BD + A */
*where = relocbase + addend;
break;
case R_IA64_IPLTLSB:
if (sym == NULL)
return -1;
/* lookup_fdesc() returns the address of the OPD. */
addr = lookup_fdesc(lf, sym);
addr = lookup_fdesc(lf, symidx);
if (addr == 0)
return -1;
return (-1);
where[0] = *((Elf_Addr*)addr) + addend;
where[1] = *((Elf_Addr*)addr + 1);
break;
@ -159,5 +154,5 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
return -1;
}
return(0);
return (0);
}

View File

@ -904,8 +904,8 @@ relocate_file(elf_file_t ef)
if (rel) {
rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -918,8 +918,8 @@ relocate_file(elf_file_t ef)
if (rela) {
relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -932,8 +932,8 @@ relocate_file(elf_file_t ef)
if (rel) {
rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -946,8 +946,8 @@ relocate_file(elf_file_t ef)
if (rela) {
relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -1190,3 +1190,50 @@ link_elf_get_gp(linker_file_t lf)
return (Elf_Addr)ef->got;
}
#endif
/*
* Symbol lookup function that can be used when the symbol index is known (ie
* in relocations). It uses the symbol index instead of doing a fully fledged
* hash table based lookup when such is valid. For example for local symbols.
* This is not only more efficient, it's also more correct. It's not always
* the case that the symbol can be found through the hash table.
*/
Elf_Addr
elf_lookup(linker_file_t lf, Elf_Word symidx, int deps)
{
elf_file_t ef = (elf_file_t)lf;
const Elf_Sym *sym;
const char *symbol;
/* Don't even try to lookup the symbol if the index is bogus. */
if (symidx >= ef->nchains)
return (0);
sym = ef->symtab + symidx;
/*
* Don't do a full lookup when the symbol is local. It may even
* fail because it may not be found through the hash table.
*/
if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
/* Force lookup failure when we have an insanity. */
if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0)
return (0);
return ((Elf_Addr)ef->address + sym->st_value);
}
/*
* XXX we can avoid doing a hash table based lookup for global
* symbols as well. This however is not always valid, so we'll
* just do it the hard way for now. Performance tweaks can
* always be added.
*/
symbol = ef->strtab + sym->st_name;
/* Force a lookup failure if the symbol name is bogus. */
if (*symbol == 0)
return (0);
return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
}

View File

@ -904,8 +904,8 @@ relocate_file(elf_file_t ef)
if (rel) {
rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -918,8 +918,8 @@ relocate_file(elf_file_t ef)
if (rela) {
relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -932,8 +932,8 @@ relocate_file(elf_file_t ef)
if (rel) {
rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -946,8 +946,8 @@ relocate_file(elf_file_t ef)
if (rela) {
relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
@ -1190,3 +1190,50 @@ link_elf_get_gp(linker_file_t lf)
return (Elf_Addr)ef->got;
}
#endif
/*
* Symbol lookup function that can be used when the symbol index is known (ie
* in relocations). It uses the symbol index instead of doing a fully fledged
* hash table based lookup when such is valid. For example for local symbols.
* This is not only more efficient, it's also more correct. It's not always
* the case that the symbol can be found through the hash table.
*/
Elf_Addr
elf_lookup(linker_file_t lf, Elf_Word symidx, int deps)
{
elf_file_t ef = (elf_file_t)lf;
const Elf_Sym *sym;
const char *symbol;
/* Don't even try to lookup the symbol if the index is bogus. */
if (symidx >= ef->nchains)
return (0);
sym = ef->symtab + symidx;
/*
* Don't do a full lookup when the symbol is local. It may even
* fail because it may not be found through the hash table.
*/
if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
/* Force lookup failure when we have an insanity. */
if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0)
return (0);
return ((Elf_Addr)ef->address + sym->st_value);
}
/*
* XXX we can avoid doing a hash table based lookup for global
* symbols as well. This however is not always valid, so we'll
* just do it the hard way for now. Performance tweaks can
* always be added.
*/
symbol = ef->strtab + sym->st_name;
/* Force a lookup failure if the symbol name is bogus. */
if (*symbol == 0)
return (0);
return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
}

View File

@ -38,13 +38,13 @@
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
elf_reloc(linker_file_t lf, const void *data, int type)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
Elf_Word rtype;
Elf_Word rtype, symidx;
const Elf_Rel *rel;
const Elf_Rela *rela;
@ -54,12 +54,14 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
where = (Elf_Addr *) (relocbase + rel->r_offset);
addend = *where;
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
break;
case ELF_RELOC_RELA:
rela = (const Elf_Rela *)data;
where = (Elf_Addr *) (relocbase + rela->r_offset);
addend = rela->r_addend;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
break;
default:
panic("elf_reloc: unknown relocation mode %d\n", type);
@ -71,9 +73,8 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
break;
case R_PPC_GLOB_DAT:
addr = (Elf_Addr)
linker_file_lookup_symbol(lf, sym, 1);
if (addr == NULL)
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
if (*where != addr)
@ -82,9 +83,8 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
case R_PPC_JMP_SLOT:
/* No point in lazy binding for kernel modules. */
addr = (Elf_Addr)
linker_file_lookup_symbol(lf, sym, 1);
if (addr == NULL)
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)
*where = addr;

View File

@ -168,13 +168,13 @@ static long reloc_target_bitmask[] = {
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type, const char *symname)
elf_reloc(linker_file_t lf, const void *data, int type)
{
const Elf_Rela *rela;
Elf_Addr relocbase;
Elf_Half *where32;
Elf_Addr *where;
Elf_Word rtype;
Elf_Word rtype, symidx;
Elf_Addr value;
Elf_Addr mask;
caddr_t addr;
@ -187,6 +187,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *symname)
where = (Elf_Addr *)(relocbase + rela->r_offset);
where32 = (Elf_Half *)where;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
if (rtype == R_SPARC_NONE)
return (0);
@ -201,7 +202,7 @@ elf_reloc(linker_file_t lf, const void *data, int type, const char *symname)
value = rela->r_addend;
if (RELOC_RESOLVE_SYMBOL(rtype)) {
addr = linker_file_lookup_symbol(lf, symname, 1);
addr = elf_lookup(lf, symidx, 1);
if (addr == 0)
return (-1);
value += (Elf_Addr)addr;

View File

@ -226,8 +226,9 @@ extern int kld_debug;
#endif
/* Support functions */
int elf_reloc(linker_file_t _lf, const void *_rel, int _type,
const char *_sym);
int elf_reloc(linker_file_t _lf, const void *_rel, int _type);
Elf_Addr elf_lookup(linker_file_t, Elf_Word, int);
/* values for type */
#define ELF_RELOC_REL 1
#define ELF_RELOC_RELA 2