summaryrefslogtreecommitdiffstats
path: root/sys/kern/link_elf.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1998-10-12 09:13:50 +0000
committerpeter <peter@FreeBSD.org>1998-10-12 09:13:50 +0000
commitb7f5f657082f06a37beb13c5dfac0de3ea4fe7f5 (patch)
tree4e2c29bfe8baa4238c5a4aaa4cac362a3d1a7b7f /sys/kern/link_elf.c
parent8834a794bd6a3e6be0f694ad55ea6f9625626e58 (diff)
downloadFreeBSD-src-b7f5f657082f06a37beb13c5dfac0de3ea4fe7f5.zip
FreeBSD-src-b7f5f657082f06a37beb13c5dfac0de3ea4fe7f5.tar.gz
Only print kernel entry point during load.
Drastically quieten down the verbose load progress messages. They were more useful for debugging than anything, but are beyond a joke when loading a few dozen modules. Simplify the ELF extended symbol table load format. Just take the main symbol table and the string table that corresponds. This is what we will be getting local symbols from. (needed for the alpha stack tracebacks). Use the (optional) full symbol tables in lookups. This means we have to furhter distinguish between symbols that can come from the dynamic linking table and the complete table. The alpha boot code now needs to be adapted as ddb/db_elf.c cannot use the simpler format. I have not implemented loading the extended symbol tables from the syscall interface yet, just for preloaded modules. I am not sure about the symbol resolution. I *think* it's possible that a local symbol can be found in preference to a global, depending on the search sequence and dependency tree.
Diffstat (limited to 'sys/kern/link_elf.c')
-rw-r--r--sys/kern/link_elf.c129
1 files changed, 108 insertions, 21 deletions
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 2fbc3e7..1a1266b 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: link_elf.c,v 1.2 1998/09/11 08:46:15 dfr Exp $
+ * $Id: link_elf.c,v 1.3 1998/10/09 23:55:31 peter Exp $
*/
#include <sys/param.h>
@@ -94,6 +94,7 @@ typedef struct elf_file {
const Elf_Off* chains;
caddr_t hash;
caddr_t strtab; /* DT_STRTAB */
+ int strsz; /* DT_STRSZ */
const Elf_Sym* symtab; /* DT_SYMTAB */
Elf_Addr* got; /* DT_PLTGOT */
const Elf_Rel* pltrel; /* DT_JMPREL */
@@ -104,11 +105,17 @@ typedef struct elf_file {
int relsize; /* DT_RELSZ */
const Elf_Rela* rela; /* DT_RELA */
int relasize; /* DT_RELASZ */
+ caddr_t modptr;
+ const Elf_Sym* ddbsymtab; /* The symbol table we are using */
+ long ddbsymcnt; /* Number of symbols */
+ caddr_t ddbstrtab; /* String table */
+ long ddbstrcnt; /* number of bytes in string table */
} *elf_file_t;
static int parse_dynamic(linker_file_t lf);
static int load_dependancies(linker_file_t lf);
static int relocate_file(linker_file_t lf);
+static int parse_module_symbols(linker_file_t lf);
/*
* The kernel symbol table starts here.
@@ -162,6 +169,7 @@ link_elf_init(void* arg)
linker_kernel_file->size = -(long)linker_kernel_file->address;
if (modptr) {
+ ef->modptr = modptr;
baseptr = preload_search_info(modptr, MODINFO_ADDR);
if (baseptr)
linker_kernel_file->address = *(caddr_t *)baseptr;
@@ -169,6 +177,7 @@ link_elf_init(void* arg)
if (sizeptr)
linker_kernel_file->size = *(size_t *)sizeptr;
}
+ (void)parse_module_symbols(linker_kernel_file);
linker_current_file = linker_kernel_file;
}
#endif
@@ -177,6 +186,56 @@ link_elf_init(void* arg)
SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0);
static int
+parse_module_symbols(linker_file_t lf)
+{
+ elf_file_t ef = lf->priv;
+ caddr_t pointer;
+ caddr_t ssym, esym, base;
+ caddr_t strtab;
+ int strcnt;
+ Elf_Sym* symtab;
+ int symcnt;
+
+ pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM);
+ if (pointer == NULL)
+ return 0;
+ ssym = *(caddr_t *)pointer;
+ pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM);
+ if (pointer == NULL)
+ return 0;
+ esym = *(caddr_t *)pointer;
+
+ base = ssym;
+
+ symcnt = *(long *)base;
+ base += sizeof(long);
+ symtab = (Elf_Sym *)base;
+ base += roundup(symcnt, sizeof(long));
+
+ if (base > esym || base < ssym) {
+ printf("Symbols are corrupt!\n");
+ return EINVAL;
+ }
+
+ strcnt = *(long *)base;
+ base += sizeof(long);
+ strtab = base;
+ base += roundup(strcnt, sizeof(long));
+
+ if (base > esym || base < ssym) {
+ printf("Symbols are corrupt!\n");
+ return EINVAL;
+ }
+
+ ef->ddbsymtab = symtab;
+ ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
+ ef->ddbstrtab = strtab;
+ ef->ddbstrcnt = strcnt;
+
+ return 0;
+}
+
+static int
parse_dynamic(linker_file_t lf)
{
elf_file_t ef = lf->priv;
@@ -199,6 +258,9 @@ parse_dynamic(linker_file_t lf)
case DT_STRTAB:
ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr);
break;
+ case DT_STRSZ:
+ ef->strsz = dp->d_un.d_val;
+ break;
case DT_SYMTAB:
ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr);
break;
@@ -250,6 +312,11 @@ parse_dynamic(linker_file_t lf)
ef->pltrelsize = 0;
}
+ ef->ddbsymtab = ef->symtab;
+ ef->ddbsymcnt = ef->nchains;
+ ef->ddbstrtab = ef->strtab;
+ ef->ddbstrcnt = ef->strsz;
+
return 0;
}
@@ -306,8 +373,6 @@ link_elf_load_module(const char *filename, linker_file_t *result)
linker_file_unload(lf);
return error;
}
-
- /* Try to load dependencies */
error = load_dependancies(lf);
if (error) {
linker_file_unload(lf);
@@ -318,6 +383,7 @@ link_elf_load_module(const char *filename, linker_file_t *result)
linker_file_unload(lf);
return error;
}
+ (void)parse_module_symbols(lf);
*result = lf;
return (0);
}
@@ -548,7 +614,6 @@ link_elf_load_file(const char* filename, linker_file_t* result)
linker_file_unload(lf);
goto out;
}
-
error = load_dependancies(lf);
if (error) {
linker_file_unload(lf);
@@ -642,8 +707,8 @@ symbol_name(elf_file_t ef, const Elf_Rela *rela)
const Elf_Sym *ref;
if (ELF_R_SYM(rela->r_info)) {
- ref = ef->symtab + ELF_R_SYM(rela->r_info);
- return ef->strtab + ref->st_name;
+ ref = ef->ddbsymtab + ELF_R_SYM(rela->r_info);
+ return ef->ddbstrtab + ref->st_name;
} else
return NULL;
}
@@ -723,17 +788,16 @@ link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym)
{
elf_file_t ef = lf->priv;
unsigned long symnum;
- const Elf_Sym* es;
+ const Elf_Sym* symp;
+ const char *strp;
unsigned long hash;
int i;
+ /* First, search hashed global symbols */
hash = elf_hash(name);
symnum = ef->buckets[hash % ef->nbuckets];
while (symnum != STN_UNDEF) {
- const Elf_Sym *symp;
- const char *strp;
-
if (symnum >= ef->nchains) {
printf("link_elf_lookup_symbol: corrupt symbol table\n");
return ENOENT;
@@ -760,6 +824,24 @@ link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym)
symnum = ef->chains[symnum];
}
+ /* If we have not found it, look at the full table (if loaded) */
+ if (ef->symtab == ef->ddbsymtab)
+ return ENOENT;
+
+ /* Exhaustive search */
+ for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
+ strp = ef->ddbstrtab + symp->st_name;
+ if (strcmp(name, strp) == 0) {
+ if (symp->st_shndx != SHN_UNDEF ||
+ (symp->st_value != 0 &&
+ ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
+ *sym = (linker_sym_t) symp;
+ return 0;
+ } else
+ return ENOENT;
+ }
+ }
+
return ENOENT;
}
@@ -768,16 +850,22 @@ link_elf_symbol_values(linker_file_t lf, linker_sym_t sym, linker_symval_t* symv
{
elf_file_t ef = lf->priv;
Elf_Sym* es = (Elf_Sym*) sym;
- int symcount = ef->nchains;
- if (es < ef->symtab)
- return ENOENT;
- if ((es - ef->symtab) > symcount)
- return ENOENT;
- symval->name = ef->strtab + es->st_name;
- symval->value = (caddr_t) ef->address + es->st_value;
- symval->size = es->st_size;
- return 0;
+ 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;
+ symval->size = es->st_size;
+ return 0;
+ }
+ if (ef->symtab == ef->ddbsymtab)
+ 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;
+ symval->size = es->st_size;
+ return 0;
+ }
+ return ENOENT;
}
static int
@@ -787,12 +875,11 @@ link_elf_search_symbol(linker_file_t lf, caddr_t value,
elf_file_t ef = lf->priv;
u_long off = (u_long) value;
u_long diff = off;
- int symcount = ef->nchains;
const Elf_Sym* es;
const Elf_Sym* best = 0;
int i;
- for (i = 0, es = ef->symtab; i < symcount; i++, es++) {
+ for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) {
if (es->st_name == 0)
continue;
if (off >= es->st_value) {
OpenPOWER on IntegriCloud