diff --git a/sys/ld/elf.c b/sys/ld/elf.c index 353d2eb..77b7677 100644 --- a/sys/ld/elf.c +++ b/sys/ld/elf.c @@ -1,5 +1,7 @@ #include "elf.h" +#include "image-list.h" +#include "ld.h" #include "resolve.h" #include @@ -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; } diff --git a/sys/ld/elf.h b/sys/ld/elf.h index 13045a5..77eab23 100644 --- a/sys/ld/elf.h +++ b/sys/ld/elf.h @@ -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 diff --git a/sys/ld/ld.h b/sys/ld/ld.h new file mode 100644 index 0000000..c7b38a5 --- /dev/null +++ b/sys/ld/ld.h @@ -0,0 +1,8 @@ +#ifndef LD_H_ +#define LD_H_ + +struct image_list; + +extern struct image_list *global_image_list(void); + +#endif diff --git a/sys/ld/main.c b/sys/ld/main.c index a98185f..753ee9e 100644 --- a/sys/ld/main.c +++ b/sys/ld/main.c @@ -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); } diff --git a/sys/ld/resolve.c b/sys/ld/resolve.c index c106ee3..41b7db2 100644 --- a/sys/ld/resolve.c +++ b/sys/ld/resolve.c @@ -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;