diff --git a/sys/alpha/alpha/elf_machdep.c b/sys/alpha/alpha/elf_machdep.c index 285a17441290..1b3c6f284390 100644 --- a/sys/alpha/alpha/elf_machdep.c +++ b/sys/alpha/alpha/elf_machdep.c @@ -89,8 +89,8 @@ SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY, &freebsd_brand_info); /* Process one elf relocation with addend. */ -int -elf_reloc(linker_file_t lf, const void *data, int type) +static int +elf_reloc_internal(linker_file_t lf, const void *data, int type, int local) { Elf_Addr relocbase = (Elf_Addr) lf->address; Elf_Addr *where; @@ -119,6 +119,15 @@ elf_reloc(linker_file_t lf, const void *data, int type) panic("elf_reloc: unknown relocation mode %d\n", type); } + if (local) { + if (rtype == R_ALPHA_RELATIVE) { + addr = relocbase + addend; + if (*where != addr) + *where = addr; + } + return (0); + } + switch (rtype) { case R_ALPHA_NONE: @@ -152,9 +161,6 @@ elf_reloc(linker_file_t lf, const void *data, int type) break; case R_ALPHA_RELATIVE: - addr = relocbase + addend; - if (*where != addr) - *where = addr; break; case R_ALPHA_COPY: @@ -173,6 +179,20 @@ elf_reloc(linker_file_t lf, const void *data, int type) return(0); } +int +elf_reloc(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 0)); +} + +int +elf_reloc_local(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 1)); +} + int elf_cpu_load_file(linker_file_t lf __unused) { diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index 71520de1747a..4cf9f216e8e8 100644 --- a/sys/amd64/amd64/elf_machdep.c +++ b/sys/amd64/amd64/elf_machdep.c @@ -86,8 +86,8 @@ SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY, &freebsd_brand_info); /* Process one elf relocation with addend. */ -int -elf_reloc(linker_file_t lf, const void *data, int type) +static int +elf_reloc_internal(linker_file_t lf, const void *data, int type, int local) { Elf_Addr relocbase = (Elf_Addr) lf->address; Elf_Addr *where; @@ -116,6 +116,15 @@ elf_reloc(linker_file_t lf, const void *data, int type) panic("unknown reloc type %d\n", type); } + if (local) { + if (rtype == R_386_RELATIVE) { /* A + B */ + addr = relocbase + addend; + if (*where != addr) + *where = addr; + } + return (0); + } + switch (rtype) { case R_386_NONE: /* none */ @@ -156,10 +165,7 @@ elf_reloc(linker_file_t lf, const void *data, int type) *where = addr; break; - case R_386_RELATIVE: /* B + A */ - addr = relocbase + addend; - if (*where != addr) - *where = addr; + case R_386_RELATIVE: break; default: @@ -170,6 +176,20 @@ elf_reloc(linker_file_t lf, const void *data, int type) return(0); } +int +elf_reloc(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 0)); +} + +int +elf_reloc_local(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 1)); +} + int elf_cpu_load_file(linker_file_t lf __unused) { diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c index 71520de1747a..4cf9f216e8e8 100644 --- a/sys/i386/i386/elf_machdep.c +++ b/sys/i386/i386/elf_machdep.c @@ -86,8 +86,8 @@ SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY, &freebsd_brand_info); /* Process one elf relocation with addend. */ -int -elf_reloc(linker_file_t lf, const void *data, int type) +static int +elf_reloc_internal(linker_file_t lf, const void *data, int type, int local) { Elf_Addr relocbase = (Elf_Addr) lf->address; Elf_Addr *where; @@ -116,6 +116,15 @@ elf_reloc(linker_file_t lf, const void *data, int type) panic("unknown reloc type %d\n", type); } + if (local) { + if (rtype == R_386_RELATIVE) { /* A + B */ + addr = relocbase + addend; + if (*where != addr) + *where = addr; + } + return (0); + } + switch (rtype) { case R_386_NONE: /* none */ @@ -156,10 +165,7 @@ elf_reloc(linker_file_t lf, const void *data, int type) *where = addr; break; - case R_386_RELATIVE: /* B + A */ - addr = relocbase + addend; - if (*where != addr) - *where = addr; + case R_386_RELATIVE: break; default: @@ -170,6 +176,20 @@ elf_reloc(linker_file_t lf, const void *data, int type) return(0); } +int +elf_reloc(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 0)); +} + +int +elf_reloc_local(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 1)); +} + int elf_cpu_load_file(linker_file_t lf __unused) { diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c index c4a4938f5e28..b3c7d90a6c2f 100644 --- a/sys/ia64/ia64/elf_machdep.c +++ b/sys/ia64/ia64/elf_machdep.c @@ -141,8 +141,8 @@ lookup_fdesc(linker_file_t lf, Elf_Word symidx) } /* Process one elf relocation with addend. */ -int -elf_reloc(linker_file_t lf, const void *data, int type) +static int +elf_reloc_internal(linker_file_t lf, const void *data, int type, int local) { Elf_Addr relocbase = (Elf_Addr)lf->address; Elf_Addr *where; @@ -179,6 +179,12 @@ elf_reloc(linker_file_t lf, const void *data, int type) panic("%s: invalid ELF relocation (0x%x)\n", __func__, type); } + if (local) { + if (rtype == R_IA64_REL64LSB) + *where = relocbase + addend; + return (0); + } + switch (rtype) { case R_IA64_NONE: break; @@ -199,7 +205,6 @@ elf_reloc(linker_file_t lf, const void *data, int type) *where = addr; break; case R_IA64_REL64LSB: /* word64 LSB BD + A */ - *where = relocbase + addend; break; case R_IA64_IPLTLSB: addr = lookup_fdesc(lf, symidx); @@ -217,6 +222,20 @@ elf_reloc(linker_file_t lf, const void *data, int type) return (0); } +int +elf_reloc(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 0)); +} + +int +elf_reloc_local(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 1)); +} + int elf_cpu_load_file(linker_file_t lf) { diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index c1a7d3acd566..3c38baca614a 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -499,7 +499,7 @@ linker_file_unload(linker_file_t file) * Give the module a chance to veto the unload. */ if ((error = module_unload(mod)) != 0) { - KLD_DPF(FILE, ("linker_file_unload: module %x" + KLD_DPF(FILE, ("linker_file_unload: module %p" " vetoes unload\n", mod)); goto out; } else @@ -594,7 +594,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps) size_t common_size = 0; int i; - KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n", + KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", file, name, deps)); if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { @@ -608,7 +608,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps) common_size = symval.size; else { KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" - ".value=%x\n", symval.value)); + ".value=%p\n", symval.value)); return (symval.value); } } @@ -618,7 +618,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps) name, 0); if (address) { KLD_DPF(SYM, ("linker_file_lookup_symbol:" - " deps value=%x\n", address)); + " deps value=%p\n", address)); return (address); } } @@ -634,7 +634,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps) STAILQ_FOREACH(cp, &file->common, link) { if (strcmp(cp->name, name) == 0) { KLD_DPF(SYM, ("linker_file_lookup_symbol:" - " old common value=%x\n", cp->address)); + " old common value=%p\n", cp->address)); return (cp->address); } } @@ -656,7 +656,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps) STAILQ_INSERT_TAIL(&file->common, cp, link); KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" - " value=%x\n", cp->address)); + " value=%p\n", cp->address)); return (cp->address); } KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); @@ -1106,46 +1106,6 @@ modlist_newmodule(const char *modname, int version, linker_file_t container) return (mod); } -/* - * This routine is cheap and nasty but will work for data pointers. - */ -static void * -linker_reloc_ptr(linker_file_t lf, const void *offset) -{ - return (lf->address + (uintptr_t)offset); -} - -/* - * Dereference MDT_VERSION metadata into module name and version - */ -static void -linker_mdt_version(linker_file_t lf, struct mod_metadata *mp, - const char **modname, int *version) -{ - struct mod_version *mvp; - - if (modname) - *modname = linker_reloc_ptr(lf, mp->md_cval); - if (version) { - mvp = linker_reloc_ptr(lf, mp->md_data); - *version = mvp->mv_version; - } -} - -/* - * Dereference MDT_DEPEND metadata into module name and mod_depend structure - */ -static void -linker_mdt_depend(linker_file_t lf, struct mod_metadata *mp, - const char **modname, struct mod_depend **verinfo) -{ - - if (modname) - *modname = linker_reloc_ptr(lf, mp->md_cval); - if (verinfo) - *verinfo = linker_reloc_ptr(lf, mp->md_data); -} - static void linker_addmodules(linker_file_t lf, struct mod_metadata **start, struct mod_metadata **stop, int preload) @@ -1155,17 +1115,11 @@ linker_addmodules(linker_file_t lf, struct mod_metadata **start, int ver; for (mdp = start; mdp < stop; mdp++) { - if (preload) - mp = *mdp; - else - mp = linker_reloc_ptr(lf, *mdp); + mp = *mdp; if (mp->md_type != MDT_VERSION) continue; - if (preload) { - modname = mp->md_cval; - ver = ((struct mod_version *)mp->md_data)->mv_version; - } else - linker_mdt_version(lf, mp, &modname, &ver); + modname = mp->md_cval; + ver = ((struct mod_version *)mp->md_data)->mv_version; if (modlist_lookup(modname, ver) != NULL) { printf("module %s already present!\n", modname); /* XXX what can we do? this is a build error. :-( */ @@ -1249,18 +1203,16 @@ linker_preload(void *arg) resolves = 1; /* unless we know otherwise */ if (!error) { for (mdp = start; mdp < stop; mdp++) { - mp = linker_reloc_ptr(lf, *mdp); + mp = *mdp; if (mp->md_type != MDT_DEPEND) continue; - linker_mdt_depend(lf, mp, &modname, &verinfo); + modname = mp->md_cval; + verinfo = mp->md_data; for (nmdp = start; nmdp < stop; nmdp++) { - nmp = linker_reloc_ptr(lf, *nmdp); + nmp = *nmdp; if (nmp->md_type != MDT_VERSION) continue; - linker_mdt_version(lf, nmp, &nmodname, - NULL); - nmodname = linker_reloc_ptr(lf, - nmp->md_cval); + nmodname = nmp->md_cval; if (strcmp(modname, nmodname) == 0) break; } @@ -1283,11 +1235,12 @@ linker_preload(void *arg) if (resolves) { if (!error) { for (mdp = start; mdp < stop; mdp++) { - mp = linker_reloc_ptr(lf, *mdp); + mp = *mdp; if (mp->md_type != MDT_VERSION) continue; - linker_mdt_version(lf, mp, - &modname, &nver); + modname = mp->md_cval; + nver = ((struct mod_version *) + mp->md_data)->mv_version; if (modlist_lookup(modname, nver) != NULL) { printf("module %s already" @@ -1338,10 +1291,11 @@ linker_preload(void *arg) &stop, NULL); if (!error) { for (mdp = start; mdp < stop; mdp++) { - mp = linker_reloc_ptr(lf, *mdp); + mp = *mdp; if (mp->md_type != MDT_DEPEND) continue; - linker_mdt_depend(lf, mp, &modname, &verinfo); + modname = mp->md_cval; + verinfo = mp->md_data; mod = modlist_lookup2(modname, verinfo); mod->container->refs++; error = linker_file_add_dependency(lf, @@ -1763,10 +1717,11 @@ linker_load_dependencies(linker_file_t lf) &count) != 0) return (0); for (mdp = start; mdp < stop; mdp++) { - mp = linker_reloc_ptr(lf, *mdp); + mp = *mdp; if (mp->md_type != MDT_VERSION) continue; - linker_mdt_version(lf, mp, &modname, &ver); + modname = mp->md_cval; + ver = ((struct mod_version *)mp->md_data)->mv_version; mod = modlist_lookup(modname, ver); if (mod != NULL) { printf("interface %s.%d already present in the KLD" @@ -1777,16 +1732,17 @@ linker_load_dependencies(linker_file_t lf) } for (mdp = start; mdp < stop; mdp++) { - mp = linker_reloc_ptr(lf, *mdp); + mp = *mdp; if (mp->md_type != MDT_DEPEND) continue; - linker_mdt_depend(lf, mp, &modname, &verinfo); + modname = mp->md_cval; + verinfo = mp->md_data; nmodname = NULL; for (nmdp = start; nmdp < stop; nmdp++) { - nmp = linker_reloc_ptr(lf, *nmdp); + nmp = *nmdp; if (nmp->md_type != MDT_VERSION) continue; - nmodname = linker_reloc_ptr(lf, nmp->md_cval); + nmodname = nmp->md_cval; if (strcmp(modname, nmodname) == 0) break; } diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index 3e5224eca834..f15803fa8435 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -116,6 +116,7 @@ static int link_elf_lookup_set(linker_file_t, const char *, 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 kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), @@ -488,6 +489,7 @@ link_elf_link_preload(linker_class_t cls, linker_file_unload(lf); return error; } + link_elf_reloc_local(lf); *result = lf; return (0); } @@ -748,6 +750,8 @@ link_elf_load_file(linker_class_t cls, const char* filename, error = parse_dynamic(ef); if (error) goto out; + link_elf_reloc_local(lf); + error = linker_load_dependencies(lf); if (error) goto out; @@ -1266,3 +1270,31 @@ elf_lookup(linker_file_t lf, Elf_Word symidx, int deps) return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); } + +static void +link_elf_reloc_local(linker_file_t lf) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Rela *relalim; + const Elf_Rela *rela; + elf_file_t ef = (elf_file_t)lf; + + /* Perform relocations without addend if there are any: */ + 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); + rel++; + } + } + + /* Perform relocations with addend if there are any: */ + 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); + rela++; + } + } +} diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index 3e5224eca834..f15803fa8435 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -116,6 +116,7 @@ static int link_elf_lookup_set(linker_file_t, const char *, 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 kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), @@ -488,6 +489,7 @@ link_elf_link_preload(linker_class_t cls, linker_file_unload(lf); return error; } + link_elf_reloc_local(lf); *result = lf; return (0); } @@ -748,6 +750,8 @@ link_elf_load_file(linker_class_t cls, const char* filename, error = parse_dynamic(ef); if (error) goto out; + link_elf_reloc_local(lf); + error = linker_load_dependencies(lf); if (error) goto out; @@ -1266,3 +1270,31 @@ elf_lookup(linker_file_t lf, Elf_Word symidx, int deps) return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); } + +static void +link_elf_reloc_local(linker_file_t lf) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Rela *relalim; + const Elf_Rela *rela; + elf_file_t ef = (elf_file_t)lf; + + /* Perform relocations without addend if there are any: */ + 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); + rel++; + } + } + + /* Perform relocations with addend if there are any: */ + 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); + rela++; + } + } +} diff --git a/sys/powerpc/powerpc/elf_machdep.c b/sys/powerpc/powerpc/elf_machdep.c index e00c9d385363..1621e1bb449a 100644 --- a/sys/powerpc/powerpc/elf_machdep.c +++ b/sys/powerpc/powerpc/elf_machdep.c @@ -89,8 +89,8 @@ SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY, &freebsd_brand_info); /* Process one elf relocation with addend. */ -int -elf_reloc(linker_file_t lf, const void *data, int type) +static int +elf_reloc_internal(linker_file_t lf, const void *data, int type, int local) { Elf_Addr relocbase = (Elf_Addr) lf->address; Elf_Addr *where; @@ -164,6 +164,20 @@ elf_reloc(linker_file_t lf, const void *data, int type) return(0); } +int +elf_reloc(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 0)); +} + +int +elf_reloc_local(linker_file_t lf, const void *data, int type) +{ + + return (elf_reloc_internal(lf, data, type, 1)); +} + int elf_cpu_load_file(linker_file_t lf __unused) { diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c index 592be485356e..a14db6ca4eff 100644 --- a/sys/sparc64/sparc64/elf_machdep.c +++ b/sys/sparc64/sparc64/elf_machdep.c @@ -235,6 +235,28 @@ 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) +{ + const Elf_Rela *rela; + Elf_Addr value; + Elf_Addr *where; + + if (type != ELF_RELOC_RELA) + return (-1); + + rela = (const Elf_Rela *)data; + if (ELF_R_TYPE(rela->r_info) != R_SPARC_RELATIVE) + return (-1); + + value = rela->r_addend + (Elf_Addr)lf->address; + where = (Elf_Addr *)((Elf_Addr)lf->address + rela->r_offset); + + *where = value; + + return (0); +} + /* Process one elf relocation with addend. */ int elf_reloc(linker_file_t lf, const void *data, int type) @@ -258,7 +280,7 @@ elf_reloc(linker_file_t lf, const void *data, int type) rtype = ELF_R_TYPE(rela->r_info); symidx = ELF_R_SYM(rela->r_info); - if (rtype == R_SPARC_NONE) + if (rtype == R_SPARC_NONE || rtype == R_SPARC_RELATIVE) return (0); if (rtype == R_SPARC_JMP_SLOT || rtype == R_SPARC_COPY || diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 5e0a76050d34..a601e3a3a9b2 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -229,6 +229,7 @@ extern int kld_debug; /* 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); 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);