From e8855d4f975f9d1b62f28eb2dbe90a8e4ce67038 Mon Sep 17 00:00:00 2001 From: Peter Wemm Date: Sun, 16 May 2004 20:00:28 +0000 Subject: [PATCH] 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). --- sys/alpha/alpha/elf_machdep.c | 20 +++++----- sys/amd64/amd64/elf_machdep.c | 61 ++++++++++++++++++------------- sys/arm/arm/elf_machdep.c | 18 +++++---- sys/i386/i386/elf_machdep.c | 20 +++++----- sys/ia64/ia64/elf_machdep.c | 23 +++++++----- sys/kern/link_elf.c | 21 +++++++---- sys/powerpc/powerpc/elf_machdep.c | 18 +++++---- sys/sparc64/sparc64/elf_machdep.c | 9 +++-- 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 794328c05b8..25c3ac7fab7 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 04d81aacd1d..32325125e2f 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 373e93774ee..303832b15de 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 8bed56a350a..c6b1ce6d635 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 1c7f1d21df6..b40c21e125e 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 f05cab162b1..a7b7a02d88d 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 1a4486fadcf..21c9ca3e96a 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 d9d2974d02a..a20442ae21c 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 3ea5718c57e..1815c47a607 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);