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.
This commit is contained in:
parent
55820fca35
commit
2d636ab077
@ -24,7 +24,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: load_elf.c,v 1.2 1998/10/02 08:04:56 peter Exp $
|
||||
* $Id: load_elf.c,v 1.3 1998/10/09 23:18:43 peter Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -155,7 +155,8 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
|
||||
mp->m_name = strdup(filename);
|
||||
mp->m_type = strdup(kernel ? elf_kerneltype : elf_moduletype);
|
||||
|
||||
printf("%s entry at %p\n", filename, (void *) dest);
|
||||
if (kernel)
|
||||
printf("%s entry at %p\n", filename, (void *) dest);
|
||||
|
||||
mp->m_size = elf_loadimage(mp, fd, dest, &ehdr, kernel);
|
||||
if (mp->m_size == 0 || mp->m_addr == 0)
|
||||
@ -189,15 +190,12 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
|
||||
int i, j;
|
||||
Elf_Phdr *phdr;
|
||||
Elf_Shdr *shdr;
|
||||
Elf_Ehdr local_ehdr;
|
||||
int ret;
|
||||
vm_offset_t firstaddr;
|
||||
vm_offset_t lastaddr;
|
||||
void *buf;
|
||||
size_t resid, chunk;
|
||||
vm_offset_t dest;
|
||||
char *secname;
|
||||
vm_offset_t shdrpos;
|
||||
vm_offset_t ssym, esym;
|
||||
Elf_Dyn *dp;
|
||||
int ndp;
|
||||
@ -207,6 +205,9 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
|
||||
int len;
|
||||
char *strtab;
|
||||
size_t strsz;
|
||||
int symstrindex;
|
||||
int symtabindex;
|
||||
long size;
|
||||
|
||||
dp = NULL;
|
||||
shdr = NULL;
|
||||
@ -239,10 +240,17 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
|
||||
if (phdr[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
#ifdef ELF_VERBOSE
|
||||
printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
|
||||
(long)phdr[i].p_filesz, (long)phdr[i].p_offset,
|
||||
(long)(phdr[i].p_vaddr + off),
|
||||
(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
|
||||
#else
|
||||
if ((phdr[i].p_flags & PF_W) == 0)
|
||||
printf(" text=0x%lx", (long)phdr[i].p_filesz);
|
||||
else
|
||||
printf(" data=0x%lx", (long)phdr[i].p_filesz);
|
||||
#endif
|
||||
|
||||
if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) {
|
||||
printf("\nelf_loadexec: cannot seek\n");
|
||||
@ -255,9 +263,13 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
|
||||
}
|
||||
/* clear space from oversized segments; eg: bss */
|
||||
if (phdr[i].p_filesz < phdr[i].p_memsz) {
|
||||
#ifdef ELF_VERBOSE
|
||||
printf(" (bss: 0x%lx-0x%lx)",
|
||||
(long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
|
||||
(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
|
||||
#else
|
||||
printf(" bss=0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
|
||||
#endif
|
||||
|
||||
/* no archsw.arch_bzero */
|
||||
buf = malloc(PAGE_SIZE);
|
||||
@ -272,79 +284,40 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
#ifdef ELF_VERBOSE
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
|
||||
firstaddr = phdr[i].p_vaddr + off;
|
||||
if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
|
||||
lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
|
||||
}
|
||||
lastaddr = roundup(lastaddr, sizeof(long));
|
||||
|
||||
/*
|
||||
* Now grab the symbol tables. This isn't easy if we're reading a
|
||||
* .gz file. I think the rule is going to have to be that you must
|
||||
* strip a file to remove symbols before gzipping it so that we do not
|
||||
* try to lseek() on it. The layout is a bit wierd, but it's what
|
||||
* the NetBSD-derived ddb/db_elf.c wants.
|
||||
* try to lseek() on it.
|
||||
*/
|
||||
lastaddr = roundup(lastaddr, sizeof(long));
|
||||
chunk = ehdr->e_shnum * ehdr->e_shentsize;
|
||||
shdr = malloc(chunk);
|
||||
if (shdr == NULL)
|
||||
goto nosyms;
|
||||
ssym = lastaddr;
|
||||
printf("Symbols: ELF Ehdr @ 0x%x; ", lastaddr);
|
||||
lastaddr += sizeof(*ehdr);
|
||||
lastaddr = roundup(lastaddr, sizeof(long));
|
||||
/* Copy out executable header modified for base offsets */
|
||||
local_ehdr = *ehdr;
|
||||
local_ehdr.e_phoff = 0;
|
||||
local_ehdr.e_phentsize = 0;
|
||||
local_ehdr.e_phnum = 0;
|
||||
local_ehdr.e_shoff = lastaddr - ssym;
|
||||
archsw.arch_copyin(&local_ehdr, ssym, sizeof(*ehdr));
|
||||
if (lseek(fd, ehdr->e_shoff, SEEK_SET) == -1) {
|
||||
printf("elf_loadimage: cannot lseek() to section headers\n");
|
||||
lastaddr = ssym; /* wind back */
|
||||
ssym = 0;
|
||||
printf("\nelf_loadimage: cannot lseek() to section headers\n");
|
||||
goto nosyms;
|
||||
}
|
||||
if (read(fd, shdr, chunk) != chunk) {
|
||||
printf("elf_loadimage: read section headers failed\n");
|
||||
lastaddr = ssym; /* wind back */
|
||||
ssym = 0;
|
||||
printf("\nelf_loadimage: read section headers failed\n");
|
||||
goto nosyms;
|
||||
}
|
||||
shdrpos = lastaddr;
|
||||
printf("Section table: 0x%x@0x%x\n", chunk, shdrpos);
|
||||
lastaddr += chunk;
|
||||
lastaddr = roundup(lastaddr, sizeof(long));
|
||||
symtabindex = -1;
|
||||
symstrindex = -1;
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
/* Explicitly skip string table for section names */
|
||||
if (i == ehdr->e_shstrndx)
|
||||
if (shdr[i].sh_type != SHT_SYMTAB)
|
||||
continue;
|
||||
switch(shdr[i].sh_type) {
|
||||
/*
|
||||
* These are the symbol tables. Their names are relative to
|
||||
* an arbitary string table.
|
||||
*/
|
||||
case SHT_SYMTAB: /* Symbol table */
|
||||
secname = "symtab";
|
||||
break;
|
||||
case SHT_DYNSYM: /* Dynamic linking symbol table */
|
||||
secname = "dynsym";
|
||||
break;
|
||||
/*
|
||||
* And here are the string tables. These can be referred to from
|
||||
* a number of sources, including the dynsym, the section table
|
||||
* names itself, etc.
|
||||
*/
|
||||
case SHT_STRTAB: /* String table */
|
||||
secname = "strtab";
|
||||
break;
|
||||
default: /* Skip it */
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < ehdr->e_phnum; j++) {
|
||||
if (phdr[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
@ -358,31 +331,72 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off,
|
||||
}
|
||||
if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
|
||||
continue; /* alread loaded in a PT_LOAD above */
|
||||
/* Save it for loading below */
|
||||
symtabindex = i;
|
||||
symstrindex = shdr[i].sh_link;
|
||||
}
|
||||
if (symtabindex < 0 || symstrindex < 0)
|
||||
goto nosyms;
|
||||
|
||||
/* Ok, committed to a load. */
|
||||
#ifndef ELF_VERBOSE
|
||||
printf(" symbols=[");
|
||||
#endif
|
||||
ssym = lastaddr;
|
||||
for (i = symtabindex; i >= 0; i = symstrindex) {
|
||||
#ifdef ELF_VERBOSE
|
||||
char *secname;
|
||||
|
||||
switch(shdr[i].sh_type) {
|
||||
case SHT_SYMTAB: /* Symbol table */
|
||||
secname = "symtab";
|
||||
break;
|
||||
case SHT_STRTAB: /* String table */
|
||||
secname = "strtab";
|
||||
break;
|
||||
default:
|
||||
secname = "WHOA!!";
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
size = shdr[i].sh_size;
|
||||
archsw.arch_copyin(&size, lastaddr, sizeof(size));
|
||||
lastaddr += sizeof(long);
|
||||
|
||||
#ifdef ELF_VERBOSE
|
||||
printf("%s: 0x%x@0x%x -> 0x%x-0x%x\n", secname,
|
||||
shdr[i].sh_size, shdr[i].sh_offset,
|
||||
lastaddr, lastaddr + shdr[i].sh_size);
|
||||
|
||||
#else
|
||||
printf("0x%x+0x%lx", sizeof(size), size);
|
||||
#endif
|
||||
|
||||
if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) {
|
||||
printf("\nelf_loadimage: could not seek for symbols - skipped!\n");
|
||||
shdr[i].sh_offset = 0;
|
||||
shdr[i].sh_size = 0;
|
||||
continue;
|
||||
lastaddr = ssym;
|
||||
ssym = 0;
|
||||
goto nosyms;
|
||||
}
|
||||
if (archsw.arch_readin(fd, lastaddr, shdr[i].sh_size) !=
|
||||
shdr[i].sh_size) {
|
||||
printf("\nelf_loadimage: could not read symbols - skipped!\n");
|
||||
shdr[i].sh_offset = 0;
|
||||
shdr[i].sh_size = 0;
|
||||
continue;
|
||||
lastaddr = ssym;
|
||||
ssym = 0;
|
||||
goto nosyms;
|
||||
}
|
||||
/* Reset offsets relative to ssym */
|
||||
shdr[i].sh_offset = lastaddr - ssym;
|
||||
lastaddr += shdr[i].sh_size;
|
||||
lastaddr = roundup(lastaddr, sizeof(long));
|
||||
if (i == symtabindex)
|
||||
symtabindex = -1;
|
||||
else if (i == symstrindex)
|
||||
symstrindex = -1;
|
||||
}
|
||||
archsw.arch_copyin(shdr, lastaddr, sizeof(*ehdr));
|
||||
esym = lastaddr;
|
||||
#ifndef ELF_VERBOSE
|
||||
printf("]\n");
|
||||
#endif
|
||||
|
||||
mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
|
||||
mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym);
|
||||
|
@ -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
|
||||
@ -176,6 +185,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)
|
||||
{
|
||||
@ -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) {
|
||||
|
@ -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
|
||||
@ -176,6 +185,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)
|
||||
{
|
||||
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user