svn commit: r338867 - in stable/11/sys: amd64/amd64 arm/arm arm64/arm64 i386/i386 kern mips/mips powerpc/powerpc riscv/riscv sparc64/sparc64 sys
Mark Johnston
markj at FreeBSD.org
Fri Sep 21 20:40:40 UTC 2018
Author: markj
Date: Fri Sep 21 20:40:37 2018
New Revision: 338867
URL: https://svnweb.freebsd.org/changeset/base/338867
Log:
MFC r338211:
Prepare the kernel linker to handle PC-relative ifunc relocations.
Modified:
stable/11/sys/amd64/amd64/elf_machdep.c
stable/11/sys/arm/arm/elf_machdep.c
stable/11/sys/arm64/arm64/elf_machdep.c
stable/11/sys/i386/i386/elf_machdep.c
stable/11/sys/kern/link_elf.c
stable/11/sys/kern/link_elf_obj.c
stable/11/sys/mips/mips/elf_machdep.c
stable/11/sys/powerpc/powerpc/elf32_machdep.c
stable/11/sys/powerpc/powerpc/elf64_machdep.c
stable/11/sys/riscv/riscv/elf_machdep.c
stable/11/sys/sparc64/sparc64/elf_machdep.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 Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/amd64/amd64/elf_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -173,13 +173,17 @@ elf64_dump_thread(struct thread *td, void *dst, size_t
*off = len;
}
-#define ERI_LOCAL 0x0001
-#define ERI_ONLYIFUNC 0x0002
+bool
+elf_is_ifunc_reloc(Elf_Size r_info)
+{
+ return (ELF_R_TYPE(r_info) == R_X86_64_IRELATIVE);
+}
+
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
- int type, elf_lookup_fn lookup, int flags)
+ int type, elf_lookup_fn lookup)
{
Elf64_Addr *where, val;
Elf32_Addr *where32, val32;
@@ -219,9 +223,6 @@ 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;
@@ -298,20 +299,11 @@ 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, lookup, 0));
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup));
}
int
@@ -319,8 +311,7 @@ elf_reloc_local(linker_file_t lf, Elf_Addr relocbase,
int type, elf_lookup_fn lookup)
{
- return (elf_reloc_internal(lf, relocbase, data, type, lookup,
- ERI_LOCAL));
+ return (elf_reloc_internal(lf, relocbase, data, type, lookup));
}
int
Modified: stable/11/sys/arm/arm/elf_machdep.c
==============================================================================
--- stable/11/sys/arm/arm/elf_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/arm/arm/elf_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -147,6 +147,13 @@ elf32_dump_thread(struct thread *td, void *dst, size_t
#endif
}
+bool
+elf_is_ifunc_reloc(Elf_Size r_info __unused)
+{
+
+ return (false);
+}
+
/*
* It is possible for the compiler to emit relocations for unaligned data.
* We handle this situation with these inlines.
Modified: stable/11/sys/arm64/arm64/elf_machdep.c
==============================================================================
--- stable/11/sys/arm64/arm64/elf_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/arm64/arm64/elf_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -129,6 +129,13 @@ elf64_dump_thread(struct thread *td __unused, void *ds
}
+bool
+elf_is_ifunc_reloc(Elf_Size r_info __unused)
+{
+
+ return (false);
+}
+
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
Modified: stable/11/sys/i386/i386/elf_machdep.c
==============================================================================
--- stable/11/sys/i386/i386/elf_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/i386/i386/elf_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -158,8 +158,14 @@ elf32_dump_thread(struct thread *td, void *dst, size_t
*off = len;
}
+bool
+elf_is_ifunc_reloc(Elf_Size r_info)
+{
+
+ return (ELF_R_TYPE(r_info) == R_386_IRELATIVE);
+}
+
#define ERI_LOCAL 0x0001
-#define ERI_ONLYIFUNC 0x0002
/* Process one elf relocation with addend. */
static int
@@ -193,9 +199,6 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
panic("unknown reloc type %d\n", type);
}
- 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);
@@ -260,15 +263,6 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbas
return -1;
}
return(0);
-}
-
-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
Modified: stable/11/sys/kern/link_elf.c
==============================================================================
--- stable/11/sys/kern/link_elf.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/kern/link_elf.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -186,11 +186,13 @@ static struct linker_class link_elf_class = {
link_elf_methods, sizeof(struct elf_file)
};
+typedef int (*elf_reloc_fn)(linker_file_t lf, Elf_Addr relocbase,
+ const void *data, int type, elf_lookup_fn lookup);
+
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 relocate_file1(elf_file_t ef, elf_lookup_fn lookup,
+ elf_reloc_fn reloc, bool ifuncs);
static int link_elf_preload_parse_symbols(elf_file_t);
static struct elf_set_head set_pcpu_list;
@@ -1186,96 +1188,61 @@ symbol_name(elf_file_t ef, Elf_Size r_info)
}
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))
+symbol_type(elf_file_t ef, Elf_Size r_info)
{
- const Elf_Rel *rellim;
+ const Elf_Sym *ref;
+
+ if (ELF_R_SYM(r_info)) {
+ ref = ef->symtab + ELF_R_SYM(r_info);
+ return (ELF_ST_TYPE(ref->st_info));
+ }
+ return (STT_NOTYPE);
+}
+
+static int
+relocate_file1(elf_file_t ef, elf_lookup_fn lookup, elf_reloc_fn reloc,
+ bool ifuncs)
+{
const Elf_Rel *rel;
- const Elf_Rela *relalim;
const Elf_Rela *rela;
const char *symname;
- /* Perform relocations without addend if there are any: */
- rel = ef->rel;
- if (rel != NULL) {
- rellim = (const Elf_Rel *)
- ((const char *)ef->rel + ef->relsize);
- while (rel < rellim) {
- 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);
- return (ENOENT);
- }
- rel++;
- }
- }
+#define APPLY_RELOCS(iter, tbl, tblsize, type) do { \
+ for ((iter) = (tbl); (iter) != NULL && \
+ (iter) < (tbl) + (tblsize) / sizeof(*(iter)); (iter)++) { \
+ if ((symbol_type(ef, (iter)->r_info) == \
+ STT_GNU_IFUNC || \
+ elf_is_ifunc_reloc((iter)->r_info)) != ifuncs) \
+ continue; \
+ if (reloc(&ef->lf, (Elf_Addr)ef->address, \
+ (iter), (type), lookup)) { \
+ symname = symbol_name(ef, (iter)->r_info); \
+ printf("link_elf: symbol %s undefined\n", \
+ symname); \
+ return (ENOENT); \
+ } \
+ } \
+} while (0)
- /* Perform relocations with addend if there are any: */
- rela = ef->rela;
- if (rela != NULL) {
- relalim = (const Elf_Rela *)
- ((const char *)ef->rela + ef->relasize);
- while (rela < relalim) {
- 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",
- symname);
- return (ENOENT);
- }
- rela++;
- }
- }
+ APPLY_RELOCS(rel, ef->rel, ef->relsize, ELF_RELOC_REL);
+ APPLY_RELOCS(rela, ef->rela, ef->relasize, ELF_RELOC_RELA);
+ APPLY_RELOCS(rel, ef->pltrel, ef->pltrelsize, ELF_RELOC_REL);
+ APPLY_RELOCS(rela, ef->pltrela, ef->pltrelasize, ELF_RELOC_RELA);
- /* Perform PLT relocations without addend if there are any: */
- rel = ef->pltrel;
- if (rel != NULL) {
- rellim = (const Elf_Rel *)
- ((const char *)ef->pltrel + ef->pltrelsize);
- while (rel < rellim) {
- 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);
- return (ENOENT);
- }
- rel++;
- }
- }
+#undef APPLY_RELOCS
- /* Perform relocations with addend if there are any: */
- rela = ef->pltrela;
- if (rela != NULL) {
- relalim = (const Elf_Rela *)
- ((const char *)ef->pltrela + ef->pltrelasize);
- while (rela < relalim) {
- 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",
- symname);
- return (ENOENT);
- }
- rela++;
- }
- }
-
return (0);
}
static int
relocate_file(elf_file_t ef)
{
- int e;
+ int error;
- e = relocate_file1(ef, elf_reloc);
-#if defined(__i386__) || defined(__amd64__)
- if (e == 0)
- e = relocate_file1(ef, elf_reloc_ifunc);
-#endif
- return (e);
+ error = relocate_file1(ef, elf_lookup, elf_reloc, false);
+ if (error == 0)
+ error = relocate_file1(ef, elf_lookup, elf_reloc, true);
+ return (error);
}
/*
@@ -1299,7 +1266,7 @@ elf_hash(const char *name)
}
static int
-link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
+link_elf_lookup_symbol(linker_file_t lf, const char *name, c_linker_sym_t *sym)
{
elf_file_t ef = (elf_file_t) lf;
unsigned long symnum;
@@ -1688,6 +1655,29 @@ link_elf_strtab_get(linker_file_t lf, caddr_t *strtab)
}
#if defined(__i386__) || defined(__amd64__)
+/*
+ * Use this lookup routine when performing relocations early during boot.
+ * The generic lookup routine depends on kobj, which is not initialized
+ * at that point.
+ */
+static int
+elf_lookup_ifunc(linker_file_t lf, Elf_Size symidx, int deps __unused,
+ Elf_Addr *res)
+{
+ elf_file_t ef;
+ const Elf_Sym *symp;
+ caddr_t val;
+
+ ef = (elf_file_t)lf;
+ symp = ef->symtab + symidx;
+ if (ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC) {
+ val = (caddr_t)ef->address + symp->st_value;
+ *res = ((Elf_Addr (*)(void))val)();
+ return (0);
+ }
+ return (ENOENT);
+}
+
void
link_elf_ireloc(caddr_t kmdp)
{
@@ -1696,7 +1686,7 @@ link_elf_ireloc(caddr_t kmdp)
volatile char *c;
size_t i;
- ef = &eff;
+ ef = &eff;
/* Do not use bzero/memset before ireloc is done. */
for (c = (char *)ef, i = 0; i < sizeof(*ef); i++)
@@ -1707,6 +1697,6 @@ link_elf_ireloc(caddr_t kmdp)
parse_dynamic(ef);
ef->address = 0;
link_elf_preload_parse_symbols(ef);
- relocate_file1(ef, elf_reloc_ifunc);
+ relocate_file1(ef, elf_lookup_ifunc, elf_reloc, true);
}
#endif
Modified: stable/11/sys/kern/link_elf_obj.c
==============================================================================
--- stable/11/sys/kern/link_elf_obj.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/kern/link_elf_obj.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -1513,15 +1513,10 @@ link_elf_reloc_local(linker_file_t lf, bool ifuncs)
/* Only do local relocs */
if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
continue;
- if ((ELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) ==
- ifuncs)
+ if ((ELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC ||
+ elf_is_ifunc_reloc(rel->r_info)) == ifuncs)
elf_reloc_local(lf, base, rel, ELF_RELOC_REL,
elf_obj_lookup);
-#if defined(__i386__) || defined(__amd64__)
- else if (ifuncs)
- elf_reloc_ifunc(lf, base, rel, ELF_RELOC_REL,
- elf_obj_lookup);
-#endif
}
}
@@ -1546,15 +1541,10 @@ link_elf_reloc_local(linker_file_t lf, bool ifuncs)
/* Only do local relocs */
if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
continue;
- if ((ELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) ==
- ifuncs)
+ if ((ELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC ||
+ elf_is_ifunc_reloc(rela->r_info)) == ifuncs)
elf_reloc_local(lf, base, rela, ELF_RELOC_RELA,
elf_obj_lookup);
-#if defined(__i386__) || defined(__amd64__)
- else if (ifuncs)
- elf_reloc_ifunc(lf, base, rela, ELF_RELOC_RELA,
- elf_obj_lookup);
-#endif
}
}
return (0);
Modified: stable/11/sys/mips/mips/elf_machdep.c
==============================================================================
--- stable/11/sys/mips/mips/elf_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/mips/mips/elf_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -161,6 +161,13 @@ elf32_dump_thread(struct thread *td __unused, void *ds
}
#endif
+bool
+elf_is_ifunc_reloc(Elf_Size r_info __unused)
+{
+
+ return (false);
+}
+
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
Modified: stable/11/sys/powerpc/powerpc/elf32_machdep.c
==============================================================================
--- stable/11/sys/powerpc/powerpc/elf32_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/powerpc/powerpc/elf32_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -170,6 +170,13 @@ elf32_dump_thread(struct thread *td, void *dst, size_t
}
#ifndef __powerpc64__
+bool
+elf_is_ifunc_reloc(Elf_Size r_info __unused)
+{
+
+ return (false);
+}
+
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
Modified: stable/11/sys/powerpc/powerpc/elf64_machdep.c
==============================================================================
--- stable/11/sys/powerpc/powerpc/elf64_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/powerpc/powerpc/elf64_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -246,6 +246,12 @@ elf64_dump_thread(struct thread *td, void *dst, size_t
*off = len;
}
+bool
+elf_is_ifunc_reloc(Elf_Size r_info __unused)
+{
+
+ return (false);
+}
/* Process one elf relocation with addend. */
static int
Modified: stable/11/sys/riscv/riscv/elf_machdep.c
==============================================================================
--- stable/11/sys/riscv/riscv/elf_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/riscv/riscv/elf_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -259,6 +259,13 @@ reloctype_to_str(int type)
return "*unknown*";
}
+bool
+elf_is_ifunc_reloc(Elf_Size r_info __unused)
+{
+
+ return (false);
+}
+
/*
* Currently kernel loadable module for RISCV is compiled with -fPIC option.
* (see also additional CFLAGS definition for RISCV in sys/conf/kmod.mk)
Modified: stable/11/sys/sparc64/sparc64/elf_machdep.c
==============================================================================
--- stable/11/sys/sparc64/sparc64/elf_machdep.c Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/sparc64/sparc64/elf_machdep.c Fri Sep 21 20:40:37 2018 (r338867)
@@ -310,6 +310,13 @@ static const long reloc_target_bitmask[] = {
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
+bool
+elf_is_ifunc_reloc(Elf_Size r_info __unused)
+{
+
+ return (false);
+}
+
int
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup __unused)
Modified: stable/11/sys/sys/linker.h
==============================================================================
--- stable/11/sys/sys/linker.h Fri Sep 21 20:38:23 2018 (r338866)
+++ stable/11/sys/sys/linker.h Fri Sep 21 20:40:37 2018 (r338867)
@@ -269,9 +269,8 @@ extern int kld_debug;
typedef int elf_lookup_fn(linker_file_t, Elf_Size, int, Elf_Addr *);
/* Support functions */
+bool elf_is_ifunc_reloc(Elf_Size r_info);
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);
More information about the svn-src-stable
mailing list