Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Sep 2015 01:28:00 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
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
Message-ID:  <201509200128.t8K1S02o005905@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509200128.t8K1S02o005905>