summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/link_elf_obj.c42
-rw-r--r--sys/sys/elf_common.h3
2 files changed, 43 insertions, 2 deletions
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 0334779..4f40258 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -173,6 +173,7 @@ static struct linker_class link_elf_class = {
};
static int relocate_file(elf_file_t ef);
+static void elf_obj_cleanup_globals_cache(elf_file_t);
static void
link_elf_error(const char *filename, const char *s)
@@ -1046,6 +1047,13 @@ relocate_file(elf_file_t ef)
}
}
+ /*
+ * Only clean SHN_FBSD_CACHED for successfull return. If we
+ * modified symbol table for the object but found an
+ * unresolved symbol, there is no reason to roll back.
+ */
+ elf_obj_cleanup_globals_cache(ef);
+
return 0;
}
@@ -1194,6 +1202,21 @@ link_elf_each_function_nameval(linker_file_t file,
return (0);
}
+static void
+elf_obj_cleanup_globals_cache(elf_file_t ef)
+{
+ Elf_Sym *sym;
+ Elf_Size i;
+
+ for (i = 0; i < ef->ddbsymcnt; i++) {
+ sym = ef->ddbsymtab + i;
+ if (sym->st_shndx == SHN_FBSD_CACHED) {
+ sym->st_shndx = SHN_UNDEF;
+ sym->st_value = 0;
+ }
+ }
+}
+
/*
* Symbol lookup function that can be used when the symbol index is known (ie
* in relocations). It uses the symbol index instead of doing a fully fledged
@@ -1205,7 +1228,7 @@ static Elf_Addr
elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps)
{
elf_file_t ef = (elf_file_t)lf;
- const Elf_Sym *sym;
+ Elf_Sym *sym;
const char *symbol;
Elf_Addr ret;
@@ -1233,7 +1256,22 @@ elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps)
if (*symbol == 0)
return (0);
ret = ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
- return ret;
+
+ /*
+ * Cache global lookups during module relocation. The failure
+ * case is particularly expensive for callers, who must scan
+ * through the entire globals table doing strcmp(). Cache to
+ * avoid doing such work repeatedly.
+ *
+ * After relocation is complete, undefined globals will be
+ * restored to SHN_UNDEF in elf_obj_cleanup_globals_cache(),
+ * above.
+ */
+ if (ret != 0) {
+ sym->st_shndx = SHN_FBSD_CACHED;
+ sym->st_value = ret;
+ }
+ return (ret);
case STB_WEAK:
printf("link_elf_obj: Weak symbols not supported\n");
diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h
index 2a29dd4..44f9996 100644
--- a/sys/sys/elf_common.h
+++ b/sys/sys/elf_common.h
@@ -251,6 +251,9 @@ typedef struct {
#define SHN_LOPROC 0xff00 /* First processor-specific. */
#define SHN_HIPROC 0xff1f /* Last processor-specific. */
#define SHN_LOOS 0xff20 /* First operating system-specific. */
+#define SHN_FBSD_CACHED SHN_LOOS /* Transient, for sys/kern/link_elf_obj
+ linker only: Cached global in local
+ symtab. */
#define SHN_HIOS 0xff3f /* Last operating system-specific. */
#define SHN_ABS 0xfff1 /* Absolute values. */
#define SHN_COMMON 0xfff2 /* Common data. */
OpenPOWER on IntegriCloud