ld: resolve: search all images for symbols, rather than just direct links
This commit is contained in:
195
sys/ld/elf.c
195
sys/ld/elf.c
@@ -1,5 +1,7 @@
|
||||
#include "elf.h"
|
||||
|
||||
#include "image-list.h"
|
||||
#include "ld.h"
|
||||
#include "resolve.h"
|
||||
|
||||
#include <errno.h>
|
||||
@@ -181,6 +183,7 @@ static int map_image(struct elf_image *image)
|
||||
}
|
||||
}
|
||||
|
||||
kern_logf("ld: image %s -> %zx", image->e_leaf.l_name, image->e_base);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -297,7 +300,7 @@ static int do_rela(struct elf_image *image, elf_rela_t *rela, bool lazy)
|
||||
rela->r_addend);
|
||||
break;
|
||||
default:
|
||||
kern_log("Unknown relocation type");
|
||||
kern_trace("Unknown relocation type");
|
||||
return ENOEXEC;
|
||||
}
|
||||
|
||||
@@ -644,7 +647,7 @@ int elf_image_link(struct elf_image *img)
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
extern int elf_image_collect_dependencies(
|
||||
int elf_image_collect_dependencies(
|
||||
struct elf_image *img,
|
||||
struct image_list *dest)
|
||||
{
|
||||
@@ -652,6 +655,7 @@ extern int elf_image_collect_dependencies(
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
kern_tracef("collecting dependencies for %s", img->e_leaf.l_name);
|
||||
int nr_added = 0;
|
||||
img->e_links = calloc(img->e_nr_links, sizeof(struct elf_image *));
|
||||
|
||||
@@ -663,24 +667,45 @@ extern int elf_image_collect_dependencies(
|
||||
const char *name = (const char *)img->e_base + img->e_strtab
|
||||
+ img->e_dyn[i].d_un.d_val;
|
||||
|
||||
if (image_list_get(dest, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct elf_image *dep = NULL;
|
||||
int status = create_image_with_name(name, &dep);
|
||||
if (status != SUCCESS) {
|
||||
return -status;
|
||||
struct image_list_leaf *leaf = NULL;
|
||||
if ((leaf = image_list_get(dest, name))) {
|
||||
dep = QUEUE_CONTAINER(struct elf_image, e_leaf, leaf);
|
||||
} else {
|
||||
int status = create_image_with_name(name, &dep);
|
||||
if (status != SUCCESS) {
|
||||
return -status;
|
||||
}
|
||||
|
||||
image_list_put(dest, &dep->e_leaf);
|
||||
}
|
||||
|
||||
image_list_put(dest, &dep->e_leaf);
|
||||
img->e_links[nr_added] = dep;
|
||||
kern_tracef(
|
||||
"%s dependency %u = %s",
|
||||
img->e_leaf.l_name,
|
||||
nr_added,
|
||||
dep->e_leaf.l_name);
|
||||
nr_added++;
|
||||
}
|
||||
|
||||
return nr_added;
|
||||
}
|
||||
|
||||
int elf_image_add_dependency(struct elf_image *img, struct elf_image *dep)
|
||||
{
|
||||
struct elf_image **deps = realloc(
|
||||
img->e_links,
|
||||
sizeof(struct elf_image *) * img->e_nr_links + 1);
|
||||
if (!deps) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
deps[img->e_nr_links++] = dep;
|
||||
img->e_links = deps;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void elf_image_close(struct elf_image *image)
|
||||
{
|
||||
if (image->e_fd) {
|
||||
@@ -714,7 +739,7 @@ static uint32_t gnu_hash(const char *name)
|
||||
return h;
|
||||
}
|
||||
|
||||
static virt_addr_t find_symbol_stdhash(
|
||||
static const elf_sym_t *find_symbol_stdhash(
|
||||
struct elf_image *img,
|
||||
const char *name,
|
||||
uint32_t hash)
|
||||
@@ -733,15 +758,22 @@ static virt_addr_t find_symbol_stdhash(
|
||||
const uint32_t *chain = &bucket[nbucket];
|
||||
|
||||
for (uint32_t i = bucket[hash % nbucket]; i; i = chain[i]) {
|
||||
if (strcmp(name, strtab + symtab[i].st_name) == 0) {
|
||||
return img->e_base + symtab[i].st_value;
|
||||
const elf_sym_t *sym = &symtab[i];
|
||||
if (strcmp(name, strtab + sym->st_name) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sym->st_value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static virt_addr_t find_symbol_gnuhash(
|
||||
static const elf_sym_t *find_symbol_gnuhash(
|
||||
struct elf_image *img,
|
||||
const char *name,
|
||||
uint32_t hash)
|
||||
@@ -749,12 +781,14 @@ static virt_addr_t find_symbol_gnuhash(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static virt_addr_t find_symbol_slow(struct elf_image *img, const char *name)
|
||||
static const elf_sym_t *find_symbol_slow(
|
||||
struct elf_image *img,
|
||||
const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static virt_addr_t find_symbol(
|
||||
static const elf_sym_t *find_symbol(
|
||||
struct elf_image *img,
|
||||
const char *name,
|
||||
uint32_t std_hash,
|
||||
@@ -770,31 +804,144 @@ static virt_addr_t find_symbol(
|
||||
}
|
||||
}
|
||||
|
||||
virt_addr_t elf_image_find_symbol(struct elf_image *img, const char *name)
|
||||
int elf_image_find_symbol(
|
||||
struct elf_image *img,
|
||||
const char *name,
|
||||
struct elf_symbol *out)
|
||||
{
|
||||
uint32_t std_hash_val = std_hash(name);
|
||||
uint32_t gnu_hash_val = gnu_hash(name);
|
||||
return find_symbol(img, name, std_hash_val, gnu_hash_val);
|
||||
const elf_sym_t *sym
|
||||
= find_symbol(img, name, std_hash_val, gnu_hash_val);
|
||||
|
||||
if (sym) {
|
||||
out->sym_container = img;
|
||||
out->sym_info = sym;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
virt_addr_t elf_image_find_linked_symbol(
|
||||
int elf_image_find_linked_symbol(
|
||||
struct elf_image *img,
|
||||
const char *name)
|
||||
const char *name,
|
||||
struct elf_symbol *out)
|
||||
{
|
||||
uint32_t std_hash_val = std_hash(name);
|
||||
uint32_t gnu_hash_val = gnu_hash(name);
|
||||
|
||||
virt_addr_t sym = 0;
|
||||
struct elf_image *candidate_container = NULL;
|
||||
const elf_sym_t *candidate = NULL;
|
||||
const elf_sym_t *sym = NULL;
|
||||
|
||||
kern_tracef("searching %p (%zx)", img, img->e_base);
|
||||
sym = find_symbol(img, name, std_hash_val, gnu_hash_val);
|
||||
if (sym) {
|
||||
if (ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
|
||||
kern_tracef(
|
||||
"found %s:%s (weak): %zx",
|
||||
img->e_leaf.l_name,
|
||||
name,
|
||||
sym->st_value);
|
||||
candidate = sym;
|
||||
candidate_container = img;
|
||||
} else {
|
||||
kern_tracef(
|
||||
"found %s:%s (strong): %zx",
|
||||
img->e_leaf.l_name,
|
||||
name,
|
||||
sym->st_value);
|
||||
out->sym_container = img;
|
||||
out->sym_info = sym;
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < img->e_nr_links; i++) {
|
||||
kern_tracef(
|
||||
"searching %p (%zx)",
|
||||
img->e_links[i],
|
||||
img->e_links[i]->e_base);
|
||||
sym = find_symbol(
|
||||
img->e_links[i],
|
||||
name,
|
||||
std_hash_val,
|
||||
gnu_hash_val);
|
||||
if (sym) {
|
||||
break;
|
||||
if (!sym) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
|
||||
kern_tracef(
|
||||
"found %s:%s (weak): %zx",
|
||||
img->e_links[i]->e_leaf.l_name,
|
||||
name,
|
||||
sym->st_value);
|
||||
candidate = sym;
|
||||
candidate_container = img->e_links[i];
|
||||
} else {
|
||||
kern_tracef(
|
||||
"found %s:%s (strong): %zx",
|
||||
img->e_links[i]->e_leaf.l_name,
|
||||
name,
|
||||
sym->st_value);
|
||||
out->sym_container = img;
|
||||
out->sym_info = sym;
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return sym;
|
||||
if (candidate) {
|
||||
out->sym_container = candidate_container;
|
||||
out->sym_info = candidate;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
virt_addr_t find_global_symbol(const char *name)
|
||||
{
|
||||
struct image_list *images = global_image_list();
|
||||
if (!images) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct image_list_iterator it;
|
||||
image_list_iterator_begin(&it, images);
|
||||
|
||||
virt_addr_t candidate = 0;
|
||||
struct elf_symbol sym = {0};
|
||||
while (it.it_leaf) {
|
||||
struct elf_image *image
|
||||
= QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
|
||||
int status = elf_image_find_symbol(image, name, &sym);
|
||||
if (status == ENOENT) {
|
||||
image_list_iterator_move_next(&it);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ELF64_ST_BIND(sym.sym_info->st_info) == STB_WEAK) {
|
||||
kern_tracef(
|
||||
"found %s:%s (weak): %zx",
|
||||
sym.sym_container->e_leaf.l_name,
|
||||
name,
|
||||
sym.sym_info->st_value);
|
||||
candidate = (virt_addr_t)sym.sym_container->e_base
|
||||
+ sym.sym_info->st_value;
|
||||
} else {
|
||||
kern_tracef(
|
||||
"found %s:%s (strong): %zx",
|
||||
sym.sym_container->e_leaf.l_name,
|
||||
name,
|
||||
sym.sym_info->st_value);
|
||||
return (virt_addr_t)sym.sym_container->e_base
|
||||
+ sym.sym_info->st_value;
|
||||
}
|
||||
|
||||
image_list_iterator_move_next(&it);
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user