diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index d1cffd9a38c..d961f092cdf 100644 --- a/sys/amd64/amd64/elf_machdep.c +++ b/sys/amd64/amd64/elf_machdep.c @@ -168,6 +168,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, Elf_Size rtype, symidx; const Elf_Rel *rel; const Elf_Rela *rela; + int error; switch (type) { case ELF_RELOC_REL: @@ -203,29 +204,29 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_X86_64_64: /* S + A */ - addr = lookup(lf, symidx, 1); + error = lookup(lf, symidx, 1, &addr); val = addr + addend; - if (addr == 0) + if (error != 0) return -1; if (*where != val) *where = val; break; case R_X86_64_PC32: /* S + A - P */ - addr = lookup(lf, symidx, 1); + error = lookup(lf, symidx, 1, &addr); where32 = (Elf32_Addr *)where; val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where); - if (addr == 0) + if (error != 0) return -1; if (*where32 != val32) *where32 = val32; break; case R_X86_64_32S: /* S + A sign extend */ - addr = lookup(lf, symidx, 1); + error = lookup(lf, symidx, 1, &addr); val32 = (Elf32_Addr)(addr + addend); where32 = (Elf32_Addr *)where; - if (addr == 0) + if (error != 0) return -1; if (*where32 != val32) *where32 = val32; @@ -242,8 +243,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, case R_X86_64_GLOB_DAT: /* S */ case R_X86_64_JMP_SLOT: /* XXX need addend + offset */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return -1; if (*where != addr) *where = addr; diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c index e5cc6a02324..34761ff0e93 100644 --- a/sys/arm/arm/elf_machdep.c +++ b/sys/arm/arm/elf_machdep.c @@ -164,6 +164,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, Elf_Word rtype, symidx; const Elf_Rel *rel; const Elf_Rela *rela; + int error; switch (type) { case ELF_RELOC_REL: @@ -199,8 +200,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_ARM_ABS32: - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return -1; store_ptr(where, addr + load_ptr(where)); break; @@ -215,8 +216,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_ARM_JUMP_SLOT: - addr = lookup(lf, symidx, 1); - if (addr) { + error = lookup(lf, symidx, 1, &addr); + if (error == 0) { store_ptr(where, addr); return (0); } diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c index 03ab10f17dc..81d6e35b3a4 100644 --- a/sys/i386/i386/elf_machdep.c +++ b/sys/i386/i386/elf_machdep.c @@ -178,6 +178,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, Elf_Word rtype, symidx; const Elf_Rel *rel; const Elf_Rela *rela; + int error; switch (type) { case ELF_RELOC_REL: @@ -213,8 +214,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_386_32: /* S + A */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return -1; addr += addend; if (*where != addr) @@ -222,8 +223,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_386_PC32: /* S + A - P */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return -1; addr += addend - (Elf_Addr)where; if (*where != addr) @@ -240,8 +241,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_386_GLOB_DAT: /* S */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return -1; if (*where != addr) *where = addr; diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index 3b741cc38fb..c931ae92749 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -158,7 +158,7 @@ static int link_elf_each_function_nameval(linker_file_t, static void link_elf_reloc_local(linker_file_t); static long link_elf_symtab_get(linker_file_t, const Elf_Sym **); static long link_elf_strtab_get(linker_file_t, caddr_t *); -static Elf_Addr elf_lookup(linker_file_t, Elf_Size, int); +static int elf_lookup(linker_file_t, Elf_Size, int, Elf_Addr *); static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), @@ -1548,8 +1548,8 @@ elf_get_symname(linker_file_t lf, Elf_Size 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. */ -static Elf_Addr -elf_lookup(linker_file_t lf, Elf_Size symidx, int deps) +static int +elf_lookup(linker_file_t lf, Elf_Size symidx, int deps, Elf_Addr *res) { elf_file_t ef = (elf_file_t)lf; const Elf_Sym *sym; @@ -1557,8 +1557,10 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int deps) Elf_Addr addr, start, base; /* Don't even try to lookup the symbol if the index is bogus. */ - if (symidx >= ef->nchains) - return (0); + if (symidx >= ef->nchains) { + *res = 0; + return (EINVAL); + } sym = ef->symtab + symidx; @@ -1568,9 +1570,12 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int deps) */ if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) { /* Force lookup failure when we have an insanity. */ - if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0) - return (0); - return ((Elf_Addr)ef->address + sym->st_value); + if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0) { + *res = 0; + return (EINVAL); + } + *res = ((Elf_Addr)ef->address + sym->st_value); + return (0); } /* @@ -1583,8 +1588,10 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int deps) symbol = ef->strtab + sym->st_name; /* Force a lookup failure if the symbol name is bogus. */ - if (*symbol == 0) - return (0); + if (*symbol == 0) { + *res = 0; + return (EINVAL); + } addr = ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); @@ -1594,7 +1601,8 @@ elf_lookup(linker_file_t lf, Elf_Size symidx, int deps) else if (elf_set_find(&set_vnet_list, addr, &start, &base)) addr = addr - start + base; #endif - return addr; + *res = addr; + return (0); } static void diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index 021381db78d..00fe1e41864 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -144,7 +144,8 @@ static void link_elf_reloc_local(linker_file_t); static long link_elf_symtab_get(linker_file_t, const Elf_Sym **); static long link_elf_strtab_get(linker_file_t, caddr_t *); -static Elf_Addr elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps); +static int elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps, + Elf_Addr *); static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), @@ -1253,38 +1254,46 @@ elf_obj_cleanup_globals_cache(elf_file_t ef) * 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. */ -static Elf_Addr -elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps) +static int +elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps, Elf_Addr *res) { elf_file_t ef = (elf_file_t)lf; Elf_Sym *sym; const char *symbol; - Elf_Addr ret; + Elf_Addr res1; /* Don't even try to lookup the symbol if the index is bogus. */ - if (symidx >= ef->ddbsymcnt) - return (0); + if (symidx >= ef->ddbsymcnt) { + *res = 0; + return (EINVAL); + } sym = ef->ddbsymtab + symidx; /* Quick answer if there is a definition included. */ - if (sym->st_shndx != SHN_UNDEF) - return (sym->st_value); + if (sym->st_shndx != SHN_UNDEF) { + *res = sym->st_value; + return (0); + } /* If we get here, then it is undefined and needs a lookup. */ switch (ELF_ST_BIND(sym->st_info)) { case STB_LOCAL: /* Local, but undefined? huh? */ - return (0); + *res = 0; + return (EINVAL); case STB_GLOBAL: + case STB_WEAK: /* Relative to Data or Function name */ symbol = ef->ddbstrtab + sym->st_name; /* Force a lookup failure if the symbol name is bogus. */ - if (*symbol == 0) - return (0); - ret = ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); + if (*symbol == 0) { + *res = 0; + return (EINVAL); + } + res1 = (Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps); /* * Cache global lookups during module relocation. The failure @@ -1296,18 +1305,20 @@ elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps) * restored to SHN_UNDEF in elf_obj_cleanup_globals_cache(), * above. */ - if (ret != 0) { + if (res1 != 0) { sym->st_shndx = SHN_FBSD_CACHED; - sym->st_value = ret; + sym->st_value = res1; + *res = res1; + return (0); + } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { + sym->st_value = 0; + *res = 0; + return (0); } - return (ret); - - case STB_WEAK: - printf("link_elf_obj: Weak symbols not supported\n"); - return (0); + return (EINVAL); default: - return (0); + return (EINVAL); } } diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c index 8cbe8d3df6c..626b5f8a4c2 100644 --- a/sys/mips/mips/elf_machdep.c +++ b/sys/mips/mips/elf_machdep.c @@ -176,6 +176,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, Elf_Word rtype = (Elf_Word)0, symidx; const Elf_Rel *rel = NULL; const Elf_Rela *rela = NULL; + int error; /* * Stash R_MIPS_HI16 info so we can use it when processing R_MIPS_LO16 @@ -215,8 +216,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_MIPS_32: /* S + A */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addr += addend; if (*where != addr) @@ -224,8 +225,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_MIPS_26: /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addend &= 0x03ffffff; @@ -243,8 +244,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_MIPS_64: /* S + A */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addr += addend; if (*(Elf64_Addr*)where != addr) @@ -253,8 +254,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, case R_MIPS_HI16: /* ((AHL + S) - ((short)(AHL + S)) >> 16 */ if (rela != NULL) { - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; @@ -268,8 +269,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, case R_MIPS_LO16: /* AHL + S */ if (rela != NULL) { - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; @@ -277,8 +278,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, } else { ahl += (int16_t)addend; - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addend &= 0xffff0000; @@ -294,8 +295,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_MIPS_HIGHER: /* %higher(A+S) */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; @@ -303,8 +304,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_MIPS_HIGHEST: /* %highest(A+S) */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; diff --git a/sys/powerpc/powerpc/elf32_machdep.c b/sys/powerpc/powerpc/elf32_machdep.c index bdcd9babb8c..d0c3480a248 100644 --- a/sys/powerpc/powerpc/elf32_machdep.c +++ b/sys/powerpc/powerpc/elf32_machdep.c @@ -183,6 +183,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, Elf_Addr addend; Elf_Word rtype, symidx; const Elf_Rela *rela; + int error; switch (type) { case ELF_RELOC_REL: @@ -206,15 +207,15 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_PPC_ADDR32: /* word32 S + A */ - addr = lookup(lf, symidx, 1); - if (addr == 0) - return -1; + error = lookup(lf, symidx, 1, &addr); + if (error != 0) + return -1; *where = elf_relocaddr(lf, addr + addend); break; case R_PPC_ADDR16_LO: /* #lo(S) */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return -1; /* * addend values are sometimes relative to sections @@ -228,8 +229,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_PPC_ADDR16_HA: /* #ha(S) */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return -1; /* * addend values are sometimes relative to sections diff --git a/sys/powerpc/powerpc/elf64_machdep.c b/sys/powerpc/powerpc/elf64_machdep.c index 47fbbff2feb..72e6efc348f 100644 --- a/sys/powerpc/powerpc/elf64_machdep.c +++ b/sys/powerpc/powerpc/elf64_machdep.c @@ -154,6 +154,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, Elf_Addr addend; Elf_Word rtype, symidx; const Elf_Rela *rela; + int error; switch (type) { case ELF_RELOC_REL: @@ -176,9 +177,9 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_PPC64_ADDR64: /* doubleword64 S + A */ - addr = lookup(lf, symidx, 1); - if (addr == 0) - return -1; + error = lookup(lf, symidx, 1, &addr); + if (error != 0) + return -1; addr += addend; *where = addr; break; @@ -188,7 +189,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, break; case R_PPC_JMP_SLOT: /* function descriptor copy */ - addr = lookup(lf, symidx, 1); + lookup(lf, symidx, 1, &addr); memcpy(where, (Elf_Addr *)addr, 3*sizeof(Elf_Addr)); __asm __volatile("dcbst 0,%0; sync" :: "r"(where) : "memory"); break; diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c index 93045757e43..0dab76d59e1 100644 --- a/sys/sparc64/sparc64/elf_machdep.c +++ b/sys/sparc64/sparc64/elf_machdep.c @@ -344,6 +344,7 @@ elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, Elf_Addr value; Elf_Addr mask; Elf_Addr addr; + int error; if (type != ELF_RELOC_RELA) return (-1); @@ -372,8 +373,8 @@ elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, value = rela->r_addend; if (RELOC_RESOLVE_SYMBOL(rtype)) { - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); value += addr; if (RELOC_BARE_SYMBOL(rtype)) diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 5d24f003944..7e562a65662 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -264,7 +264,7 @@ extern int kld_debug; #endif -typedef Elf_Addr elf_lookup_fn(linker_file_t, Elf_Size, int); +typedef int elf_lookup_fn(linker_file_t, Elf_Size, int, Elf_Addr *); /* Support functions */ int elf_reloc(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu);