ld: resolve: search all images for symbols, rather than just direct links

This commit is contained in:
2026-03-22 19:05:47 +00:00
parent 44cd6c551a
commit 3e0fdb616c
5 changed files with 251 additions and 47 deletions

View File

@@ -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;
}

View File

@@ -344,6 +344,11 @@ struct elf_image {
size_t e_nr_links;
};
struct elf_symbol {
struct elf_image *sym_container;
const elf_sym_t *sym_info;
};
extern const char *elf_image_status_to_string(enum elf_image_status status);
extern int elf_image_open(const char *path, struct elf_image **out);
@@ -352,14 +357,25 @@ extern int elf_image_load(struct elf_image *img);
extern int elf_image_collect_dependencies(
struct elf_image *img,
struct image_list *dest);
extern int elf_image_add_dependency(
struct elf_image *img,
struct elf_image *dep);
extern int elf_image_link(struct elf_image *img);
extern void elf_image_close(struct elf_image *img);
extern virt_addr_t elf_image_find_symbol(
extern int elf_image_find_symbol(
struct elf_image *img,
const char *name);
extern virt_addr_t elf_image_find_linked_symbol(
const char *name,
struct elf_symbol *out);
extern int elf_image_find_symbol(
struct elf_image *img,
const char *name);
const char *name,
struct elf_symbol *out);
extern int elf_image_find_linked_symbol(
struct elf_image *img,
const char *name,
struct elf_symbol *out);
extern virt_addr_t find_global_symbol(const char *name);
#endif

8
sys/ld/ld.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef LD_H_
#define LD_H_
struct image_list;
extern struct image_list *global_image_list(void);
#endif

View File

@@ -27,6 +27,13 @@ static const char *search_paths[] = {
static const size_t nr_search_paths
= sizeof search_paths / sizeof search_paths[0];
static struct image_list images = {0};
struct image_list *global_image_list(void)
{
return &images;
}
static void report_error(const char *name, int err, const char *msg, ...)
{
char buf[1024];
@@ -35,7 +42,7 @@ static void report_error(const char *name, int err, const char *msg, ...)
vsnprintf(buf, sizeof buf, msg, arg);
va_end(arg);
kern_tracef("%s: %s: %s", name, buf, strerror(err));
kern_logf("%s: %s: %s", name, buf, strerror(err));
}
static const char *get_image_name(const char *path)
@@ -71,7 +78,7 @@ static int find_image(struct elf_image *img)
return ENOENT;
}
static int load_images(struct image_list *list)
static int load_images(const char *task_name, struct image_list *list)
{
int status = SUCCESS;
struct image_list_iterator it;
@@ -91,18 +98,33 @@ static int load_images(struct image_list *list)
/* Find the image using its name */
status = find_image(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
case ELF_IMAGE_OPEN:
/* parse the image */
status = elf_image_parse(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
case ELF_IMAGE_PARSED:
/* load the image */
status = elf_image_load(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
case ELF_IMAGE_LOADED:
@@ -114,6 +136,11 @@ static int load_images(struct image_list *list)
}
if (new_dependencies < 0) {
report_error(
task_name,
-new_dependencies,
"error while loading %s",
image->e_leaf.l_name);
return -new_dependencies;
}
@@ -127,7 +154,7 @@ static int load_images(struct image_list *list)
return SUCCESS;
}
static int link_images(struct image_list *list)
static int link_images(const char *task_name, struct image_list *list)
{
int status = SUCCESS;
struct image_list_iterator it;
@@ -143,6 +170,14 @@ static int link_images(struct image_list *list)
elf_image_status_to_string(image->e_status));
status = elf_image_link(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
image_list_iterator_move_next(&it);
}
@@ -162,7 +197,6 @@ int main(const struct rosetta_bootstrap *bs)
const char *task_name = bs->bs_argv[2];
const char *image_name = get_image_name(exec_path);
struct image_list images;
image_list_init(&images);
struct elf_image *exec = NULL;
@@ -183,23 +217,13 @@ int main(const struct rosetta_bootstrap *bs)
image_name);
image_list_put(&images, &exec->e_leaf);
err = load_images(&images);
err = load_images(task_name, &images);
if (err != SUCCESS) {
report_error(
task_name,
err,
"error while loading %s",
exec_path);
return -1;
}
err = link_images(&images);
err = link_images(task_name, &images);
if (err != SUCCESS) {
report_error(
task_name,
err,
"error while loading %s",
exec_path);
return -1;
}
@@ -218,7 +242,12 @@ int main(const struct rosetta_bootstrap *bs)
}
kern_tracef("ld finished");
int (*entry)(int, const char **)
= (int (*)(int, const char **))exec->e_entry;
return entry(bs->bs_argc - 2, bs->bs_argv + 2);
struct rosetta_bootstrap exec_bsinfo;
memcpy(&exec_bsinfo, bs, sizeof exec_bsinfo);
exec_bsinfo.bs_argc -= 2;
exec_bsinfo.bs_argv += 2;
int (*entry)(const struct rosetta_bootstrap *)
= (int (*)(const struct rosetta_bootstrap *))exec->e_entry;
return entry(&exec_bsinfo);
}

View File

@@ -39,7 +39,11 @@ uintptr_t dl_runtime_resolve(struct elf_image *img, unsigned long sym_id)
img->e_leaf.l_name,
sym_id,
sym_name);
#if 0
virt_addr_t sym_addr = elf_image_find_linked_symbol(img, sym_name);
#else
virt_addr_t sym_addr = find_global_symbol(sym_name);
#endif
kern_tracef("symbol %s = %zx", sym_name, sym_addr);
kern_tracef("slot %s = %zx", sym_name, &got[slot_id]);
got[slot_id] = sym_addr;