summaryrefslogtreecommitdiffstats
path: root/sys/kern/link_elf_obj.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/link_elf_obj.c')
-rw-r--r--sys/kern/link_elf_obj.c129
1 files changed, 108 insertions, 21 deletions
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 2fbc3e7..1a1266b 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.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