From owner-svn-src-head@freebsd.org Sun Sep 20 01:28:03 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id F20A9A02DB2; Sun, 20 Sep 2015 01:28:02 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id E0F8B1C6E; Sun, 20 Sep 2015 01:28:02 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t8K1S2lo005916; Sun, 20 Sep 2015 01:28:02 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t8K1S02o005905; Sun, 20 Sep 2015 01:28:00 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201509200128.t8K1S02o005905@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Sun, 20 Sep 2015 01:28:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r288000 - in head/sys: amd64/amd64 arm/arm i386/i386 kern mips/mips powerpc/powerpc sparc64/sparc64 sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 20 Sep 2015 01:28:03 -0000 Author: kib Date: Sun Sep 20 01:27:59 2015 New Revision: 288000 URL: https://svnweb.freebsd.org/changeset/base/288000 Log: Add support for weak symbols to the kernel linkers. It means that linkers no longer raise an error when undefined weak symbols are found, but relocate as if the symbol value was 0. Note that we do not repeat the mistake of userspace dynamic linker of making the symbol lookup prefer non-weak symbol definition over the weak one, if both are available. In fact, kernel linker uses the first definition found, and ignores duplicates. Signature of the elf_lookup() and elf_obj_lookup() functions changed to split result/error code and the symbol address returned. Otherwise, it is impossible to return zero address as the symbol value, to MD relocation code. This explains the mechanical changes in elf_machdep.c sources. The powerpc64 R_PPC_JMP_SLOT handler did not checked error from the lookup() call, the patch leaves the code as is (untested). Reported by: glebius Sponsored by: The FreeBSD Foundation MFC after: 1 week Modified: head/sys/amd64/amd64/elf_machdep.c head/sys/arm/arm/elf_machdep.c head/sys/i386/i386/elf_machdep.c head/sys/kern/link_elf.c head/sys/kern/link_elf_obj.c head/sys/mips/mips/elf_machdep.c head/sys/powerpc/powerpc/elf32_machdep.c head/sys/powerpc/powerpc/elf64_machdep.c head/sys/sparc64/sparc64/elf_machdep.c head/sys/sys/linker.h Modified: head/sys/amd64/amd64/elf_machdep.c ============================================================================== --- head/sys/amd64/amd64/elf_machdep.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/amd64/amd64/elf_machdep.c Sun Sep 20 01:27:59 2015 (r288000) @@ -168,6 +168,7 @@ elf_reloc_internal(linker_file_t lf, Elf 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 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 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; Modified: head/sys/arm/arm/elf_machdep.c ============================================================================== --- head/sys/arm/arm/elf_machdep.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/arm/arm/elf_machdep.c Sun Sep 20 01:27:59 2015 (r288000) @@ -164,6 +164,7 @@ elf_reloc_internal(linker_file_t lf, Elf 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 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 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); } Modified: head/sys/i386/i386/elf_machdep.c ============================================================================== --- head/sys/i386/i386/elf_machdep.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/i386/i386/elf_machdep.c Sun Sep 20 01:27:59 2015 (r288000) @@ -178,6 +178,7 @@ elf_reloc_internal(linker_file_t lf, Elf 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 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 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 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; Modified: head/sys/kern/link_elf.c ============================================================================== --- head/sys/kern/link_elf.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/kern/link_elf.c Sun Sep 20 01:27:59 2015 (r288000) @@ -158,7 +158,7 @@ static int link_elf_each_function_nameva 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_Si * 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 sy 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 sy */ 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 sy 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 sy else if (elf_set_find(&set_vnet_list, addr, &start, &base)) addr = addr - start + base; #endif - return addr; + *res = addr; + return (0); } static void Modified: head/sys/kern/link_elf_obj.c ============================================================================== --- head/sys/kern/link_elf_obj.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/kern/link_elf_obj.c Sun Sep 20 01:27:59 2015 (r288000) @@ -144,7 +144,8 @@ static void link_elf_reloc_local(linker_ 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 * 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_Siz * 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); } } Modified: head/sys/mips/mips/elf_machdep.c ============================================================================== --- head/sys/mips/mips/elf_machdep.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/mips/mips/elf_machdep.c Sun Sep 20 01:27:59 2015 (r288000) @@ -176,6 +176,7 @@ elf_reloc_internal(linker_file_t lf, Elf 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 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 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 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 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 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 } 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 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 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; Modified: head/sys/powerpc/powerpc/elf32_machdep.c ============================================================================== --- head/sys/powerpc/powerpc/elf32_machdep.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/powerpc/powerpc/elf32_machdep.c Sun Sep 20 01:27:59 2015 (r288000) @@ -183,6 +183,7 @@ elf_reloc_internal(linker_file_t lf, Elf 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 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 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 Modified: head/sys/powerpc/powerpc/elf64_machdep.c ============================================================================== --- head/sys/powerpc/powerpc/elf64_machdep.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/powerpc/powerpc/elf64_machdep.c Sun Sep 20 01:27:59 2015 (r288000) @@ -154,6 +154,7 @@ elf_reloc_internal(linker_file_t lf, Elf 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 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 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; Modified: head/sys/sparc64/sparc64/elf_machdep.c ============================================================================== --- head/sys/sparc64/sparc64/elf_machdep.c Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/sparc64/sparc64/elf_machdep.c Sun Sep 20 01:27:59 2015 (r288000) @@ -344,6 +344,7 @@ elf_reloc(linker_file_t lf, Elf_Addr rel 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 rel 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)) Modified: head/sys/sys/linker.h ============================================================================== --- head/sys/sys/linker.h Sun Sep 20 01:09:23 2015 (r287999) +++ head/sys/sys/linker.h Sun Sep 20 01:27:59 2015 (r288000) @@ -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);