diff options
-rw-r--r-- | sys/alpha/alpha/elf_machdep.c | 20 | ||||
-rw-r--r-- | sys/amd64/amd64/elf_machdep.c | 61 | ||||
-rw-r--r-- | sys/arm/arm/elf_machdep.c | 18 | ||||
-rw-r--r-- | sys/i386/i386/elf_machdep.c | 20 | ||||
-rw-r--r-- | sys/ia64/ia64/elf_machdep.c | 23 | ||||
-rw-r--r-- | sys/kern/link_elf.c | 21 | ||||
-rw-r--r-- | sys/powerpc/powerpc/elf_machdep.c | 18 | ||||
-rw-r--r-- | sys/sparc64/sparc64/elf_machdep.c | 9 | ||||
-rw-r--r-- | sys/sys/linker.h | 7 |
9 files changed, 113 insertions, 84 deletions
diff --git a/sys/alpha/alpha/elf_machdep.c b/sys/alpha/alpha/elf_machdep.c index 794328c..25c3ac7 100644 --- a/sys/alpha/alpha/elf_machdep.c +++ b/sys/alpha/alpha/elf_machdep.c @@ -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 diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index 04d81aa..3232512 100644 --- a/sys/amd64/amd64/elf_machdep.c +++ b/sys/amd64/amd64/elf_machdep.c @@ -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 diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c index 373e937..303832b 100644 --- a/sys/arm/arm/elf_machdep.c +++ b/sys/arm/arm/elf_machdep.c @@ -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 diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c index 8bed56a..c6b1ce6 100644 --- a/sys/i386/i386/elf_machdep.c +++ b/sys/i386/i386/elf_machdep.c @@ -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 diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c index 1c7f1d2..b40c21e 100644 --- a/sys/ia64/ia64/elf_machdep.c +++ b/sys/ia64/ia64/elf_machdep.c @@ -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 diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index f05cab1..a7b7a02 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -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++; } } diff --git a/sys/powerpc/powerpc/elf_machdep.c b/sys/powerpc/powerpc/elf_machdep.c index 1a4486f..21c9ca3 100644 --- a/sys/powerpc/powerpc/elf_machdep.c +++ b/sys/powerpc/powerpc/elf_machdep.c @@ -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 diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c index d9d2974..a20442a 100644 --- a/sys/sparc64/sparc64/elf_machdep.c +++ b/sys/sparc64/sparc64/elf_machdep.c @@ -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; diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 3ea5718..1815c47 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -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); |