diff options
author | kib <kib@FreeBSD.org> | 2015-09-27 01:33:43 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2015-09-27 01:33:43 +0000 |
commit | b44e8c14438c6602432ef5d490df5fd818d5a1db (patch) | |
tree | 606c7d952a5108145e2f9e88a6ecd9c4b0d13664 | |
parent | 8a6fcabbcf4777957124f6be9ba9dba42b68a9b7 (diff) | |
download | FreeBSD-src-b44e8c14438c6602432ef5d490df5fd818d5a1db.zip FreeBSD-src-b44e8c14438c6602432ef5d490df5fd818d5a1db.tar.gz |
MFC r288000:
Add support for weak symbols to the kernel linkers.
-rw-r--r-- | sys/amd64/amd64/elf_machdep.c | 17 | ||||
-rw-r--r-- | sys/arm/arm/elf_machdep.c | 9 | ||||
-rw-r--r-- | sys/i386/i386/elf_machdep.c | 13 | ||||
-rw-r--r-- | sys/ia64/ia64/elf_machdep.c | 39 | ||||
-rw-r--r-- | sys/kern/link_elf.c | 30 | ||||
-rw-r--r-- | sys/kern/link_elf_obj.c | 51 | ||||
-rw-r--r-- | sys/mips/mips/elf_machdep.c | 33 | ||||
-rw-r--r-- | sys/powerpc/powerpc/elf32_machdep.c | 15 | ||||
-rw-r--r-- | sys/powerpc/powerpc/elf64_machdep.c | 9 | ||||
-rw-r--r-- | sys/sparc64/sparc64/elf_machdep.c | 5 | ||||
-rw-r--r-- | sys/sys/linker.h | 2 |
11 files changed, 127 insertions, 96 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index 23fa39b..f9ba30d 100644 --- a/sys/amd64/amd64/elf_machdep.c +++ b/sys/amd64/amd64/elf_machdep.c @@ -167,6 +167,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: @@ -202,29 +203,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; @@ -241,8 +242,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 8ef9bd4..931a82b 100644 --- a/sys/arm/arm/elf_machdep.c +++ b/sys/arm/arm/elf_machdep.c @@ -132,6 +132,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: @@ -167,8 +168,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; *where += addr; break; @@ -183,8 +184,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) { *where = addr; return (0); } diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c index 8cd4440..6acd32a 100644 --- a/sys/i386/i386/elf_machdep.c +++ b/sys/i386/i386/elf_machdep.c @@ -177,6 +177,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: @@ -212,8 +213,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) @@ -221,8 +222,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) @@ -239,8 +240,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/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c index 05cb641..f1ab4a0 100644 --- a/sys/ia64/ia64/elf_machdep.c +++ b/sys/ia64/ia64/elf_machdep.c @@ -127,17 +127,18 @@ elf64_dump_thread(struct thread *td, void *dst, size_t *off __unused) } -static Elf_Addr -lookup_fdesc(linker_file_t lf, Elf_Size symidx, elf_lookup_fn lookup) +static int +lookup_fdesc(linker_file_t lf, Elf_Size symidx, elf_lookup_fn lookup, + Elf_Addr *addr1) { linker_file_t top; Elf_Addr addr; const char *symname; - int i; + int i, error; static int eot = 0; - addr = lookup(lf, symidx, 0); - if (addr == 0) { + error = lookup(lf, symidx, 0, &addr); + if (error != 0) { top = lf; symname = elf_get_symname(top, symidx); for (i = 0; i < top->ndeps; i++) { @@ -148,30 +149,33 @@ lookup_fdesc(linker_file_t lf, Elf_Size symidx, elf_lookup_fn lookup) break; } if (addr == 0) - return (0); + return (EINVAL); } if (eot) - return (0); + return (EINVAL); /* * Lookup and/or construct OPD */ for (i = 0; i < 8192; i += 2) { - if (fptr_storage[i] == addr) - return (Elf_Addr)(fptr_storage + i); + if (fptr_storage[i] == addr) { + *addr1 = (Elf_Addr)(fptr_storage + i); + return (0); + } if (fptr_storage[i] == 0) { fptr_storage[i] = addr; fptr_storage[i+1] = link_elf_get_gp(lf); - return (Elf_Addr)(fptr_storage + i); + *addr1 = (Elf_Addr)(fptr_storage + i); + return (0); } } printf("%s: fptr table full\n", __func__); eot = 1; - return (0); + return (EINVAL); } /* Process one elf relocation with addend. */ @@ -184,6 +188,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: @@ -223,8 +228,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, case R_IA_64_NONE: break; case R_IA_64_DIR64LSB: /* word64 LSB S + A */ - addr = lookup(lf, symidx, 1); - if (addr == 0) + error = lookup(lf, symidx, 1, &addr); + if (error != 0) return (-1); *where = addr + addend; break; @@ -233,16 +238,16 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, printf("%s: addend ignored for OPD relocation\n", __func__); } - addr = lookup_fdesc(lf, symidx, lookup); - if (addr == 0) + error = lookup_fdesc(lf, symidx, lookup, &addr); + if (error != 0) return (-1); *where = addr; break; case R_IA_64_REL64LSB: /* word64 LSB BD + A */ break; case R_IA_64_IPLTLSB: - addr = lookup_fdesc(lf, symidx, lookup); - if (addr == 0) + error = lookup_fdesc(lf, symidx, lookup, &addr); + if (error != 0) return (-1); where[0] = *((Elf_Addr*)addr) + addend; where[1] = *((Elf_Addr*)addr + 1); diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index 631ba75..b4f6586 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), @@ -1498,8 +1498,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; @@ -1507,8 +1507,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; @@ -1518,9 +1520,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); } /* @@ -1533,8 +1538,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)); @@ -1544,7 +1551,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 4f40258..453d8ce 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), @@ -1224,38 +1225,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 @@ -1267,18 +1276,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 d374713..2e22281 100644 --- a/sys/mips/mips/elf_machdep.c +++ b/sys/mips/mips/elf_machdep.c @@ -174,6 +174,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 @@ -213,8 +214,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) @@ -222,8 +223,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; @@ -241,8 +242,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) @@ -251,8 +252,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; @@ -266,8 +267,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; @@ -275,8 +276,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; @@ -292,8 +293,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; @@ -301,8 +302,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 dbe58df..c2094ff 100644 --- a/sys/powerpc/powerpc/elf32_machdep.c +++ b/sys/powerpc/powerpc/elf32_machdep.c @@ -164,6 +164,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: @@ -187,16 +188,16 @@ 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; addr += addend; *where = addr; 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 @@ -211,8 +212,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 0c41a8d..3fcca47 100644 --- a/sys/powerpc/powerpc/elf64_machdep.c +++ b/sys/powerpc/powerpc/elf64_machdep.c @@ -135,6 +135,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: @@ -157,9 +158,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; @@ -169,7 +170,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 4d55717..621e643 100644 --- a/sys/sparc64/sparc64/elf_machdep.c +++ b/sys/sparc64/sparc64/elf_machdep.c @@ -343,6 +343,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); @@ -371,8 +372,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 b2942f2..ce4d86e 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -259,7 +259,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); |