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