svn commit: r333720 - in stable/11/sys: amd64/amd64 i386/i386 kern sys

Konstantin Belousov kib at FreeBSD.org
Thu May 17 15:24:55 UTC 2018


Author: kib
Date: Thu May 17 15:24:53 2018
New Revision: 333720
URL: https://svnweb.freebsd.org/changeset/base/333720

Log:
  MFC r333228
  Implement support for ifuncs in the kernel linker on x86.
  
  MFC r333411:
  Avoid calls to bzero() before ireloc
  
  Approved by:	re (marius)

Modified:
  stable/11/sys/amd64/amd64/elf_machdep.c
  stable/11/sys/amd64/amd64/machdep.c
  stable/11/sys/i386/i386/elf_machdep.c
  stable/11/sys/i386/i386/machdep.c
  stable/11/sys/kern/link_elf.c
  stable/11/sys/kern/link_elf_obj.c
  stable/11/sys/sys/linker.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/amd64/amd64/elf_machdep.c
==============================================================================
--- stable/11/sys/amd64/amd64/elf_machdep.c	Thu May 17 15:21:19 2018	(r333719)
+++ stable/11/sys/amd64/amd64/elf_machdep.c	Thu May 17 15:24:53 2018	(r333720)
@@ -173,10 +173,13 @@ elf64_dump_thread(struct thread *td, void *dst, size_t
 	*off = len;
 }
 
+#define	ERI_LOCAL	0x0001
+#define	ERI_ONLYIFUNC	0x0002
+
 /* Process one elf relocation with addend. */
 static int
 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
-    int type, int local, elf_lookup_fn lookup)
+    int type, elf_lookup_fn lookup, int flags)
 {
 	Elf64_Addr *where, val;
 	Elf32_Addr *where32, val32;
@@ -215,6 +218,9 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
 		panic("unknown reloc type %d\n", type);
 	}
 
+	if (((flags & ERI_ONLYIFUNC) == 0) ^ (rtype != R_X86_64_IRELATIVE))
+		return (0);
+
 	switch (rtype) {
 		case R_X86_64_NONE:	/* none */
 			break;
@@ -273,6 +279,13 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
 				*where = val;
 			break;
 
+		case R_X86_64_IRELATIVE:
+			addr = relocbase + addend;
+			val = ((Elf64_Addr (*)(void))addr)();
+			if (*where != val)
+				*where = val;
+			break;
+
 		default:
 			printf("kldload: unexpected relocation type %ld\n",
 			       rtype);
@@ -282,11 +295,20 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
 }
 
 int
+elf_reloc_ifunc(linker_file_t lf, Elf_Addr relocbase, const void *data,
+    int type, elf_lookup_fn lookup)
+{
+
+	return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+	    ERI_ONLYIFUNC));
+}
+
+int
 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
     elf_lookup_fn lookup)
 {
 
-	return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
+	return (elf_reloc_internal(lf, relocbase, data, type, lookup, 0));
 }
 
 int
@@ -294,7 +316,8 @@ elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, 
     int type, elf_lookup_fn lookup)
 {
 
-	return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
+	return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+	    ERI_LOCAL));
 }
 
 int

Modified: stable/11/sys/amd64/amd64/machdep.c
==============================================================================
--- stable/11/sys/amd64/amd64/machdep.c	Thu May 17 15:21:19 2018	(r333719)
+++ stable/11/sys/amd64/amd64/machdep.c	Thu May 17 15:24:53 2018	(r333720)
@@ -1564,16 +1564,23 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 	size_t kstack0_sz;
 	int late_console;
 
-	/*
- 	 * This may be done better later if it gets more high level
- 	 * components in it. If so just link td->td_proc here.
-	 */
-	proc_linkup0(&proc0, &thread0);
-
 	kmdp = init_ops.parse_preload_data(modulep);
 
 	identify_cpu1();
 	identify_hypervisor();
+	/*
+	 * hw.cpu_stdext_disable is ignored by the call, it will be
+	 * re-evaluted by the below call to finishidentcpu().
+	 */
+	identify_cpu2();
+
+	link_elf_ireloc(kmdp);
+
+	/*
+	 * This may be done better later if it gets more high level
+	 * components in it. If so just link td->td_proc here.
+	 */
+	proc_linkup0(&proc0, &thread0);
 
 	/* Init basic tunables, hz etc */
 	init_param1();

Modified: stable/11/sys/i386/i386/elf_machdep.c
==============================================================================
--- stable/11/sys/i386/i386/elf_machdep.c	Thu May 17 15:21:19 2018	(r333719)
+++ stable/11/sys/i386/i386/elf_machdep.c	Thu May 17 15:24:53 2018	(r333720)
@@ -158,10 +158,13 @@ elf32_dump_thread(struct thread *td, void *dst, size_t
 	*off = len;
 }
 
+#define	ERI_LOCAL	0x0001
+#define	ERI_ONLYIFUNC	0x0002
+
 /* Process one elf relocation with addend. */
 static int
 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
-    int type, int local, elf_lookup_fn lookup)
+    int type, elf_lookup_fn lookup, int flags)
 {
 	Elf_Addr *where;
 	Elf_Addr addr;
@@ -190,7 +193,10 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
 		panic("unknown reloc type %d\n", type);
 	}
 
-	if (local) {
+	if (((flags & ERI_ONLYIFUNC) == 0) ^ (rtype != R_386_IRELATIVE))
+		return (0);
+
+	if ((flags & ERI_LOCAL) != 0) {
 		if (rtype == R_386_RELATIVE) {	/* A + B */
 			addr = elf_relocaddr(lf, relocbase + addend);
 			if (*where != addr)
@@ -242,6 +248,12 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
 		case R_386_RELATIVE:
 			break;
 
+		case R_386_IRELATIVE:
+			addr = relocbase + addend;
+			addr = ((Elf_Addr (*)(void))addr)();
+			if (*where != addr)
+				*where = addr;
+			break;
 		default:
 			printf("kldload: unexpected relocation type %d\n",
 			       rtype);
@@ -251,11 +263,20 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
 }
 
 int
+elf_reloc_ifunc(linker_file_t lf, Elf_Addr relocbase, const void *data,
+    int type, elf_lookup_fn lookup)
+{
+
+	return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+	    ERI_ONLYIFUNC));
+}
+
+int
 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
     elf_lookup_fn lookup)
 {
 
-	return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
+	return (elf_reloc_internal(lf, relocbase, data, type, lookup, 0));
 }
 
 int
@@ -263,7 +284,8 @@ elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, 
     int type, elf_lookup_fn lookup)
 {
 
-	return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
+	return (elf_reloc_internal(lf, relocbase, data, type, lookup,
+	    ERI_LOCAL));
 }
 
 int

Modified: stable/11/sys/i386/i386/machdep.c
==============================================================================
--- stable/11/sys/i386/i386/machdep.c	Thu May 17 15:21:19 2018	(r333719)
+++ stable/11/sys/i386/i386/machdep.c	Thu May 17 15:24:53 2018	(r333720)
@@ -2441,6 +2441,7 @@ init386(int first)
 	int gsel_tss, metadata_missing, x, pa;
 	struct pcpu *pc;
 	struct xstate_hdr *xhdr;
+	caddr_t kmdp;
 	int late_console;
 
 	thread0.td_kstack = proc0kstack;
@@ -2687,6 +2688,9 @@ init386(int first)
 		cninit();
 		i386_kdb_init();
 	}
+
+	kmdp = preload_search_by_type("elf kernel");
+	link_elf_ireloc(kmdp);
 
 	vm86_initialize();
 	getmemsize(first);

Modified: stable/11/sys/kern/link_elf.c
==============================================================================
--- stable/11/sys/kern/link_elf.c	Thu May 17 15:21:19 2018	(r333719)
+++ stable/11/sys/kern/link_elf.c	Thu May 17 15:24:53 2018	(r333720)
@@ -188,6 +188,9 @@ static struct linker_class link_elf_class = {
 
 static int	parse_dynamic(elf_file_t);
 static int	relocate_file(elf_file_t);
+static int	relocate_file1(elf_file_t ef, int (*elf_reloc_func)(
+		    linker_file_t lf, Elf_Addr relocbase, const void *data,
+		    int type, elf_lookup_fn lookup));
 static int	link_elf_preload_parse_symbols(elf_file_t);
 
 static struct elf_set_head set_pcpu_list;
@@ -1183,7 +1186,8 @@ symbol_name(elf_file_t ef, Elf_Size r_info)
 }
 
 static int
-relocate_file(elf_file_t ef)
+relocate_file1(elf_file_t ef, int (*elf_reloc_func)(linker_file_t lf,
+    Elf_Addr relocbase, const void *data, int type, elf_lookup_fn lookup))
 {
 	const Elf_Rel *rellim;
 	const Elf_Rel *rel;
@@ -1197,7 +1201,7 @@ relocate_file(elf_file_t ef)
 		rellim = (const Elf_Rel *)
 		    ((const char *)ef->rel + ef->relsize);
 		while (rel < rellim) {
-			if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel,
+			if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rel,
 			    ELF_RELOC_REL, elf_lookup)) {
 				symname = symbol_name(ef, rel->r_info);
 				printf("link_elf: symbol %s undefined\n", symname);
@@ -1213,7 +1217,7 @@ relocate_file(elf_file_t ef)
 		relalim = (const Elf_Rela *)
 		    ((const char *)ef->rela + ef->relasize);
 		while (rela < relalim) {
-			if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela,
+			if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rela,
 			    ELF_RELOC_RELA, elf_lookup)) {
 				symname = symbol_name(ef, rela->r_info);
 				printf("link_elf: symbol %s undefined\n",
@@ -1230,7 +1234,7 @@ relocate_file(elf_file_t ef)
 		rellim = (const Elf_Rel *)
 		    ((const char *)ef->pltrel + ef->pltrelsize);
 		while (rel < rellim) {
-			if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel,
+			if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rel,
 			    ELF_RELOC_REL, elf_lookup)) {
 				symname = symbol_name(ef, rel->r_info);
 				printf("link_elf: symbol %s undefined\n",
@@ -1247,7 +1251,7 @@ relocate_file(elf_file_t ef)
 		relalim = (const Elf_Rela *)
 		    ((const char *)ef->pltrela + ef->pltrelasize);
 		while (rela < relalim) {
-			if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela,
+			if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rela,
 			    ELF_RELOC_RELA, elf_lookup)) {
 				symname = symbol_name(ef, rela->r_info);
 				printf("link_elf: symbol %s undefined\n",
@@ -1261,6 +1265,19 @@ relocate_file(elf_file_t ef)
 	return (0);
 }
 
+static int
+relocate_file(elf_file_t ef)
+{
+	int e;
+
+	e = relocate_file1(ef, elf_reloc);
+#if defined(__i386__) || defined(__amd64__)
+	if (e == 0)
+		e = relocate_file1(ef, elf_reloc_ifunc);
+#endif
+	return (e);
+}
+
 /*
  * Hash function for symbol table lookup.  Don't even think about changing
  * this.  It is specified by the System V ABI.
@@ -1318,7 +1335,8 @@ link_elf_lookup_symbol(linker_file_t lf, const char* n
 		if (strcmp(name, strp) == 0) {
 			if (symp->st_shndx != SHN_UNDEF ||
 			    (symp->st_value != 0 &&
-			     ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
+			    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+			    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC))) {
 				*sym = (c_linker_sym_t) symp;
 				return (0);
 			}
@@ -1338,7 +1356,8 @@ link_elf_lookup_symbol(linker_file_t lf, const char* n
 		if (strcmp(name, strp) == 0) {
 			if (symp->st_shndx != SHN_UNDEF ||
 			    (symp->st_value != 0 &&
-			     ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
+			    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+			    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC))) {
 				*sym = (c_linker_sym_t) symp;
 				return (0);
 			}
@@ -1353,12 +1372,18 @@ static int
 link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
     linker_symval_t *symval)
 {
-	elf_file_t ef = (elf_file_t) lf;
-	const Elf_Sym* es = (const Elf_Sym*) sym;
+	elf_file_t ef;
+	const Elf_Sym *es;
+	caddr_t val;
 
+	ef = (elf_file_t)lf;
+	es = (const Elf_Sym *)sym;
 	if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
 		symval->name = ef->strtab + es->st_name;
-		symval->value = (caddr_t) ef->address + es->st_value;
+		val = (caddr_t)ef->address + es->st_value;
+		if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
+			val = ((caddr_t (*)(void))val)();
+		symval->value = val;
 		symval->size = es->st_size;
 		return (0);
 	}
@@ -1366,7 +1391,10 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_
 		return (ENOENT);
 	if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
 		symval->name = ef->ddbstrtab + es->st_name;
-		symval->value = (caddr_t) ef->address + es->st_value;
+		val = (caddr_t)ef->address + es->st_value;
+		if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
+			val = ((caddr_t (*)(void))val)();
+		symval->value = val;
 		symval->size = es->st_size;
 		return (0);
 	}
@@ -1476,7 +1504,8 @@ link_elf_each_function_name(linker_file_t file,
 	/* Exhaustive search */
 	for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
 		if (symp->st_value != 0 &&
-		    ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
+		    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+		    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
 			error = callback(ef->ddbstrtab + symp->st_name, opaque);
 			if (error != 0)
 				return (error);
@@ -1497,7 +1526,8 @@ link_elf_each_function_nameval(linker_file_t file,
 	/* Exhaustive search */
 	for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
 		if (symp->st_value != 0 &&
-		    ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
+		    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+		    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
 			error = link_elf_symbol_values(file,
 			    (c_linker_sym_t) symp, &symval);
 			if (error != 0)
@@ -1656,3 +1686,27 @@ link_elf_strtab_get(linker_file_t lf, caddr_t *strtab)
 
 	return (ef->ddbstrcnt);
 }
+
+#if defined(__i386__) || defined(__amd64__)
+void
+link_elf_ireloc(caddr_t kmdp)
+{
+	struct elf_file eff;
+	elf_file_t ef;
+	volatile char *c;
+	size_t i;
+
+	ef =  &eff;
+
+	/* Do not use bzero/memset before ireloc is done. */
+	for (c = (char *)ef, i = 0; i < sizeof(*ef); i++)
+		c[i] = 0;
+
+	ef->modptr = kmdp;
+	ef->dynamic = (Elf_Dyn *)&_DYNAMIC;
+	parse_dynamic(ef);
+	ef->address = 0;
+	link_elf_preload_parse_symbols(ef);
+	relocate_file1(ef, elf_reloc_ifunc);
+}
+#endif

Modified: stable/11/sys/kern/link_elf_obj.c
==============================================================================
--- stable/11/sys/kern/link_elf_obj.c	Thu May 17 15:21:19 2018	(r333719)
+++ stable/11/sys/kern/link_elf_obj.c	Thu May 17 15:24:53 2018	(r333720)
@@ -1194,12 +1194,19 @@ static int
 link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
     linker_symval_t *symval)
 {
-	elf_file_t ef = (elf_file_t) lf;
-	const Elf_Sym *es = (const Elf_Sym*) sym;
+	elf_file_t ef;
+	const Elf_Sym *es;
+	caddr_t val;
 
+	ef = (elf_file_t) lf;
+	es = (const Elf_Sym*) sym;
+	val = (caddr_t)es->st_value;
 	if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
 		symval->name = ef->ddbstrtab + es->st_name;
-		symval->value = (caddr_t)es->st_value;
+		val = (caddr_t)es->st_value;
+		if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
+			val = ((caddr_t (*)(void))val)();
+		symval->value = val;
 		symval->size = es->st_size;
 		return 0;
 	}
@@ -1284,7 +1291,8 @@ link_elf_each_function_name(linker_file_t file,
 	/* Exhaustive search */
 	for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
 		if (symp->st_value != 0 &&
-		    ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
+		    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+		    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
 			error = callback(ef->ddbstrtab + symp->st_name, opaque);
 			if (error)
 				return (error);
@@ -1305,8 +1313,10 @@ link_elf_each_function_nameval(linker_file_t file,
 	/* Exhaustive search */
 	for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
 		if (symp->st_value != 0 &&
-		    ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
-			error = link_elf_symbol_values(file, (c_linker_sym_t) symp, &symval);
+		    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+		    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
+			error = link_elf_symbol_values(file,
+			    (c_linker_sym_t)symp, &symval);
 			if (error)
 				return (error);
 			error = callback(file, i, &symval, opaque);

Modified: stable/11/sys/sys/linker.h
==============================================================================
--- stable/11/sys/sys/linker.h	Thu May 17 15:21:19 2018	(r333719)
+++ stable/11/sys/sys/linker.h	Thu May 17 15:24:53 2018	(r333720)
@@ -269,11 +269,16 @@ extern int kld_debug;
 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);
-int	elf_reloc_local(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu);
+int	elf_reloc(linker_file_t _lf, Elf_Addr base, const void *_rel,
+	    int _type, elf_lookup_fn _lu);
+int	elf_reloc_ifunc(linker_file_t _lf, Elf_Addr base, const void *_rel,
+	    int _type, elf_lookup_fn _lu);
+int	elf_reloc_local(linker_file_t _lf, Elf_Addr base, const void *_rel,
+	    int _type, elf_lookup_fn _lu);
 Elf_Addr elf_relocaddr(linker_file_t _lf, Elf_Addr addr);
 const Elf_Sym *elf_get_sym(linker_file_t _lf, Elf_Size _symidx);
 const char *elf_get_symname(linker_file_t _lf, Elf_Size _symidx);
+void	link_elf_ireloc(caddr_t kmdp);
 
 typedef struct linker_ctf {
 	const uint8_t 	*ctftab;	/* Decompressed CTF data. */


More information about the svn-src-all mailing list