summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/alpha/alpha/elf_machdep.c30
-rw-r--r--sys/amd64/amd64/elf_machdep.c32
-rw-r--r--sys/i386/i386/elf_machdep.c32
-rw-r--r--sys/ia64/ia64/elf_machdep.c25
-rw-r--r--sys/kern/kern_linker.c102
-rw-r--r--sys/kern/link_elf.c32
-rw-r--r--sys/kern/link_elf_obj.c32
-rw-r--r--sys/powerpc/powerpc/elf_machdep.c18
-rw-r--r--sys/sparc64/sparc64/elf_machdep.c24
-rw-r--r--sys/sys/linker.h1
10 files changed, 232 insertions, 96 deletions
diff --git a/sys/alpha/alpha/elf_machdep.c b/sys/alpha/alpha/elf_machdep.c
index 285a174..1b3c6f2 100644
--- a/sys/alpha/alpha/elf_machdep.c
+++ b/sys/alpha/alpha/elf_machdep.c
@@ -89,8 +89,8 @@ SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
&freebsd_brand_info);
/* Process one elf relocation with addend. */
-int
-elf_reloc(linker_file_t lf, const void *data, int type)
+static int
+elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
@@ -119,6 +119,15 @@ elf_reloc(linker_file_t lf, const void *data, int type)
panic("elf_reloc: unknown relocation mode %d\n", type);
}
+ if (local) {
+ if (rtype == R_ALPHA_RELATIVE) {
+ addr = relocbase + addend;
+ if (*where != addr)
+ *where = addr;
+ }
+ return (0);
+ }
+
switch (rtype) {
case R_ALPHA_NONE:
@@ -152,9 +161,6 @@ elf_reloc(linker_file_t lf, const void *data, int type)
break;
case R_ALPHA_RELATIVE:
- addr = relocbase + addend;
- if (*where != addr)
- *where = addr;
break;
case R_ALPHA_COPY:
@@ -174,6 +180,20 @@ elf_reloc(linker_file_t lf, const void *data, int type)
}
int
+elf_reloc(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 0));
+}
+
+int
+elf_reloc_local(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 1));
+}
+
+int
elf_cpu_load_file(linker_file_t lf __unused)
{
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index 71520de..4cf9f21 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
@@ -86,8 +86,8 @@ SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
&freebsd_brand_info);
/* Process one elf relocation with addend. */
-int
-elf_reloc(linker_file_t lf, const void *data, int type)
+static int
+elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
@@ -116,6 +116,15 @@ elf_reloc(linker_file_t lf, const void *data, int type)
panic("unknown reloc type %d\n", type);
}
+ if (local) {
+ if (rtype == R_386_RELATIVE) { /* A + B */
+ addr = relocbase + addend;
+ if (*where != addr)
+ *where = addr;
+ }
+ return (0);
+ }
+
switch (rtype) {
case R_386_NONE: /* none */
@@ -156,10 +165,7 @@ elf_reloc(linker_file_t lf, const void *data, int type)
*where = addr;
break;
- case R_386_RELATIVE: /* B + A */
- addr = relocbase + addend;
- if (*where != addr)
- *where = addr;
+ case R_386_RELATIVE:
break;
default:
@@ -171,6 +177,20 @@ elf_reloc(linker_file_t lf, const void *data, int type)
}
int
+elf_reloc(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 0));
+}
+
+int
+elf_reloc_local(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 1));
+}
+
+int
elf_cpu_load_file(linker_file_t lf __unused)
{
diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c
index 71520de..4cf9f21 100644
--- a/sys/i386/i386/elf_machdep.c
+++ b/sys/i386/i386/elf_machdep.c
@@ -86,8 +86,8 @@ SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
&freebsd_brand_info);
/* Process one elf relocation with addend. */
-int
-elf_reloc(linker_file_t lf, const void *data, int type)
+static int
+elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
@@ -116,6 +116,15 @@ elf_reloc(linker_file_t lf, const void *data, int type)
panic("unknown reloc type %d\n", type);
}
+ if (local) {
+ if (rtype == R_386_RELATIVE) { /* A + B */
+ addr = relocbase + addend;
+ if (*where != addr)
+ *where = addr;
+ }
+ return (0);
+ }
+
switch (rtype) {
case R_386_NONE: /* none */
@@ -156,10 +165,7 @@ elf_reloc(linker_file_t lf, const void *data, int type)
*where = addr;
break;
- case R_386_RELATIVE: /* B + A */
- addr = relocbase + addend;
- if (*where != addr)
- *where = addr;
+ case R_386_RELATIVE:
break;
default:
@@ -171,6 +177,20 @@ elf_reloc(linker_file_t lf, const void *data, int type)
}
int
+elf_reloc(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 0));
+}
+
+int
+elf_reloc_local(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 1));
+}
+
+int
elf_cpu_load_file(linker_file_t lf __unused)
{
diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c
index c4a4938..b3c7d90 100644
--- a/sys/ia64/ia64/elf_machdep.c
+++ b/sys/ia64/ia64/elf_machdep.c
@@ -141,8 +141,8 @@ lookup_fdesc(linker_file_t lf, Elf_Word symidx)
}
/* Process one elf relocation with addend. */
-int
-elf_reloc(linker_file_t lf, const void *data, int type)
+static int
+elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
{
Elf_Addr relocbase = (Elf_Addr)lf->address;
Elf_Addr *where;
@@ -179,6 +179,12 @@ elf_reloc(linker_file_t lf, const void *data, int type)
panic("%s: invalid ELF relocation (0x%x)\n", __func__, type);
}
+ if (local) {
+ if (rtype == R_IA64_REL64LSB)
+ *where = relocbase + addend;
+ return (0);
+ }
+
switch (rtype) {
case R_IA64_NONE:
break;
@@ -199,7 +205,6 @@ elf_reloc(linker_file_t lf, const void *data, int type)
*where = addr;
break;
case R_IA64_REL64LSB: /* word64 LSB BD + A */
- *where = relocbase + addend;
break;
case R_IA64_IPLTLSB:
addr = lookup_fdesc(lf, symidx);
@@ -218,6 +223,20 @@ elf_reloc(linker_file_t lf, const void *data, int type)
}
int
+elf_reloc(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 0));
+}
+
+int
+elf_reloc_local(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 1));
+}
+
+int
elf_cpu_load_file(linker_file_t lf)
{
Elf_Ehdr *hdr;
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index c1a7d3a..3c38bac 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -499,7 +499,7 @@ linker_file_unload(linker_file_t file)
* Give the module a chance to veto the unload.
*/
if ((error = module_unload(mod)) != 0) {
- KLD_DPF(FILE, ("linker_file_unload: module %x"
+ KLD_DPF(FILE, ("linker_file_unload: module %p"
" vetoes unload\n", mod));
goto out;
} else
@@ -594,7 +594,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
size_t common_size = 0;
int i;
- KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
+ KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n",
file, name, deps));
if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
@@ -608,7 +608,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
common_size = symval.size;
else {
KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol"
- ".value=%x\n", symval.value));
+ ".value=%p\n", symval.value));
return (symval.value);
}
}
@@ -618,7 +618,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
name, 0);
if (address) {
KLD_DPF(SYM, ("linker_file_lookup_symbol:"
- " deps value=%x\n", address));
+ " deps value=%p\n", address));
return (address);
}
}
@@ -634,7 +634,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
STAILQ_FOREACH(cp, &file->common, link) {
if (strcmp(cp->name, name) == 0) {
KLD_DPF(SYM, ("linker_file_lookup_symbol:"
- " old common value=%x\n", cp->address));
+ " old common value=%p\n", cp->address));
return (cp->address);
}
}
@@ -656,7 +656,7 @@ linker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
STAILQ_INSERT_TAIL(&file->common, cp, link);
KLD_DPF(SYM, ("linker_file_lookup_symbol: new common"
- " value=%x\n", cp->address));
+ " value=%p\n", cp->address));
return (cp->address);
}
KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
@@ -1106,46 +1106,6 @@ modlist_newmodule(const char *modname, int version, linker_file_t container)
return (mod);
}
-/*
- * This routine is cheap and nasty but will work for data pointers.
- */
-static void *
-linker_reloc_ptr(linker_file_t lf, const void *offset)
-{
- return (lf->address + (uintptr_t)offset);
-}
-
-/*
- * Dereference MDT_VERSION metadata into module name and version
- */
-static void
-linker_mdt_version(linker_file_t lf, struct mod_metadata *mp,
- const char **modname, int *version)
-{
- struct mod_version *mvp;
-
- if (modname)
- *modname = linker_reloc_ptr(lf, mp->md_cval);
- if (version) {
- mvp = linker_reloc_ptr(lf, mp->md_data);
- *version = mvp->mv_version;
- }
-}
-
-/*
- * Dereference MDT_DEPEND metadata into module name and mod_depend structure
- */
-static void
-linker_mdt_depend(linker_file_t lf, struct mod_metadata *mp,
- const char **modname, struct mod_depend **verinfo)
-{
-
- if (modname)
- *modname = linker_reloc_ptr(lf, mp->md_cval);
- if (verinfo)
- *verinfo = linker_reloc_ptr(lf, mp->md_data);
-}
-
static void
linker_addmodules(linker_file_t lf, struct mod_metadata **start,
struct mod_metadata **stop, int preload)
@@ -1155,17 +1115,11 @@ linker_addmodules(linker_file_t lf, struct mod_metadata **start,
int ver;
for (mdp = start; mdp < stop; mdp++) {
- if (preload)
- mp = *mdp;
- else
- mp = linker_reloc_ptr(lf, *mdp);
+ mp = *mdp;
if (mp->md_type != MDT_VERSION)
continue;
- if (preload) {
- modname = mp->md_cval;
- ver = ((struct mod_version *)mp->md_data)->mv_version;
- } else
- linker_mdt_version(lf, mp, &modname, &ver);
+ modname = mp->md_cval;
+ ver = ((struct mod_version *)mp->md_data)->mv_version;
if (modlist_lookup(modname, ver) != NULL) {
printf("module %s already present!\n", modname);
/* XXX what can we do? this is a build error. :-( */
@@ -1249,18 +1203,16 @@ restart:
resolves = 1; /* unless we know otherwise */
if (!error) {
for (mdp = start; mdp < stop; mdp++) {
- mp = linker_reloc_ptr(lf, *mdp);
+ mp = *mdp;
if (mp->md_type != MDT_DEPEND)
continue;
- linker_mdt_depend(lf, mp, &modname, &verinfo);
+ modname = mp->md_cval;
+ verinfo = mp->md_data;
for (nmdp = start; nmdp < stop; nmdp++) {
- nmp = linker_reloc_ptr(lf, *nmdp);
+ nmp = *nmdp;
if (nmp->md_type != MDT_VERSION)
continue;
- linker_mdt_version(lf, nmp, &nmodname,
- NULL);
- nmodname = linker_reloc_ptr(lf,
- nmp->md_cval);
+ nmodname = nmp->md_cval;
if (strcmp(modname, nmodname) == 0)
break;
}
@@ -1283,11 +1235,12 @@ restart:
if (resolves) {
if (!error) {
for (mdp = start; mdp < stop; mdp++) {
- mp = linker_reloc_ptr(lf, *mdp);
+ mp = *mdp;
if (mp->md_type != MDT_VERSION)
continue;
- linker_mdt_version(lf, mp,
- &modname, &nver);
+ modname = mp->md_cval;
+ nver = ((struct mod_version *)
+ mp->md_data)->mv_version;
if (modlist_lookup(modname,
nver) != NULL) {
printf("module %s already"
@@ -1338,10 +1291,11 @@ restart:
&stop, NULL);
if (!error) {
for (mdp = start; mdp < stop; mdp++) {
- mp = linker_reloc_ptr(lf, *mdp);
+ mp = *mdp;
if (mp->md_type != MDT_DEPEND)
continue;
- linker_mdt_depend(lf, mp, &modname, &verinfo);
+ modname = mp->md_cval;
+ verinfo = mp->md_data;
mod = modlist_lookup2(modname, verinfo);
mod->container->refs++;
error = linker_file_add_dependency(lf,
@@ -1763,10 +1717,11 @@ linker_load_dependencies(linker_file_t lf)
&count) != 0)
return (0);
for (mdp = start; mdp < stop; mdp++) {
- mp = linker_reloc_ptr(lf, *mdp);
+ mp = *mdp;
if (mp->md_type != MDT_VERSION)
continue;
- linker_mdt_version(lf, mp, &modname, &ver);
+ modname = mp->md_cval;
+ ver = ((struct mod_version *)mp->md_data)->mv_version;
mod = modlist_lookup(modname, ver);
if (mod != NULL) {
printf("interface %s.%d already present in the KLD"
@@ -1777,16 +1732,17 @@ linker_load_dependencies(linker_file_t lf)
}
for (mdp = start; mdp < stop; mdp++) {
- mp = linker_reloc_ptr(lf, *mdp);
+ mp = *mdp;
if (mp->md_type != MDT_DEPEND)
continue;
- linker_mdt_depend(lf, mp, &modname, &verinfo);
+ modname = mp->md_cval;
+ verinfo = mp->md_data;
nmodname = NULL;
for (nmdp = start; nmdp < stop; nmdp++) {
- nmp = linker_reloc_ptr(lf, *nmdp);
+ nmp = *nmdp;
if (nmp->md_type != MDT_VERSION)
continue;
- nmodname = linker_reloc_ptr(lf, nmp->md_cval);
+ nmodname = nmp->md_cval;
if (strcmp(modname, nmodname) == 0)
break;
}
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 3e5224e..f15803f 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -116,6 +116,7 @@ static int link_elf_lookup_set(linker_file_t, const char *,
static int link_elf_each_function_name(linker_file_t,
int (*)(const char *, void *),
void *);
+static void link_elf_reloc_local(linker_file_t);
static kobj_method_t link_elf_methods[] = {
KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol),
@@ -488,6 +489,7 @@ link_elf_link_preload(linker_class_t cls,
linker_file_unload(lf);
return error;
}
+ link_elf_reloc_local(lf);
*result = lf;
return (0);
}
@@ -748,6 +750,8 @@ link_elf_load_file(linker_class_t cls, const char* filename,
error = parse_dynamic(ef);
if (error)
goto out;
+ link_elf_reloc_local(lf);
+
error = linker_load_dependencies(lf);
if (error)
goto out;
@@ -1266,3 +1270,31 @@ elf_lookup(linker_file_t lf, Elf_Word symidx, int deps)
return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
}
+
+static void
+link_elf_reloc_local(linker_file_t lf)
+{
+ const Elf_Rel *rellim;
+ const Elf_Rel *rel;
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
+ elf_file_t ef = (elf_file_t)lf;
+
+ /* Perform relocations without addend if there are any: */
+ if ((rel = ef->rel) != NULL) {
+ rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
+ while (rel < rellim) {
+ elf_reloc_local(lf, rel, ELF_RELOC_REL);
+ rel++;
+ }
+ }
+
+ /* Perform relocations with addend if there are any: */
+ if ((rela = ef->rela) != NULL) {
+ relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
+ while (rela < relalim) {
+ elf_reloc_local(lf, rela, ELF_RELOC_RELA);
+ rela++;
+ }
+ }
+}
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 3e5224e..f15803f 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -116,6 +116,7 @@ static int link_elf_lookup_set(linker_file_t, const char *,
static int link_elf_each_function_name(linker_file_t,
int (*)(const char *, void *),
void *);
+static void link_elf_reloc_local(linker_file_t);
static kobj_method_t link_elf_methods[] = {
KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol),
@@ -488,6 +489,7 @@ link_elf_link_preload(linker_class_t cls,
linker_file_unload(lf);
return error;
}
+ link_elf_reloc_local(lf);
*result = lf;
return (0);
}
@@ -748,6 +750,8 @@ link_elf_load_file(linker_class_t cls, const char* filename,
error = parse_dynamic(ef);
if (error)
goto out;
+ link_elf_reloc_local(lf);
+
error = linker_load_dependencies(lf);
if (error)
goto out;
@@ -1266,3 +1270,31 @@ elf_lookup(linker_file_t lf, Elf_Word symidx, int deps)
return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
}
+
+static void
+link_elf_reloc_local(linker_file_t lf)
+{
+ const Elf_Rel *rellim;
+ const Elf_Rel *rel;
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
+ elf_file_t ef = (elf_file_t)lf;
+
+ /* Perform relocations without addend if there are any: */
+ if ((rel = ef->rel) != NULL) {
+ rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
+ while (rel < rellim) {
+ elf_reloc_local(lf, rel, ELF_RELOC_REL);
+ rel++;
+ }
+ }
+
+ /* Perform relocations with addend if there are any: */
+ if ((rela = ef->rela) != NULL) {
+ relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
+ while (rela < relalim) {
+ elf_reloc_local(lf, rela, ELF_RELOC_RELA);
+ rela++;
+ }
+ }
+}
diff --git a/sys/powerpc/powerpc/elf_machdep.c b/sys/powerpc/powerpc/elf_machdep.c
index e00c9d3..1621e1b 100644
--- a/sys/powerpc/powerpc/elf_machdep.c
+++ b/sys/powerpc/powerpc/elf_machdep.c
@@ -89,8 +89,8 @@ SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
&freebsd_brand_info);
/* Process one elf relocation with addend. */
-int
-elf_reloc(linker_file_t lf, const void *data, int type)
+static int
+elf_reloc_internal(linker_file_t lf, const void *data, int type, int local)
{
Elf_Addr relocbase = (Elf_Addr) lf->address;
Elf_Addr *where;
@@ -165,6 +165,20 @@ elf_reloc(linker_file_t lf, const void *data, int type)
}
int
+elf_reloc(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 0));
+}
+
+int
+elf_reloc_local(linker_file_t lf, const void *data, int type)
+{
+
+ return (elf_reloc_internal(lf, data, type, 1));
+}
+
+int
elf_cpu_load_file(linker_file_t lf __unused)
{
diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c
index 592be48..a14db6c 100644
--- a/sys/sparc64/sparc64/elf_machdep.c
+++ b/sys/sparc64/sparc64/elf_machdep.c
@@ -235,6 +235,28 @@ static long reloc_target_bitmask[] = {
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
+int
+elf_reloc_local(linker_file_t lf, const void *data, int type)
+{
+ const Elf_Rela *rela;
+ Elf_Addr value;
+ Elf_Addr *where;
+
+ if (type != ELF_RELOC_RELA)
+ return (-1);
+
+ rela = (const Elf_Rela *)data;
+ if (ELF_R_TYPE(rela->r_info) != R_SPARC_RELATIVE)
+ return (-1);
+
+ value = rela->r_addend + (Elf_Addr)lf->address;
+ where = (Elf_Addr *)((Elf_Addr)lf->address + rela->r_offset);
+
+ *where = value;
+
+ return (0);
+}
+
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, const void *data, int type)
@@ -258,7 +280,7 @@ elf_reloc(linker_file_t lf, const void *data, int type)
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
- if (rtype == R_SPARC_NONE)
+ if (rtype == R_SPARC_NONE || rtype == R_SPARC_RELATIVE)
return (0);
if (rtype == R_SPARC_JMP_SLOT || rtype == R_SPARC_COPY ||
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
index 5e0a760..a601e3a 100644
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -229,6 +229,7 @@ extern int kld_debug;
/* Support functions */
int elf_reloc(linker_file_t _lf, const void *_rel, int _type);
+int elf_reloc_local(linker_file_t _lf, const void *_rel, int _type);
Elf_Addr elf_lookup(linker_file_t, Elf_Word, int);
const Elf_Sym *elf_get_sym(linker_file_t _lf, Elf_Word _symidx);
const char *elf_get_symname(linker_file_t _lf, Elf_Word _symidx);
OpenPOWER on IntegriCloud