From 0c79589d60d02f3c32a3a0e9e2577fa30988dba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 12 Jan 2003 16:59:18 +0000 Subject: [PATCH] First set of changes to have a BeOS compatible runtime loader. Added a simple locking strategy to the loader (didn't do any locking before), it now uses a global recursive lock for the exported API. Implemented all needed functionality for the BeOS image API. Now registers images with the kernel. Added several ToDo items. Cleanups, and possibly more I've forgotten about. (hope this works since the local diff does not?!) git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2436 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/apps/rld/rldelf.c | 692 +++++++++++++++++++++-------------- 1 file changed, 421 insertions(+), 271 deletions(-) diff --git a/src/kernel/apps/rld/rldelf.c b/src/kernel/apps/rld/rldelf.c index 816db304ed..6e0191e11d 100644 --- a/src/kernel/apps/rld/rldelf.c +++ b/src/kernel/apps/rld/rldelf.c @@ -1,6 +1,7 @@ /* -** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. ** Copyright 2002, Manuel J. Petit. All rights reserved. +** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ @@ -16,6 +17,11 @@ #include "rld_priv.h" +// ToDo: implement better locking strategy +// ToDo: implement unload_program() +// ToDo: implement load_addon()/unload_addon(): at the very least, we will have to make +// sure that B_ADD_ON_IMAGE is set correctly +// ToDo: implement search paths $LIBRARY_PATH, $ADDON_PATH #define PAGE_SIZE 4096 #define PAGE_MASK ((PAGE_SIZE)-1) @@ -28,66 +34,63 @@ enum { - RFLAG_RW = 0x0001, - RFLAG_ANON = 0x0002, + RFLAG_RW = 0x0001, + RFLAG_ANON = 0x0002, - RFLAG_SORTED = 0x0400, - RFLAG_SYMBOLIC = 0x0800, - RFLAG_RELOCATED = 0x1000, - RFLAG_PROTECTED = 0x2000, - RFLAG_INITIALIZED = 0x4000, - RFLAG_NEEDAGIRLFRIEND= 0x8000 + RFLAG_SORTED = 0x0400, + RFLAG_SYMBOLIC = 0x0800, + RFLAG_RELOCATED = 0x1000, + RFLAG_PROTECTED = 0x2000, + RFLAG_INITIALIZED = 0x4000, + RFLAG_NEEDAGIRLFRIEND = 0x8000 }; typedef struct elf_region_t { - region_id id; - addr start; - addr size; - addr vmstart; - addr vmsize; - addr fdstart; - addr fdsize; - long delta; - unsigned flags; + region_id id; + addr start; + addr size; + addr vmstart; + addr vmsize; + addr fdstart; + addr fdsize; + long delta; + uint32 flags; } elf_region_t; -typedef -struct image_t { - /* - * image identification - */ - char name[SYS_MAX_OS_NAME_LEN]; - dynmodule_id imageid; +typedef struct image_t { + // image identification + char name[SYS_MAX_OS_NAME_LEN]; + image_id id; + image_type type; - struct image_t *next; - struct image_t *prev; - int refcount; - unsigned flags; - - addr entry_point; - addr dynamic_ptr; // pointer to the dynamic section + struct image_t *next; + struct image_t *prev; + int32 ref_count; + uint32 flags; + addr entry_point; + addr dynamic_ptr; // pointer to the dynamic section // pointer to symbol participation data structures - unsigned int *symhash; - struct Elf32_Sym *syms; - char *strtab; - struct Elf32_Rel *rel; - int rel_len; - struct Elf32_Rela *rela; - int rela_len; - struct Elf32_Rel *pltrel; - int pltrel_len; + uint32 *symhash; + struct Elf32_Sym *syms; + char *strtab; + struct Elf32_Rel *rel; + int rel_len; + struct Elf32_Rela *rela; + int rela_len; + struct Elf32_Rel *pltrel; + int pltrel_len; - unsigned num_needed; - struct image_t **needed; + uint32 num_needed; + struct image_t **needed; // describes the text and data regions - unsigned num_regions; - elf_region_t regions[1]; + uint32 num_regions; + elf_region_t regions[1]; } image_t; @@ -98,14 +101,17 @@ struct image_queue_t { } image_queue_t; -static image_queue_t loaded_images = { 0, 0 }; -static image_queue_t loading_images = { 0, 0 }; -static image_queue_t disposable_images = { 0, 0 }; -static unsigned loaded_image_count = 0; -static unsigned imageid_count = 0; +static image_queue_t gLoadedImages = {0, 0}; +static image_queue_t gLoadingImages = {0, 0}; +static image_queue_t gDisposableImages = {0, 0}; +static uint32 gLoadedImageCount = 0; +// a recursive lock static sem_id rld_sem; -static struct uspace_prog_args_t const *uspa; +static thread_id rld_sem_owner; +static int32 rld_sem_count; + +static struct uspace_program_args const *gProgramArgs; #define STRING(image, offset) ((char *)(&(image)->strtab[(offset)])) @@ -126,47 +132,66 @@ static struct uspace_prog_args_t const *uspa; } +static void +rld_unlock() +{ + if (rld_sem_count-- == 1) { + rld_sem_owner = -1; + release_sem(rld_sem); + } +} + static void -enqueue_image(image_queue_t *queue, image_t *img) +rld_lock() { - img->next = 0; + thread_id self = sys_get_current_thread_id(); + if (self != rld_sem_owner) { + acquire_sem(rld_sem); + rld_sem_owner = self; + } + rld_sem_count++; +} - img->prev = queue->tail; + +static void +enqueue_image(image_queue_t *queue, image_t *image) +{ + image->next = 0; + + image->prev = queue->tail; if (queue->tail) - queue->tail->next= img; + queue->tail->next = image; - queue->tail = img; + queue->tail = image; if (!queue->head) - queue->head= img; + queue->head = image; } static void -dequeue_image(image_queue_t *queue, image_t *img) +dequeue_image(image_queue_t *queue, image_t *image) { - if(img->next) { - img->next->prev= img->prev; - } else { - queue->tail= img->prev; - } + if (image->next) + image->next->prev = image->prev; + else + queue->tail = image->prev; - if(img->prev) { - img->prev->next= img->next; - } else { - queue->head= img->next; - } + if (image->prev) + image->prev->next = image->next; + else + queue->head = image->next; - img->prev= 0; - img->next= 0; + image->prev = 0; + image->next = 0; } -static unsigned long -elf_hash(const unsigned char *name) +static uint32 +elf_hash(const uchar *name) { - unsigned long hash = 0; - unsigned long temp; + uint32 hash = 0; + uint32 temp; while (*name) { hash = (hash << 4) + *name++; @@ -184,12 +209,12 @@ find_image(char const *name) { image_t *iter; - for (iter = loaded_images.head; iter; iter = iter->next) { + for (iter = gLoadedImages.head; iter; iter = iter->next) { if (strncmp(iter->name, name, sizeof(iter->name)) == 0) return iter; } - for (iter = loading_images.head; iter; iter = iter->next) { + for (iter = gLoadingImages.head; iter; iter = iter->next) { if (strncmp(iter->name, name, sizeof(iter->name)) == 0) return iter; } @@ -198,8 +223,22 @@ find_image(char const *name) } -static int -parse_eheader(struct Elf32_Ehdr *eheader) +static image_t * +find_loaded_image_by_id(image_id id) +{ + image_t *image; + + for (image = gLoadedImages.head; image; image = image->next) { + if (image->id == id) + return image; + } + + return NULL; +} + + +static status_t +parse_elf_header(struct Elf32_Ehdr *eheader, int32 *_pheaderSize, int32 *_sheaderSize) { if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) return ERR_INVALID_BINARY; @@ -213,7 +252,10 @@ parse_eheader(struct Elf32_Ehdr *eheader) if (eheader->e_phentsize < sizeof(struct Elf32_Phdr)) return ERR_INVALID_BINARY; - return eheader->e_phentsize*eheader->e_phnum; + *_pheaderSize = eheader->e_phentsize * eheader->e_phnum; + *_sheaderSize = eheader->e_shentsize * eheader->e_shnum; + + return *_pheaderSize > 0 && *_sheaderSize > 0 ? B_OK : ERR_INVALID_BINARY; } @@ -279,37 +321,34 @@ count_regions(char const *buff, int phnum, int phentsize) static image_t * create_image(char const *name, int num_regions) { - image_t *retval; - size_t alloc_size; + size_t allocSize; + image_t *image; - alloc_size = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t); + allocSize = sizeof(image_t) + (num_regions - 1) * sizeof(elf_region_t); - retval = rldalloc(alloc_size); + image = rldalloc(allocSize); + memset(image, 0, allocSize); - memset(retval, 0, alloc_size); + strlcpy(image->name, name, sizeof(image->name)); + image->ref_count = 1; + image->num_regions = num_regions; - strlcpy(retval->name, name, sizeof(retval->name)); - retval->imageid = imageid_count; - retval->refcount = 1; - retval->num_regions = num_regions; - - imageid_count += 1; - - return retval; + return image; } static void -destroy_image(image_t *image) +delete_image(image_t *image) { - size_t alloc_size; + size_t size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t); - alloc_size = sizeof(image_t) + (image->num_regions - 1) * sizeof(elf_region_t); + sys_unregister_image(image->id); + // registered in load_container() - memset(image->needed, 0xa5, sizeof(image->needed[0])*image->num_needed); + memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed); rldfree(image->needed); - memset(image, 0xa5, alloc_size); + memset(image, 0xa5, size); rldfree(image); } @@ -317,81 +356,83 @@ destroy_image(image_t *image) static void parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) { - int i; + struct Elf32_Phdr *pheader; int regcount; - struct Elf32_Phdr *pheaders; + int i; regcount = 0; for (i = 0; i < phnum; i++) { - pheaders = (struct Elf32_Phdr *)(buff + i * phentsize); + pheader = (struct Elf32_Phdr *)(buff + i * phentsize); - switch (pheaders->p_type) { + switch (pheader->p_type) { case PT_NULL: /* NOP header */ break; case PT_LOAD: - if (pheaders->p_memsz== pheaders->p_filesz) { + if (pheader->p_memsz == pheader->p_filesz) { /* * everything in one area */ - image->regions[regcount].start = pheaders->p_vaddr; - image->regions[regcount].size = pheaders->p_memsz; - image->regions[regcount].vmstart= _ROUNDOWN(pheaders->p_vaddr, PAGE_SIZE); - image->regions[regcount].vmsize = _ROUNDUP (pheaders->p_memsz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE); - image->regions[regcount].fdstart= pheaders->p_offset; - image->regions[regcount].fdsize = pheaders->p_filesz; - image->regions[regcount].delta= 0; - image->regions[regcount].flags= 0; - if(pheaders->p_flags & PF_W) { + image->regions[regcount].start = pheader->p_vaddr; + image->regions[regcount].size = pheader->p_memsz; + image->regions[regcount].vmstart = _ROUNDOWN(pheader->p_vaddr, PAGE_SIZE); + image->regions[regcount].vmsize = _ROUNDUP(pheader->p_memsz + + (pheader->p_vaddr % PAGE_SIZE), PAGE_SIZE); + image->regions[regcount].fdstart = pheader->p_offset; + image->regions[regcount].fdsize = pheader->p_filesz; + image->regions[regcount].delta = 0; + image->regions[regcount].flags = 0; + if (pheader->p_flags & PF_W) { // this is a writable segment - image->regions[regcount].flags|= RFLAG_RW; + image->regions[regcount].flags |= RFLAG_RW; } } else { /* * may require splitting */ - unsigned A = pheaders->p_vaddr + pheaders->p_memsz; - unsigned B = pheaders->p_vaddr + pheaders->p_filesz - 1; + unsigned A = pheader->p_vaddr + pheader->p_memsz; + unsigned B = pheader->p_vaddr + pheader->p_filesz - 1; A = PAGE_BASE(A); B = PAGE_BASE(B); - image->regions[regcount].start = pheaders->p_vaddr; - image->regions[regcount].size = pheaders->p_filesz; - image->regions[regcount].vmstart = _ROUNDOWN(pheaders->p_vaddr, PAGE_SIZE); - image->regions[regcount].vmsize = _ROUNDUP (pheaders->p_filesz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE); - image->regions[regcount].fdstart = pheaders->p_offset; - image->regions[regcount].fdsize = pheaders->p_filesz; + image->regions[regcount].start = pheader->p_vaddr; + image->regions[regcount].size = pheader->p_filesz; + image->regions[regcount].vmstart = _ROUNDOWN(pheader->p_vaddr, PAGE_SIZE); + image->regions[regcount].vmsize = _ROUNDUP (pheader->p_filesz + + (pheader->p_vaddr % PAGE_SIZE), PAGE_SIZE); + image->regions[regcount].fdstart = pheader->p_offset; + image->regions[regcount].fdsize = pheader->p_filesz; image->regions[regcount].delta = 0; image->regions[regcount].flags = 0; - if (pheaders->p_flags & PF_W) { + if (pheader->p_flags & PF_W) { // this is a writable segment - image->regions[regcount].flags|= RFLAG_RW; + image->regions[regcount].flags |= RFLAG_RW; } - if (A!= B) { + if (A != B) { /* * yeah, it requires splitting */ regcount += 1; - image->regions[regcount].start = pheaders->p_vaddr; - image->regions[regcount].size = pheaders->p_memsz - pheaders->p_filesz; + image->regions[regcount].start = pheader->p_vaddr; + image->regions[regcount].size = pheader->p_memsz - pheader->p_filesz; image->regions[regcount].vmstart = image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize; - image->regions[regcount].vmsize = _ROUNDUP (pheaders->p_memsz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE) - image->regions[regcount-1].vmsize; + image->regions[regcount].vmsize = _ROUNDUP (pheader->p_memsz + (pheader->p_vaddr % PAGE_SIZE), PAGE_SIZE) - image->regions[regcount-1].vmsize; image->regions[regcount].fdstart = 0; image->regions[regcount].fdsize = 0; image->regions[regcount].delta = 0; image->regions[regcount].flags = RFLAG_ANON; - if (pheaders->p_flags & PF_W) { + if (pheader->p_flags & PF_W) { // this is a writable segment - image->regions[regcount].flags|= RFLAG_RW; + image->regions[regcount].flags |= RFLAG_RW; } } } regcount += 1; break; case PT_DYNAMIC: - image->dynamic_ptr = pheaders->p_vaddr; + image->dynamic_ptr = pheader->p_vaddr; break; case PT_INTERP: /* should check here for appropiate interpreter */ @@ -406,7 +447,7 @@ parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) /* we don't use it */ break; default: - FATAL(true, "unhandled pheader type 0x%lx\n", pheaders[i].p_type); + FATAL(true, "unhandled pheader type 0x%lx\n", pheader[i].p_type); break; } } @@ -475,8 +516,7 @@ map_image(int fd, char const *path, image_t *image, bool fixed) addr_specifier, image->regions[i].vmsize, REGION_WIRING_LAZY, - LOCK_RW - ); + LOCK_RW); if (image->regions[i].id < 0) goto error; @@ -492,8 +532,8 @@ map_image(int fd, char const *path, image_t *image, bool fixed) LOCK_RW, REGION_PRIVATE_MAP, path, - _ROUNDOWN(image->regions[i].fdstart, PAGE_SIZE) - ); + _ROUNDOWN(image->regions[i].fdstart, PAGE_SIZE)); + if (image->regions[i].id < 0) goto error; @@ -561,7 +601,7 @@ parse_dynamic_segment(image_t *image) image->num_needed += 1; break; case DT_HASH: - image->symhash = (unsigned int *)(d[i].d_un.d_ptr + image->regions[0].delta); + image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->regions[0].delta); break; case DT_STRTAB: image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta); @@ -602,21 +642,32 @@ parse_dynamic_segment(image_t *image) static struct Elf32_Sym * -find_symbol_xxx(image_t *img, const char *name) +find_symbol(image_t *image, const char *name, int32 type) { - unsigned int hash; - unsigned int i; + uint32 hash, i; - if (img->dynamic_ptr == NULL) + // ToDo: "type" is currently ignored! + (void)type; + + if (image->dynamic_ptr == NULL) return NULL; - hash = elf_hash(name) % HASHTABSIZE(img); + hash = elf_hash(name) % HASHTABSIZE(image); - for (i = HASHBUCKETS(img)[hash]; i != STN_UNDEF; i = HASHCHAINS(img)[i]) { - if (img->syms[i].st_shndx != SHN_UNDEF - && ((ELF32_ST_BIND(img->syms[i].st_info)== STB_GLOBAL) || (ELF32_ST_BIND(img->syms[i].st_info) == STB_WEAK)) - && !strcmp(SYMNAME(img, &img->syms[i]), name)) - return &img->syms[i]; + for (i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) { + struct Elf32_Sym *symbol = &image->syms[i]; + + if (symbol->st_shndx != SHN_UNDEF + && ((ELF32_ST_BIND(symbol->st_info)== STB_GLOBAL) + || (ELF32_ST_BIND(symbol->st_info) == STB_WEAK)) + && !strcmp(SYMNAME(image, symbol), name)) { + // check if the type matches + if ((type == B_SYMBOL_TYPE_TEXT && ELF32_ST_TYPE(symbol->st_info) != STT_FUNC) + || (type == B_SYMBOL_TYPE_DATA && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT)) + continue; + + return symbol; + } } return NULL; @@ -624,25 +675,20 @@ find_symbol_xxx(image_t *img, const char *name) static struct Elf32_Sym * -find_symbol(image_t **shimg, const char *name) +find_symbol_in_loaded_images(image_t **_image, const char *name) { - image_t *iter; - unsigned int hash; - unsigned int i; + image_t *image; - for (iter = loaded_images.head; iter; iter = iter->next) { - if (iter->dynamic_ptr == NULL) + for (image = gLoadedImages.head; image; image = image->next) { + struct Elf32_Sym *symbol; + + if (image->dynamic_ptr == NULL) continue; - hash = elf_hash(name) % HASHTABSIZE(iter); - - for(i = HASHBUCKETS(iter)[hash]; i != STN_UNDEF; i = HASHCHAINS(iter)[i]) { - if (iter->syms[i].st_shndx!= SHN_UNDEF - && ((ELF32_ST_BIND(iter->syms[i].st_info)== STB_GLOBAL) || (ELF32_ST_BIND(iter->syms[i].st_info)== STB_WEAK)) - && !strcmp(SYMNAME(iter, &iter->syms[i]), name)) { - *shimg = iter; - return &iter->syms[i]; - } + symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY); + if (symbol) { + *_image = image; + return symbol; } } @@ -660,10 +706,10 @@ resolve_symbol(image_t *image, struct Elf32_Sym *sym, addr *sym_addr) switch (sym->st_shndx) { case SHN_UNDEF: // patch the symbol name - symname= SYMNAME(image, sym); + symname = SYMNAME(image, sym); // it's undefined, must be outside this image, try the other image - sym2 = find_symbol(&shimg, symname); + sym2 = find_symbol_in_loaded_images(&shimg, symname); if (!sym2) { printf("elf_resolve_symbol: could not resolve symbol '%s'\n", symname); return ERR_ELF_RESOLVING_SYMBOL; @@ -705,24 +751,48 @@ resolve_symbol(image_t *image, struct Elf32_Sym *sym, addr *sym_addr) #include "arch/rldreloc.inc" -static image_t * -load_container(char const *path, char const *name, bool fixed) +static void +register_image(image_t *image, const char *path) { - int fd; - int len; - int ph_len; - char ph_buff[4096]; - int num_regions; - bool map_success; - bool dynamic_success; + image_info info; + + // ToDo: set these correctly + info.id = 0; + info.type = image->type; + info.sequence = 0; + info.init_order = 0; + info.init_routine = (void *)image->entry_point; + info.term_routine = (void *)image->entry_point; + info.device = 0; + info.node = 0; + strlcpy(info.name, path, sizeof(info.name)); + info.text = NULL; + info.text_size = 0; + info.data = NULL; + info.data_size = 0; + image->id = sys_register_image(&info, sizeof(image_info)); +} + + +static image_t * +load_container(char const *path, char const *name, image_type type) +{ + int32 pheaderSize, sheaderSize; + int fd; + int len; + char ph_buff[4096]; + int num_regions; + bool map_success; + bool dynamic_success; image_t *found; image_t *image; struct Elf32_Ehdr eheader; + // have we already loaded that image? found = find_image(name); if (found) { - found->refcount += 1; + atomic_add(&found->ref_count, 1); return found; } @@ -732,12 +802,14 @@ load_container(char const *path, char const *name, bool fixed) len = sys_read(fd, 0, &eheader, sizeof(eheader)); FATAL((len != sizeof(eheader)), "troubles reading ELF header\n"); - ph_len = parse_eheader(&eheader); - FATAL((ph_len <= 0), "incorrect ELF header\n"); - FATAL((ph_len > (int)sizeof(ph_buff)), "cannot handle Program headers bigger than %lu\n", (long unsigned)sizeof(ph_buff)); + if (parse_elf_header(&eheader, &pheaderSize, &sheaderSize) < B_OK) { + FATAL(1, "incorrect ELF header\n"); + } + // ToDo: what to do about this restriction?? + FATAL((pheaderSize > (int)sizeof(ph_buff)), "cannot handle Program headers bigger than %lu\n", (long unsigned)sizeof(ph_buff)); - len = sys_read(fd, eheader.e_phoff, ph_buff, ph_len); - FATAL((len != ph_len), "troubles reading Program headers\n"); + len = sys_read(fd, eheader.e_phoff, ph_buff, pheaderSize); + FATAL((len != pheaderSize), "troubles reading Program headers\n"); num_regions = count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize); FATAL((num_regions <= 0), "troubles parsing Program headers, num_regions= %d\n", num_regions); @@ -748,47 +820,46 @@ load_container(char const *path, char const *name, bool fixed) parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize); FATAL(!assert_dynamic_loadable(image), "dynamic segment must be loadable (implementation restriction)\n"); - map_success = map_image(fd, path, image, fixed); + map_success = map_image(fd, path, image, type == B_APP_IMAGE); FATAL(!map_success, "troubles reading image\n"); dynamic_success = parse_dynamic_segment(image); FATAL(!dynamic_success, "troubles handling dynamic section\n"); image->entry_point = eheader.e_entry + image->regions[0].delta; + image->type = type; + register_image(image, path); sys_close(fd); - enqueue_image(&loaded_images, image); + enqueue_image(&gLoadedImages, image); return image; } static void -load_dependencies(image_t *img) +load_dependencies(image_t *image) { - unsigned i; - unsigned j; - - struct Elf32_Dyn *d; + struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; addr needed_offset; char path[256]; + uint32 i, j; - d = (struct Elf32_Dyn *)img->dynamic_ptr; if (!d) return; - img->needed = rldalloc(img->num_needed*sizeof(image_t*)); - FATAL((!img->needed), "failed to allocate needed struct\n"); - memset(img->needed, 0, img->num_needed*sizeof(image_t*)); + image->needed = rldalloc(image->num_needed * sizeof(image_t *)); + FATAL((!image->needed), "failed to allocate needed struct\n"); + memset(image->needed, 0, image->num_needed * sizeof(image_t *)); for (i = 0, j = 0; d[i].d_tag != DT_NULL; i++) { - switch(d[i].d_tag) { + switch (d[i].d_tag) { case DT_NEEDED: needed_offset = d[i].d_un.d_ptr; - sprintf(path, "/boot/lib/%s", STRING(img, needed_offset)); - img->needed[j]= load_container(path, STRING(img, needed_offset), false); - j+= 1; + sprintf(path, "/boot/lib/%s", STRING(image, needed_offset)); + image->needed[j] = load_container(path, STRING(image, needed_offset), B_LIBRARY_IMAGE); + j += 1; break; default: @@ -799,81 +870,84 @@ load_dependencies(image_t *img) } } - FATAL((j!= img->num_needed), "Internal error at load_dependencies()"); + FATAL((j != image->num_needed), "Internal error at load_dependencies()"); return; } -static unsigned -topological_sort(image_t *img, unsigned slot, image_t **init_list) +static uint32 +topological_sort(image_t *image, uint32 slot, image_t **initList) { - unsigned i; + uint32 i; - img->flags|= RFLAG_SORTED; /* make sure we don't visit this one */ - for(i= 0; i< img->num_needed; i++) { - if(!(img->needed[i]->flags & RFLAG_SORTED)) { - slot= topological_sort(img->needed[i], slot, init_list); - } + image->flags |= RFLAG_SORTED; /* make sure we don't visit this one */ + for (i = 0; i < image->num_needed; i++) { + if (!(image->needed[i]->flags & RFLAG_SORTED)) + slot = topological_sort(image->needed[i], slot, initList); } - init_list[slot]= img; - return slot+1; + initList[slot] = image; + return slot + 1; } static void -init_dependencies(image_t *img, bool init_head) +init_dependencies(image_t *image, bool initHead) { unsigned i; unsigned slot; - image_t **init_list; + image_t **initList; - init_list = rldalloc(loaded_image_count*sizeof(image_t*)); - FATAL((!init_list), "memory shortage in init_dependencies()"); - memset(init_list, 0, loaded_image_count*sizeof(image_t*)); + initList = rldalloc(gLoadedImageCount * sizeof(image_t *)); + FATAL((!initList), "memory shortage in init_dependencies()"); + memset(initList, 0, gLoadedImageCount * sizeof(image_t *)); - img->flags |= RFLAG_SORTED; /* make sure we don't visit this one */ + image->flags |= RFLAG_SORTED; /* make sure we don't visit this one */ slot = 0; - for (i = 0; i < img->num_needed; i++) { - if (!(img->needed[i]->flags & RFLAG_SORTED)) - slot = topological_sort(img->needed[i], slot, init_list); + for (i = 0; i < image->num_needed; i++) { + if (!(image->needed[i]->flags & RFLAG_SORTED)) + slot = topological_sort(image->needed[i], slot, initList); } - if (init_head) { - init_list[slot] = img; + if (initHead) { + initList[slot] = image; slot += 1; } for (i = 0; i < slot; i++) { - addr _initf = init_list[i]->entry_point; + addr _initf = initList[i]->entry_point; libinit_f *initf = (libinit_f *)(_initf); if (initf) - initf(init_list[i]->imageid, uspa); + initf(initList[i]->id, gProgramArgs); } - rldfree(init_list); + rldfree(initList); } static void -put_image(image_t *img) +put_image(image_t *image) { - img->refcount -= 1; - if (img->refcount == 0) { + // If all references to the image are gone, add it to the disposable list + // and remove all dependencies + + if (atomic_add(&image->ref_count, -1) == 1) { size_t i; - dequeue_image(&loaded_images, img); - enqueue_image(&disposable_images, img); + dequeue_image(&gLoadedImages, image); + enqueue_image(&gDisposableImages, image); - for(i = 0; i < img->num_needed; i++) { - put_image(img->needed[i]); + for (i = 0; i < image->num_needed; i++) { + put_image(image->needed[i]); } } } +// #pragma mark - + /* * exported functions: * @@ -886,131 +960,207 @@ put_image(image_t *img) * + dynamic_symbol() */ -dynmodule_id -load_program(char const *path, void **entry) +image_id +load_program(char const *path, void **_entry) { image_t *image; image_t *iter; - image = load_container(path, NEWOS_MAGIC_APPNAME, true); + rld_lock(); + // for now, just do stupid simple global locking - for (iter = loaded_images.head; iter; iter = iter->next) { + image = load_container(path, MAGIC_APP_NAME, B_APP_IMAGE); + + for (iter = gLoadedImages.head; iter; iter = iter->next) { load_dependencies(iter); } - for (iter = loaded_images.head; iter; iter = iter->next) { + for (iter = gLoadedImages.head; iter; iter = iter->next) { bool relocate_success; relocate_success = relocate_image(iter); FATAL(!relocate_success, "troubles relocating\n"); } - init_dependencies(loaded_images.head, false); + init_dependencies(gLoadedImages.head, false); - *entry = (void*)(image->entry_point); - return image->imageid; + *_entry = (void *)(image->entry_point); + + rld_unlock(); + return image->id; } -dynmodule_id -load_library(char const *path) +image_id +load_library(char const *path, uint32 flags) { image_t *image; image_t *iter; + // ToDo: implement flags + (void)flags; + + rld_lock(); + // for now, just do stupid simple global locking + + // have we already loaded this library? + // Checking it at this stage saves loading its dependencies again + // ToDo: don't we have to increment the reference counter of the dependencies?? image = find_image(path); if (image) { - image->refcount += 1; - return image->imageid; + atomic_add(&image->ref_count, 1); + rld_unlock(); + return image->id; } - image = load_container(path, path, false); + image = load_container(path, path, B_LIBRARY_IMAGE); - for (iter = loaded_images.head; iter; iter = iter->next) { + for (iter = gLoadedImages.head; iter; iter = iter->next) { load_dependencies(iter); } - for (iter = loaded_images.head; iter; iter = iter->next) { - bool relocate_success; + for (iter = gLoadedImages.head; iter; iter = iter->next) { + bool relocateSuccess; - relocate_success = relocate_image(iter); - FATAL(!relocate_success, "troubles relocating\n"); + relocateSuccess = relocate_image(iter); + FATAL(!relocateSuccess, "troubles relocating\n"); } init_dependencies(image, true); - return image->imageid; + rld_unlock(); + return image->id; } -dynmodule_id -unload_library(dynmodule_id imid) +status_t +unload_library(image_id imageID) { int retval; image_t *iter; + rld_lock(); + // for now, just do stupid simple global locking + /* * we only check images that have been already initialized */ - for (iter = loaded_images.head; iter; iter = iter->next) { - if (iter->imageid == imid) { + for (iter = gLoadedImages.head; iter; iter = iter->next) { + if (iter->id == imageID) { /* * do the unloading */ put_image(iter); - break; } } - retval = iter ? 0 : -1; + retval = iter ? B_OK : -1; - while ((iter = disposable_images.head) != NULL) { + while ((iter = gDisposableImages.head) != NULL) { // call image fini here... - dequeue_image(&disposable_images, iter); + dequeue_image(&gDisposableImages, iter); unmap_image(iter); - destroy_image(iter); + delete_image(iter); } + rld_unlock(); return retval; } -void * -dynamic_symbol(dynmodule_id imid, char const *symname) +status_t +get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, int32 *_nameLength, + int32 *_type, void **_location) { - image_t *iter; + int32 count = 0, i, j; + image_t *image; - /* - * we only check images that have been already initialized - */ - for (iter = loaded_images.head; iter; iter = iter->next) { - struct Elf32_Sym *sym; + rld_lock(); - if (iter->imageid != imid) - continue; - - sym = find_symbol_xxx(iter, symname); - if (sym) - return (void*)(sym->st_value + iter->regions[0].delta); + // get the image from those who have been already initialized + image = find_loaded_image_by_id(imageID); + if (image == NULL) { + rld_unlock(); + return B_BAD_IMAGE_ID; } - return NULL; + // iterate through all the hash buckets until we've found the one + for (i = 0; i < HASHTABSIZE(image); i++) { + for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { + struct Elf32_Sym *symbol = &image->syms[i]; + + if (count == num) { + strlcpy(nameBuffer, SYMNAME(image, symbol), *_nameLength); + *_nameLength = strlen(SYMNAME(image, symbol)); + + // ToDo: check with the return types of that BeOS function + if (ELF32_ST_TYPE(symbol->st_info) == STT_FUNC) + *_type = B_SYMBOL_TYPE_TEXT; + else if (ELF32_ST_TYPE(symbol->st_info) == STT_OBJECT) + *_type = B_SYMBOL_TYPE_DATA; + else + *_type = B_SYMBOL_TYPE_ANY; + + *_location = (void *)(symbol->st_value + image->regions[0].delta); + goto out; + } + count++; + } + } +out: + rld_unlock(); + + if (num != count) + return B_BAD_INDEX; + + return B_OK; } +status_t +get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_location) +{ + status_t status = B_OK; + image_t *image; + + rld_lock(); + // for now, just do stupid simple global locking + + // get the image from those who have been already initialized + image = find_loaded_image_by_id(imageID); + if (image != NULL) { + struct Elf32_Sym *symbol; + + // get the symbol in the image + symbol = find_symbol(image, symbolName, symbolType); + if (symbol) + *_location = (void *)(symbol->st_value + image->regions[0].delta); + else + status = B_ENTRY_NOT_FOUND; + } else + status = B_BAD_IMAGE_ID; + + rld_unlock(); + return status; +} + + +// #pragma mark - + /* - * init routine, just get hold of the uspa args + * init routine, just get hold of the user-space program args */ void -rldelf_init(struct uspace_prog_args_t const *_uspa) +rldelf_init(struct uspace_program_args const *_args) { - uspa = _uspa; + gProgramArgs = _args; rld_sem = create_sem(1, "rld_lock\n"); + rld_sem_owner = -1; + rld_sem_count = 0; } -