Resolve the GOT before doing relocations. Then, when doing relocations, for
symbols in the global part of the symbol table, use the updated GOT entry rather than doing a lookup. (This provides the same effect as `-z combreloc' on other platforms -- at most one lookup is done per symbol.) Unfortunately, it is necessary to turn off lazy binding on MIPS. As the comment says: * XXX DANGER WILL ROBINSON! * You might think this is stupid, as it intentionally * defeats lazy binding -- and you'd be right. * Unfortunately, for lazy binding to work right, we * need to a way to force the GOT slots used for * function pointers to be resolved immediately. This * is supposed to be done automatically by the linker, * by not outputting a PLT slot and setting st_value * to 0, but GNU ld does not do so reliably.
This commit is contained in:
parent
7798fe3a64
commit
a3c903f7cb
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: mips_reloc.c,v 1.33 2002/09/14 23:53:21 thorpej Exp $ */
|
/* $NetBSD: mips_reloc.c,v 1.34 2002/09/25 03:52:06 mycroft Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
|
* Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
|
||||||
|
@ -108,27 +108,6 @@ _rtld_relocate_nonplt_self(dynp, relocbase)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
|
|
||||||
for (; rel < rellim; rel++) {
|
|
||||||
where = (Elf_Addr *)(relocbase + rel->r_offset);
|
|
||||||
|
|
||||||
switch (ELF_R_TYPE(rel->r_info)) {
|
|
||||||
case R_TYPE(NONE):
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R_TYPE(REL32):
|
|
||||||
sym = symtab + ELF_R_SYM(rel->r_info);
|
|
||||||
if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
|
|
||||||
ELF_ST_TYPE(sym->st_info) == STT_SECTION)
|
|
||||||
*where += (Elf_Addr)(sym->st_value + relocbase);
|
|
||||||
else
|
|
||||||
abort();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = (got[1] & 0x80000000) ? 2 : 1;
|
i = (got[1] & 0x80000000) ? 2 : 1;
|
||||||
/* Relocate the local GOT entries */
|
/* Relocate the local GOT entries */
|
||||||
|
@ -142,6 +121,26 @@ _rtld_relocate_nonplt_self(dynp, relocbase)
|
||||||
++sym;
|
++sym;
|
||||||
++got;
|
++got;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
|
||||||
|
for (; rel < rellim; rel++) {
|
||||||
|
where = (Elf_Addr *)(relocbase + rel->r_offset);
|
||||||
|
|
||||||
|
switch (ELF_R_TYPE(rel->r_info)) {
|
||||||
|
case R_TYPE(NONE):
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_TYPE(REL32):
|
||||||
|
assert(ELF_R_SYM(rel->r_info) < gotsym);
|
||||||
|
sym = symtab + ELF_R_SYM(rel->r_info);
|
||||||
|
assert(sym->st_info == STT_SECTION);
|
||||||
|
*where += (Elf_Addr)(sym->st_value + relocbase);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -182,6 +181,60 @@ _rtld_relocate_nonplt_objects(obj, self)
|
||||||
if (self)
|
if (self)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
i = (got[1] & 0x80000000) ? 2 : 1;
|
||||||
|
/* Relocate the local GOT entries */
|
||||||
|
got += i;
|
||||||
|
for (; i < obj->local_gotno; i++)
|
||||||
|
*got++ += (Elf_Addr)obj->relocbase;
|
||||||
|
sym = obj->symtab + obj->gotsym;
|
||||||
|
/* Now do the global GOT entries */
|
||||||
|
for (i = obj->gotsym; i < obj->symtabno; i++) {
|
||||||
|
rdbg((" doing got %d sym %p (%s, %x)", i - obj->gotsym, sym,
|
||||||
|
sym->st_name + obj->strtab, *got));
|
||||||
|
|
||||||
|
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
|
||||||
|
sym->st_shndx == SHN_UNDEF) {
|
||||||
|
/*
|
||||||
|
* XXX DANGER WILL ROBINSON!
|
||||||
|
* You might think this is stupid, as it intentionally
|
||||||
|
* defeats lazy binding -- and you'd be right.
|
||||||
|
* Unfortunately, for lazy binding to work right, we
|
||||||
|
* need to a way to force the GOT slots used for
|
||||||
|
* function pointers to be resolved immediately. This
|
||||||
|
* is supposed to be done automatically by the linker,
|
||||||
|
* by not outputting a PLT slot and setting st_value
|
||||||
|
* to 0, but GNU ld does not do so reliably.
|
||||||
|
*/
|
||||||
|
def = _rtld_find_symdef(i, obj, &defobj, true);
|
||||||
|
if (def == NULL)
|
||||||
|
return -1;
|
||||||
|
*got = def->st_value + (Elf_Addr)defobj->relocbase;
|
||||||
|
} else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
|
||||||
|
sym->st_value != 0) {
|
||||||
|
/*
|
||||||
|
* If there are non-PLT references to the function,
|
||||||
|
* st_value should be 0, forcing us to resolve the
|
||||||
|
* address immediately.
|
||||||
|
*/
|
||||||
|
*got = sym->st_value + (Elf_Addr)obj->relocbase;
|
||||||
|
} else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
|
||||||
|
/* Symbols with index SHN_ABS are not relocated. */
|
||||||
|
if (sym->st_shndx != SHN_ABS)
|
||||||
|
*got = sym->st_value +
|
||||||
|
(Elf_Addr)obj->relocbase;
|
||||||
|
} else {
|
||||||
|
def = _rtld_find_symdef(i, obj, &defobj, true);
|
||||||
|
if (def == NULL)
|
||||||
|
return -1;
|
||||||
|
*got = def->st_value + (Elf_Addr)defobj->relocbase;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdbg((" --> now %x", *got));
|
||||||
|
++sym;
|
||||||
|
++got;
|
||||||
|
}
|
||||||
|
|
||||||
|
got = obj->pltgot;
|
||||||
for (rel = obj->rel; rel < obj->rellim; rel++) {
|
for (rel = obj->rel; rel < obj->rellim; rel++) {
|
||||||
Elf_Addr *where, tmp;
|
Elf_Addr *where, tmp;
|
||||||
unsigned long symnum;
|
unsigned long symnum;
|
||||||
|
@ -197,9 +250,16 @@ _rtld_relocate_nonplt_objects(obj, self)
|
||||||
/* 32-bit PC-relative reference */
|
/* 32-bit PC-relative reference */
|
||||||
def = obj->symtab + symnum;
|
def = obj->symtab + symnum;
|
||||||
|
|
||||||
if (ELF_ST_BIND(def->st_info) == STB_LOCAL &&
|
if (symnum >= obj->gotsym) {
|
||||||
(ELF_ST_TYPE(def->st_info) == STT_SECTION ||
|
tmp = *where;
|
||||||
ELF_ST_TYPE(def->st_info) == STT_NOTYPE)) {
|
tmp += got[obj->local_gotno + symnum - obj->gotsym];
|
||||||
|
*where = tmp;
|
||||||
|
|
||||||
|
rdbg(("REL32/G %s in %s --> %p in %s",
|
||||||
|
obj->strtab + def->st_name, obj->path,
|
||||||
|
(void *)tmp, obj->path));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
/*
|
/*
|
||||||
* XXX: ABI DIFFERENCE!
|
* XXX: ABI DIFFERENCE!
|
||||||
*
|
*
|
||||||
|
@ -220,48 +280,18 @@ _rtld_relocate_nonplt_objects(obj, self)
|
||||||
*
|
*
|
||||||
* --rkb, Oct 6, 2001
|
* --rkb, Oct 6, 2001
|
||||||
*/
|
*/
|
||||||
if (__predict_true(RELOC_ALIGNED_P(where))) {
|
tmp = *where;
|
||||||
tmp = *where;
|
|
||||||
|
|
||||||
if (def->st_info == STT_SECTION &&
|
if (def->st_info == STT_SECTION &&
|
||||||
tmp < def->st_value)
|
tmp < def->st_value)
|
||||||
tmp += (Elf_Addr)def->st_value;
|
tmp += (Elf_Addr)def->st_value;
|
||||||
|
|
||||||
tmp += (Elf_Addr)obj->relocbase;
|
tmp += (Elf_Addr)obj->relocbase;
|
||||||
*where = tmp;
|
*where = tmp;
|
||||||
} else {
|
|
||||||
tmp = load_ptr(where);
|
|
||||||
|
|
||||||
if (def->st_info == STT_SECTION &&
|
|
||||||
tmp < def->st_value)
|
|
||||||
tmp += (Elf_Addr)def->st_value;
|
|
||||||
|
|
||||||
tmp += (Elf_Addr)obj->relocbase;
|
|
||||||
store_ptr(where, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
rdbg(("REL32 %s in %s --> %p in %s",
|
rdbg(("REL32 %s in %s --> %p in %s",
|
||||||
obj->strtab + def->st_name, obj->path,
|
obj->strtab + def->st_name, obj->path,
|
||||||
(void *)tmp, obj->path));
|
(void *)tmp, obj->path));
|
||||||
} else {
|
|
||||||
def = _rtld_find_symdef(symnum, obj, &defobj,
|
|
||||||
false);
|
|
||||||
if (def == NULL)
|
|
||||||
return -1;
|
|
||||||
if (__predict_true(RELOC_ALIGNED_P(where))) {
|
|
||||||
tmp = *where +
|
|
||||||
(Elf_Addr)(defobj->relocbase +
|
|
||||||
def->st_value);
|
|
||||||
*where = tmp;
|
|
||||||
} else {
|
|
||||||
tmp = load_ptr(where) +
|
|
||||||
(Elf_Addr)(defobj->relocbase +
|
|
||||||
def->st_value);
|
|
||||||
store_ptr(where, tmp);
|
|
||||||
}
|
|
||||||
rdbg(("REL32 %s in %s --> %p in %s",
|
|
||||||
obj->strtab + obj->symtab[symnum].st_name,
|
|
||||||
obj->path, (void *)tmp, defobj->path));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -278,39 +308,6 @@ _rtld_relocate_nonplt_objects(obj, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i = (got[1] & 0x80000000) ? 2 : 1;
|
|
||||||
/* Relocate the local GOT entries */
|
|
||||||
got += i;
|
|
||||||
for (; i < obj->local_gotno; i++)
|
|
||||||
*got++ += (Elf_Addr)obj->relocbase;
|
|
||||||
sym = obj->symtab + obj->gotsym;
|
|
||||||
/* Now do the global GOT entries */
|
|
||||||
for (i = obj->gotsym; i < obj->symtabno; i++) {
|
|
||||||
rdbg((" doing got %d sym %p (%s, %x)", i - obj->gotsym, sym,
|
|
||||||
sym->st_name + obj->strtab, *got));
|
|
||||||
|
|
||||||
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
|
|
||||||
sym->st_value != 0)
|
|
||||||
/* The symbol table contains the address of the PLT
|
|
||||||
slot. However, sometimes a PLT slot is not
|
|
||||||
allocated, so we have to check st_value first. */
|
|
||||||
*got = sym->st_value + (Elf_Addr)obj->relocbase;
|
|
||||||
else if (ELF_ST_TYPE(sym->st_info) == STT_SECTION &&
|
|
||||||
ELF_ST_BIND(sym->st_info) == STB_GLOBAL) {
|
|
||||||
/* Symbols with index SHN_ABS are not relocated. */
|
|
||||||
if (sym->st_shndx != SHN_ABS)
|
|
||||||
*got = sym->st_value +
|
|
||||||
(Elf_Addr)obj->relocbase;
|
|
||||||
} else {
|
|
||||||
def = _rtld_find_symdef(i, obj, &defobj, true);
|
|
||||||
if (def == NULL)
|
|
||||||
return -1;
|
|
||||||
*got = def->st_value + (Elf_Addr)defobj->relocbase;
|
|
||||||
}
|
|
||||||
++sym;
|
|
||||||
++got;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue