Make a small revision to the api between the elf linker core and the

elf_reloc() backends for two reasons.  First, to support the possibility
of there being two elf linkers in the kernel (eg: amd64), and second, to
pass the relocbase explicitly (for relocating .o format kld files).
This commit is contained in:
peter 2004-05-16 20:00:28 +00:00
parent ffb6541b3f
commit 29f2cef3b2
9 changed files with 113 additions and 84 deletions

View File

@ -108,9 +108,9 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
@ -152,7 +152,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_ALPHA_REFQUAD:
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
@ -161,7 +161,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_ALPHA_GLOB_DAT:
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
@ -171,7 +171,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
case R_ALPHA_JMP_SLOT:
/* No point in lazy binding for kernel modules. */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)
@ -198,17 +198,19 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
}
int
elf_reloc(linker_file_t lf, const void *data, int type)
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 0));
return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
}
int
elf_reloc_local(linker_file_t lf, const void *data, int type)
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 1));
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
}
int

View File

@ -104,10 +104,11 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf64_Addr *where, val;
Elf32_Addr *where32, val32;
Elf_Addr addr;
Elf_Addr addend;
Elf_Word rtype, symidx;
@ -133,37 +134,39 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
panic("unknown reloc type %d\n", type);
}
if (local) {
if (rtype == R_X86_64_RELATIVE) { /* A + B */
addr = relocbase + addend;
if (*where != addr)
*where = addr;
}
return (0);
}
switch (rtype) {
case R_X86_64_NONE: /* none */
break;
case R_X86_64_64: /* S + A */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
val = addr + addend;
if (addr == 0)
return -1;
addr += addend;
if (*where != addr)
*where = addr;
if (*where != val)
*where = val;
break;
case R_X86_64_PC32: /* S + A - P */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
where32 = (Elf32_Addr *)where;
val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where);
if (addr == 0)
return -1;
addr += addend - (Elf_Addr)where;
/* XXX needs to be 32 bit *where, not 64 bit */
if (*where != addr)
*where = addr;
if (*where32 != val32)
*where32 = val32;
break;
case R_X86_64_32S: /* S + A sign extend */
addr = lookup(lf, symidx, 1);
val32 = (Elf32_Addr)(addr + addend);
where32 = (Elf32_Addr *)where;
if (addr == 0)
return -1;
if (*where32 != val32)
*where32 = val32;
break;
case R_X86_64_COPY: /* none */
@ -176,7 +179,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_X86_64_GLOB_DAT: /* S */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)
@ -184,6 +187,10 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_X86_64_RELATIVE: /* B + A */
addr = relocbase + addend;
val = addr;
if (*where != val)
*where = val;
break;
default:
@ -195,17 +202,19 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
}
int
elf_reloc(linker_file_t lf, const void *data, int type)
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 0));
return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
}
int
elf_reloc_local(linker_file_t lf, const void *data, int type)
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 1));
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
}
int

View File

@ -104,9 +104,9 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
@ -148,7 +148,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_ARM_PC24: /* S + A - P */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend - (Elf_Addr)where;
@ -166,7 +166,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_ARM_GLOB_DAT: /* S */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)
@ -185,17 +185,19 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
}
int
elf_reloc(linker_file_t lf, const void *data, int type)
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 0));
return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
}
int
elf_reloc_local(linker_file_t lf, const void *data, int type)
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 1));
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
}
int

View File

@ -104,9 +104,9 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
@ -148,7 +148,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_386_32: /* S + A */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
@ -157,7 +157,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_386_PC32: /* S + A - P */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend - (Elf_Addr)where;
@ -175,7 +175,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_386_GLOB_DAT: /* S */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)
@ -194,17 +194,19 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
}
int
elf_reloc(linker_file_t lf, const void *data, int type)
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 0));
return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
}
int
elf_reloc_local(linker_file_t lf, const void *data, int type)
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 1));
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
}
int

View File

@ -143,7 +143,7 @@ ia64_coredump(struct thread *td, struct vnode *vp, off_t limit)
}
static Elf_Addr
lookup_fdesc(linker_file_t lf, Elf_Word symidx)
lookup_fdesc(linker_file_t lf, Elf_Word symidx, elf_lookup_fn lookup)
{
linker_file_t top;
Elf_Addr addr;
@ -151,7 +151,7 @@ lookup_fdesc(linker_file_t lf, Elf_Word symidx)
int i;
static int eot = 0;
addr = elf_lookup(lf, symidx, 0);
addr = lookup(lf, symidx, 0);
if (addr == 0) {
top = lf;
symname = elf_get_symname(top, symidx);
@ -191,7 +191,8 @@ lookup_fdesc(linker_file_t lf, Elf_Word symidx)
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
{
Elf_Addr relocbase = (Elf_Addr)lf->address;
Elf_Addr *where;
@ -238,7 +239,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
case R_IA64_NONE:
break;
case R_IA64_DIR64LSB: /* word64 LSB S + A */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return (-1);
*where = addr + addend;
@ -248,7 +249,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
printf("%s: addend ignored for OPD relocation\n",
__func__);
}
addr = lookup_fdesc(lf, symidx);
addr = lookup_fdesc(lf, symidx, lookup);
if (addr == 0)
return (-1);
*where = addr;
@ -256,7 +257,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
case R_IA64_REL64LSB: /* word64 LSB BD + A */
break;
case R_IA64_IPLTLSB:
addr = lookup_fdesc(lf, symidx);
addr = lookup_fdesc(lf, symidx, lookup);
if (addr == 0)
return (-1);
where[0] = *((Elf_Addr*)addr) + addend;
@ -272,17 +273,19 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
}
int
elf_reloc(linker_file_t lf, const void *data, int type)
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 0));
return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
}
int
elf_reloc_local(linker_file_t lf, const void *data, int type)
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 1));
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
}
int

View File

@ -118,6 +118,7 @@ static int link_elf_each_function_name(linker_file_t,
int (*)(const char *, void *),
void *);
static void link_elf_reloc_local(linker_file_t);
static Elf_Addr elf_lookup(linker_file_t lf, Elf_Word symidx, int deps);
static kobj_method_t link_elf_methods[] = {
KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol),
@ -928,7 +929,8 @@ relocate_file(elf_file_t ef)
if (rel) {
rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
while (rel < rellim) {
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL,
elf_lookup)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
@ -942,7 +944,8 @@ relocate_file(elf_file_t ef)
if (rela) {
relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
while (rela < relalim) {
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA,
elf_lookup)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
@ -956,7 +959,8 @@ relocate_file(elf_file_t ef)
if (rel) {
rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize);
while (rel < rellim) {
if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL,
elf_lookup)) {
symname = symbol_name(ef, rel->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
@ -970,7 +974,8 @@ relocate_file(elf_file_t ef)
if (rela) {
relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize);
while (rela < relalim) {
if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA,
elf_lookup)) {
symname = symbol_name(ef, rela->r_info);
printf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
@ -1244,7 +1249,7 @@ elf_get_symname(linker_file_t lf, Elf_Word symidx)
* 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
static Elf_Addr
elf_lookup(linker_file_t lf, Elf_Word symidx, int deps)
{
elf_file_t ef = (elf_file_t)lf;
@ -1297,7 +1302,8 @@ link_elf_reloc_local(linker_file_t lf)
if ((rel = ef->rel) != NULL) {
rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
while (rel < rellim) {
elf_reloc_local(lf, rel, ELF_RELOC_REL);
elf_reloc_local(lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL,
elf_lookup);
rel++;
}
}
@ -1306,7 +1312,8 @@ link_elf_reloc_local(linker_file_t lf)
if ((rela = ef->rela) != NULL) {
relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
while (rela < relalim) {
elf_reloc_local(lf, rela, ELF_RELOC_RELA);
elf_reloc_local(lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA,
elf_lookup);
rela++;
}
}

View File

@ -106,9 +106,9 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
Elf_Addr addr;
Elf_Addr addend;
@ -141,7 +141,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
break;
case R_PPC_GLOB_DAT:
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
@ -151,7 +151,7 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
case R_PPC_JMP_SLOT:
/* No point in lazy binding for kernel modules. */
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
if (*where != addr)
@ -181,17 +181,19 @@ elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
}
int
elf_reloc(linker_file_t lf, const void *data, int type)
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 0));
return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
}
int
elf_reloc_local(linker_file_t lf, const void *data, int type)
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, data, type, 1));
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
}
int

View File

@ -252,7 +252,8 @@ static long reloc_target_bitmask[] = {
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
int
elf_reloc_local(linker_file_t lf, const void *data, int type)
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
const Elf_Rela *rela;
Elf_Addr value;
@ -275,7 +276,8 @@ elf_reloc_local(linker_file_t lf, const void *data, int type)
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type)
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
const Elf_Rela *rela;
Elf_Addr relocbase;
@ -289,7 +291,6 @@ elf_reloc(linker_file_t lf, const void *data, int type)
if (type != ELF_RELOC_RELA)
return (-1);
relocbase = (Elf_Addr)lf->address;
rela = (const Elf_Rela *)data;
where = (Elf_Addr *)(relocbase + rela->r_offset);
where32 = (Elf_Half *)where;
@ -309,7 +310,7 @@ elf_reloc(linker_file_t lf, const void *data, int type)
value = rela->r_addend;
if (RELOC_RESOLVE_SYMBOL(rtype)) {
addr = elf_lookup(lf, symidx, 1);
addr = lookup(lf, symidx, 1);
if (addr == 0)
return (-1);
value += addr;

View File

@ -241,10 +241,11 @@ extern int kld_debug;
#endif
typedef Elf_Addr elf_lookup_fn(linker_file_t, Elf_Word, int);
/* Support functions */
int elf_reloc(linker_file_t _lf, const void *_rel, int _type);
int elf_reloc_local(linker_file_t _lf, const void *_rel, int _type);
Elf_Addr elf_lookup(linker_file_t, Elf_Word, int);
int elf_reloc(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu);
int elf_reloc_local(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu);
const Elf_Sym *elf_get_sym(linker_file_t _lf, Elf_Word _symidx);
const char *elf_get_symname(linker_file_t _lf, Elf_Word _symidx);