Fixed rare bug in the user space loader where it would decide to create an extra
[newos.git] / apps / rld / rldelf.c
blob9a717271e95beaa885a9c378ff69222806dcc45a
1 /*
2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Copyright 2002, Manuel J. Petit. All rights reserved.
4 ** Distributed under the terms of the NewOS License.
5 */
7 #include <string.h>
8 #include <stdio.h>
9 #include <newos/errors.h>
10 #include <newos/elf32.h>
11 #include <newos/user_runtime.h>
12 #include <sys/syscalls.h>
13 #include <arch/cpu.h>
15 #include "rld_priv.h"
17 #if ARCH_sh4
18 #define ELF_PREPEND_UNDERSCORE 1
19 #endif
21 #ifndef ELF_PREPEND_UNDERSCORE
22 #define ELF_PREPEND_UNDERSCORE 0
23 #endif
25 #define PAGE_MASK ((PAGE_SIZE)-1)
26 #define PAGE_OFFS(y) ((y)&(PAGE_MASK))
27 #define PAGE_BASE(y) ((y)&~(PAGE_MASK))
29 #define ROUNDOWN(x,y) ((x)&~((y)-1))
30 #define ROUNDUP(x,y) ROUNDOWN(x+y-1,y)
33 enum {
34 RFLAG_RW = 0x0001,
35 RFLAG_ANON = 0x0002,
37 RFLAG_SORTED = 0x0400,
38 RFLAG_SYMBOLIC = 0x0800,
39 RFLAG_RELOCATED = 0x1000,
40 RFLAG_PROTECTED = 0x2000,
41 RFLAG_INITIALIZED = 0x4000,
42 RFLAG_NEEDAGIRLFRIEND= 0x8000
46 typedef
47 struct elf_region_t {
48 region_id id;
49 addr_t start;
50 addr_t size;
51 addr_t vmstart;
52 addr_t vmsize;
53 addr_t fdstart;
54 addr_t fdsize;
55 long delta;
56 unsigned flags;
57 } elf_region_t;
60 typedef
61 struct image_t {
63 * image identification
65 char name[SYS_MAX_OS_NAME_LEN];
66 dynmodule_id imageid;
68 struct image_t *next;
69 struct image_t *prev;
70 int refcount;
71 unsigned flags;
73 addr_t entry_point;
74 addr_t dynamic_ptr; // pointer to the dynamic section
77 // pointer to symbol participation data structures
78 unsigned int *symhash;
79 struct Elf32_Sym *syms;
80 char *strtab;
81 struct Elf32_Rel *rel;
82 int rel_len;
83 struct Elf32_Rela *rela;
84 int rela_len;
85 struct Elf32_Rel *pltrel;
86 int pltrel_len;
87 int pltrel_type; // DT_REL or DT_RELA
89 unsigned num_needed;
90 struct image_t **needed;
92 // describes the text and data regions
93 unsigned num_regions;
94 elf_region_t regions[1];
95 } image_t;
98 typedef
99 struct image_queue_t {
100 image_t *head;
101 image_t *tail;
102 } image_queue_t;
105 static image_queue_t loaded_images= { 0, 0 };
106 static image_queue_t loading_images= { 0, 0 };
107 static image_queue_t disposable_images= { 0, 0 };
108 static unsigned loaded_image_count= 0;
109 static unsigned imageid_count= 0;
111 static sem_id rld_sem;
112 static struct uspace_prog_args_t const *uspa;
115 #define STRING(image, offset) ((char *)(&(image)->strtab[(offset)]))
116 #define SYMNAME(image, sym) STRING(image, (sym)->st_name)
117 #define SYMBOL(image, num) ((struct Elf32_Sym *)&(image)->syms[num])
118 #define HASHTABSIZE(image) ((image)->symhash[0])
119 #define HASHBUCKETS(image) ((unsigned int *)&(image)->symhash[2])
120 #define HASHCHAINS(image) ((unsigned int *)&(image)->symhash[2+HASHTABSIZE(image)])
124 * This macro is non ISO compliant, but a gcc extension
126 #define FATAL(x,y...) \
127 if(x) { \
128 printf("rld.so: " y); \
129 _kern_exit(0); \
134 static
135 void
136 enqueue_image(image_queue_t *queue, image_t *img)
138 img->next= 0;
140 img->prev= queue->tail;
141 if(queue->tail) {
142 queue->tail->next= img;
144 queue->tail= img;
145 if(!queue->head) {
146 queue->head= img;
150 static
151 void
152 dequeue_image(image_queue_t *queue, image_t *img)
154 if(img->next) {
155 img->next->prev= img->prev;
156 } else {
157 queue->tail= img->prev;
160 if(img->prev) {
161 img->prev->next= img->next;
162 } else {
163 queue->head= img->next;
166 img->prev= 0;
167 img->next= 0;
170 static
171 unsigned long
172 elf_hash(const unsigned char *name)
174 unsigned long hash = 0;
175 unsigned long temp;
177 while(*name) {
178 hash = (hash << 4) + *name++;
179 if((temp = hash & 0xf0000000)) {
180 hash ^= temp >> 24;
182 hash &= ~temp;
184 return hash;
187 static
188 image_t *
189 find_image(char const *name)
191 image_t *iter;
193 iter= loaded_images.head;
194 while(iter) {
195 if(strncmp(iter->name, name, sizeof(iter->name)) == 0) {
196 return iter;
198 iter= iter->next;
201 iter= loading_images.head;
202 while(iter) {
203 if(strncmp(iter->name, name, sizeof(iter->name)) == 0) {
204 return iter;
206 iter= iter->next;
209 return 0;
212 static
214 parse_eheader(struct Elf32_Ehdr *eheader)
216 if(memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
217 return ERR_INVALID_BINARY;
219 if(eheader->e_ident[4] != ELFCLASS32)
220 return ERR_INVALID_BINARY;
222 if(eheader->e_phoff == 0)
223 return ERR_INVALID_BINARY;
225 if(eheader->e_phentsize < sizeof(struct Elf32_Phdr))
226 return ERR_INVALID_BINARY;
228 return eheader->e_phentsize*eheader->e_phnum;
231 static
233 count_regions(char const *buff, int phnum, int phentsize)
235 int i;
236 int retval;
237 struct Elf32_Phdr *pheaders;
239 retval= 0;
240 for(i= 0; i< phnum; i++) {
241 pheaders= (struct Elf32_Phdr *)(buff+i*phentsize);
243 switch(pheaders->p_type) {
244 case PT_NULL:
245 /* NOP header */
246 break;
247 case PT_LOAD:
248 retval+= 1;
249 if(pheaders->p_memsz!= pheaders->p_filesz) {
250 unsigned A= pheaders->p_vaddr+pheaders->p_memsz-1;
251 unsigned B= pheaders->p_vaddr+pheaders->p_filesz-1;
253 A= PAGE_BASE(A);
254 B= PAGE_BASE(B);
256 if(A!= B) {
257 retval+= 1;
260 break;
261 case PT_DYNAMIC:
262 /* will be handled at some other place */
263 break;
264 case PT_INTERP:
265 /* should check here for appropiate interpreter */
266 break;
267 case PT_NOTE:
268 /* unsupported */
269 break;
270 case PT_SHLIB:
271 /* undefined semantics */
272 break;
273 case PT_PHDR:
274 /* we don't use it */
275 break;
276 default:
277 FATAL(true, "unhandled pheader type 0x%x\n", pheaders[i].p_type);
278 break;
282 return retval;
288 * create_image() & destroy_image()
290 * Create and destroy image_t structures. The destroyer makes sure that the
291 * memory buffers are full of garbage before freeing.
293 static
294 image_t *
295 create_image(char const *name, int num_regions)
297 image_t *retval;
298 size_t alloc_size;
300 alloc_size= sizeof(image_t)+(num_regions-1)*sizeof(elf_region_t);
302 retval= rldalloc(alloc_size);
304 memset(retval, 0, alloc_size);
306 strlcpy(retval->name, name, sizeof(retval->name));
307 retval->imageid= imageid_count;
308 retval->refcount= 1;
309 retval->num_regions= num_regions;
311 imageid_count+= 1;
313 return retval;
316 static
317 void
318 destroy_image(image_t *image)
320 size_t alloc_size;
322 alloc_size= sizeof(image_t)+(image->num_regions-1)*sizeof(elf_region_t);
324 memset(image->needed, 0xa5, sizeof(image->needed[0])*image->num_needed);
325 rldfree(image->needed);
327 memset(image, 0xa5, alloc_size);
328 rldfree(image);
333 static
334 void
335 parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
337 int i;
338 int regcount;
339 struct Elf32_Phdr *pheaders;
341 regcount= 0;
342 for(i= 0; i< phnum; i++) {
343 pheaders= (struct Elf32_Phdr *)(buff+i*phentsize);
345 switch(pheaders->p_type) {
346 case PT_NULL:
347 /* NOP header */
348 break;
349 case PT_LOAD:
350 if(pheaders->p_memsz== pheaders->p_filesz) {
352 * everything in one area
354 image->regions[regcount].start = pheaders->p_vaddr;
355 image->regions[regcount].size = pheaders->p_memsz;
356 image->regions[regcount].vmstart= ROUNDOWN(pheaders->p_vaddr, PAGE_SIZE);
357 image->regions[regcount].vmsize = ROUNDUP (pheaders->p_memsz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE);
358 image->regions[regcount].fdstart= pheaders->p_offset;
359 image->regions[regcount].fdsize = pheaders->p_filesz;
360 image->regions[regcount].delta= 0;
361 image->regions[regcount].flags= 0;
362 if(pheaders->p_flags & PF_W) {
363 // this is a writable segment
364 image->regions[regcount].flags|= RFLAG_RW;
366 } else {
368 * may require splitting
370 unsigned A= pheaders->p_vaddr+pheaders->p_memsz-1;
371 unsigned B= pheaders->p_vaddr+pheaders->p_filesz-1;
373 A= PAGE_BASE(A);
374 B= PAGE_BASE(B);
376 image->regions[regcount].start = pheaders->p_vaddr;
377 image->regions[regcount].size = pheaders->p_filesz;
378 image->regions[regcount].vmstart= ROUNDOWN(pheaders->p_vaddr, PAGE_SIZE);
379 image->regions[regcount].vmsize = ROUNDUP (pheaders->p_filesz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE);
380 image->regions[regcount].fdstart= pheaders->p_offset;
381 image->regions[regcount].fdsize = pheaders->p_filesz;
382 image->regions[regcount].delta= 0;
383 image->regions[regcount].flags= 0;
384 if(pheaders->p_flags & PF_W) {
385 // this is a writable segment
386 image->regions[regcount].flags|= RFLAG_RW;
389 if(A!= B) {
391 * yeah, it requires splitting
393 regcount+= 1;
394 image->regions[regcount].start = pheaders->p_vaddr;
395 image->regions[regcount].size = pheaders->p_memsz - pheaders->p_filesz;
396 image->regions[regcount].vmstart= image->regions[regcount-1].vmstart + image->regions[regcount-1].vmsize;
397 image->regions[regcount].vmsize = ROUNDUP (pheaders->p_memsz + (pheaders->p_vaddr % PAGE_SIZE), PAGE_SIZE) - image->regions[regcount-1].vmsize;
398 image->regions[regcount].fdstart= 0;
399 image->regions[regcount].fdsize = 0;
400 image->regions[regcount].delta= 0;
401 image->regions[regcount].flags= RFLAG_ANON;
402 if(pheaders->p_flags & PF_W) {
403 // this is a writable segment
404 image->regions[regcount].flags|= RFLAG_RW;
408 regcount+= 1;
409 break;
410 case PT_DYNAMIC:
411 image->dynamic_ptr = pheaders->p_vaddr;
412 break;
413 case PT_INTERP:
414 /* should check here for appropiate interpreter */
415 break;
416 case PT_NOTE:
417 /* unsupported */
418 break;
419 case PT_SHLIB:
420 /* undefined semantics */
421 break;
422 case PT_PHDR:
423 /* we don't use it */
424 break;
425 default:
426 FATAL(true, "unhandled pheader type 0x%x\n", pheaders[i].p_type);
427 break;
432 static
433 bool
434 assert_dynamic_loadable(image_t *image)
436 unsigned i;
438 if(!image->dynamic_ptr) {
439 return true;
442 for(i= 0; i< image->num_regions; i++) {
443 if(image->dynamic_ptr>= image->regions[i].start) {
444 if(image->dynamic_ptr< image->regions[i].start+image->regions[i].size) {
445 return true;
450 return false;
453 static
454 bool
455 map_image(int fd, char const *path, image_t *image, bool fixed)
457 unsigned i;
459 (void)(fd);
461 for(i= 0; i< image->num_regions; i++) {
462 char region_name[256];
463 addr_t load_address;
464 unsigned addr_specifier;
466 sprintf(
467 region_name,
468 "%s:seg_%d(%s)",
469 path,
471 (image->regions[i].flags&RFLAG_RW)?"RW":"RO"
474 if(image->dynamic_ptr && !fixed) {
476 * relocatable image... we can afford to place wherever
478 if(i== 0) {
480 * but only the first segment gets a free ride
482 load_address= 0;
483 addr_specifier= REGION_ADDR_ANY_ADDRESS;
484 } else {
485 load_address= image->regions[i].vmstart + image->regions[i-1].delta;
486 addr_specifier= REGION_ADDR_EXACT_ADDRESS;
488 } else {
490 * not relocatable, put it where it asks or die trying
492 load_address= image->regions[i].vmstart;
493 addr_specifier= REGION_ADDR_EXACT_ADDRESS;
496 if(image->regions[i].flags & RFLAG_ANON) {
497 #if DEBUG_RLD
498 printf("rld map_image: creating anon region: name '%s' address 0x%x specifier 0x%x size 0x%x\n",
499 region_name, load_address, addr_specifier, image->regions[i].vmsize);
500 #endif
501 image->regions[i].id= _kern_vm_create_anonymous_region(
502 region_name,
503 (void **)&load_address,
504 addr_specifier,
505 image->regions[i].vmsize,
506 REGION_WIRING_LAZY,
507 LOCK_RW
510 if(image->regions[i].id < 0) {
511 printf("rld map_image: err %d from create_anon_region\n", image->regions[i].id);
512 goto error;
514 image->regions[i].delta = load_address - image->regions[i].vmstart;
515 image->regions[i].vmstart= load_address;
516 } else {
517 #if DEBUG_RLD
518 printf("rld map_image: mapping file: name '%s' address 0x%x specifier 0x%x size 0x%x path '%s' offset 0x%Lx\n",
519 region_name, load_address, addr_specifier, image->regions[i].vmsize,
520 path, ROUNDOWN(image->regions[i].fdstart, PAGE_SIZE));
521 #endif
522 image->regions[i].id= _kern_vm_map_file(
523 region_name,
524 (void **)&load_address,
525 addr_specifier,
526 image->regions[i].vmsize,
527 LOCK_RW,
528 REGION_PRIVATE_MAP,
529 path,
530 ROUNDOWN(image->regions[i].fdstart, PAGE_SIZE)
532 if(image->regions[i].id < 0) {
533 printf("rld map_image: err %d from map_file (address 0x%x)\n", image->regions[i].id, load_address);
534 goto error;
536 image->regions[i].delta = load_address - image->regions[i].vmstart;
537 image->regions[i].vmstart= load_address;
540 * handle trailer bits in data segment
542 if(image->regions[i].flags & RFLAG_RW) {
543 unsigned start_clearing;
544 unsigned to_clear;
546 start_clearing=
547 image->regions[i].vmstart
548 + PAGE_OFFS(image->regions[i].start)
549 + image->regions[i].size;
550 to_clear=
551 image->regions[i].vmsize
552 - PAGE_OFFS(image->regions[i].start)
553 - image->regions[i].size;
554 memset((void*)start_clearing, 0, to_clear);
559 if(image->dynamic_ptr) {
560 image->dynamic_ptr+= image->regions[0].delta;
563 return true;
565 error:
566 return false;
569 static
570 void
571 unmap_image(image_t *image)
573 unsigned i;
575 for(i= 0; i< image->num_regions; i++) {
576 _kern_vm_delete_region(image->regions[i].id);
578 image->regions[i].id= -1;
582 static
583 bool
584 parse_dynamic_segment(image_t *image)
586 struct Elf32_Dyn *d;
587 int i;
589 image->symhash = 0;
590 image->syms = 0;
591 image->strtab = 0;
593 d = (struct Elf32_Dyn *)image->dynamic_ptr;
594 if(!d) {
595 return true;
598 for(i=0; d[i].d_tag != DT_NULL; i++) {
599 switch(d[i].d_tag) {
600 case DT_NEEDED:
601 image->num_needed+= 1;
602 break;
603 case DT_HASH:
604 image->symhash = (unsigned int *)(d[i].d_un.d_ptr + image->regions[0].delta);
605 break;
606 case DT_STRTAB:
607 image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
608 break;
609 case DT_SYMTAB:
610 image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
611 break;
612 case DT_REL:
613 image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
614 break;
615 case DT_RELSZ:
616 image->rel_len = d[i].d_un.d_val;
617 break;
618 case DT_RELA:
619 image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
620 break;
621 case DT_RELASZ:
622 image->rela_len = d[i].d_un.d_val;
623 break;
624 // TK: procedure linkage table
625 case DT_JMPREL:
626 image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
627 break;
628 case DT_PLTRELSZ:
629 image->pltrel_len = d[i].d_un.d_val;
630 break;
631 case DT_PLTREL:
632 image->pltrel_type = d[i].d_un.d_val;
633 break;
634 default:
635 continue;
639 // lets make sure we found all the required sections
640 if(!image->symhash || !image->syms || !image->strtab) {
641 return false;
644 return true;
647 static
648 struct Elf32_Sym *
649 find_symbol_xxx(image_t *img, const char *_symbol)
651 unsigned int hash;
652 unsigned int i;
653 const char *symbol;
655 /* some architectures prepend a '_' to symbols, so lets do it here for lookups */
656 #if ELF_PREPEND_UNDERSCORE
657 char new_symbol[SYS_MAX_NAME_LEN];
659 new_symbol[0] = '_';
660 new_symbol[1] = 0;
661 strlcat(new_symbol, _symbol, SYS_MAX_NAME_LEN);
662 symbol = new_symbol;
663 #else
664 symbol = _symbol;
665 #endif
667 if(img->dynamic_ptr) {
668 hash = elf_hash(symbol) % HASHTABSIZE(img);
669 for(i = HASHBUCKETS(img)[hash]; i != STN_UNDEF; i = HASHCHAINS(img)[i]) {
670 if(img->syms[i].st_shndx!= SHN_UNDEF) {
671 if((ELF32_ST_BIND(img->syms[i].st_info)== STB_GLOBAL) || (ELF32_ST_BIND(img->syms[i].st_info)== STB_WEAK)) {
672 if(!strcmp(SYMNAME(img, &img->syms[i]), symbol)) {
673 return &img->syms[i];
680 return NULL;
683 static
684 struct Elf32_Sym *
685 find_symbol(image_t **shimg, const char *name)
687 image_t *iter;
688 unsigned int hash;
689 unsigned int i;
691 iter= loaded_images.head;
692 while(iter) {
693 if(iter->dynamic_ptr) {
694 hash = elf_hash(name) % HASHTABSIZE(iter);
695 for(i = HASHBUCKETS(iter)[hash]; i != STN_UNDEF; i = HASHCHAINS(iter)[i]) {
696 if(iter->syms[i].st_shndx!= SHN_UNDEF) {
697 if((ELF32_ST_BIND(iter->syms[i].st_info)== STB_GLOBAL) || (ELF32_ST_BIND(iter->syms[i].st_info)== STB_WEAK)) {
698 if(!strcmp(SYMNAME(iter, &iter->syms[i]), name)) {
699 *shimg= iter;
700 return &iter->syms[i];
707 iter= iter->next;
710 return NULL;
713 static
715 resolve_symbol(image_t *image, struct Elf32_Sym *sym, addr_t *sym_addr)
717 struct Elf32_Sym *sym2;
718 char *symname;
719 image_t *shimg;
721 switch(sym->st_shndx) {
722 case SHN_UNDEF:
723 // patch the symbol name
724 symname= SYMNAME(image, sym);
726 // it's undefined, must be outside this image, try the other image
727 sym2 = find_symbol(&shimg, symname);
728 if(!sym2) {
729 printf("elf_resolve_symbol: could not resolve symbol '%s'\n", symname);
730 return ERR_ELF_RESOLVING_SYMBOL;
733 // make sure they're the same type
734 if(ELF32_ST_TYPE(sym->st_info)!= STT_NOTYPE) {
735 if(ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) {
736 printf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", symname);
737 return ERR_ELF_RESOLVING_SYMBOL;
741 if(ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) {
742 printf("elf_resolve_symbol: found symbol '%s' but not exported\n", symname);
743 return ERR_ELF_RESOLVING_SYMBOL;
746 *sym_addr = sym2->st_value + shimg->regions[0].delta;
747 return NO_ERROR;
748 case SHN_ABS:
749 *sym_addr = sym->st_value + image->regions[0].delta;
750 return NO_ERROR;
751 case SHN_COMMON:
752 // XXX finish this
753 printf("elf_resolve_symbol: COMMON symbol, finish me!\n");
754 return ERR_NOT_IMPLEMENTED;
755 default:
756 // standard symbol
757 *sym_addr = sym->st_value + image->regions[0].delta;
758 return NO_ERROR;
763 #include "arch/rldreloc.inc"
766 static
767 image_t *
768 load_container(char const *path, char const *name, bool fixed)
770 int fd;
771 int len;
772 int ph_len;
773 char ph_buff[4096];
774 int num_regions;
775 bool map_success;
776 bool dynamic_success;
777 image_t *found;
778 image_t *image;
780 struct Elf32_Ehdr eheader;
782 found= find_image(name);
783 if(found) {
784 found->refcount+= 1;
785 return found;
788 #if DEBUG_RLD
789 printf("rld: load_container: path '%s', name '%s' entry\n", path, name);
790 #endif
792 fd= _kern_open(path, 0);
793 FATAL((fd< 0), "cannot open file %s\n", path);
795 len= _kern_read(fd, &eheader, 0, sizeof(eheader));
796 FATAL((len!= sizeof(eheader)), "troubles reading ELF header\n");
798 ph_len= parse_eheader(&eheader);
799 FATAL((ph_len<= 0), "incorrect ELF header\n");
800 FATAL((ph_len> (int)sizeof(ph_buff)), "cannot handle Program headers bigger than %lu\n", (long unsigned)sizeof(ph_buff));
802 len= _kern_read(fd, ph_buff, eheader.e_phoff, ph_len);
803 FATAL((len!= ph_len), "troubles reading Program headers\n");
805 num_regions= count_regions(ph_buff, eheader.e_phnum, eheader.e_phentsize);
806 FATAL((num_regions<= 0), "troubles parsing Program headers, num_regions= %d\n", num_regions);
808 image= create_image(name, num_regions);
809 FATAL((!image), "failed to allocate image_t control block\n");
811 parse_program_headers(image, ph_buff, eheader.e_phnum, eheader.e_phentsize);
812 FATAL(!assert_dynamic_loadable(image), "dynamic segment must be loadable (implementation restriction)\n");
814 map_success= map_image(fd, path, image, fixed);
815 FATAL(!map_success, "troubles reading image\n");
817 dynamic_success= parse_dynamic_segment(image);
818 FATAL(!dynamic_success, "troubles handling dynamic section\n");
820 image->entry_point= eheader.e_entry + image->regions[0].delta;
822 #if DEBUG_RLD
824 int i;
826 printf("rld: load_container: path '%s', name '%s' loaded:\n", path, name);
827 printf("\tregions:\n");
828 for(i=0; i<image->num_regions; i++) {
829 printf("\t\tid %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
830 image->regions[i].id, image->regions[i].start, image->regions[i].size,
831 image->regions[i].vmstart, image->regions[i].vmsize, image->regions[i].fdstart,
832 image->regions[i].fdsize, image->regions[i].delta, image->regions[i].flags);
835 #endif
837 _kern_close(fd);
839 enqueue_image(&loaded_images, image);
841 return image;
845 static
846 void
847 load_dependencies(image_t *img)
849 unsigned i;
850 unsigned j;
852 struct Elf32_Dyn *d;
853 addr_t needed_offset;
854 char path[256];
856 d = (struct Elf32_Dyn *)img->dynamic_ptr;
857 if(!d) {
858 return;
861 img->needed= rldalloc(img->num_needed*sizeof(image_t*));
862 FATAL((!img->needed), "failed to allocate needed struct\n");
863 memset(img->needed, 0, img->num_needed*sizeof(image_t*));
865 for(i=0, j= 0; d[i].d_tag != DT_NULL; i++) {
866 switch(d[i].d_tag) {
867 case DT_NEEDED:
868 needed_offset = d[i].d_un.d_ptr;
869 sprintf(path, "/boot/lib/%s", STRING(img, needed_offset));
870 img->needed[j]= load_container(path, STRING(img, needed_offset), false);
871 j+= 1;
873 break;
874 default:
876 * ignore any other tag
878 continue;
882 FATAL((j!= img->num_needed), "Internal error at load_dependencies()");
884 return;
887 static
888 unsigned
889 topological_sort(image_t *img, unsigned slot, image_t **init_list)
891 unsigned i;
893 img->flags|= RFLAG_SORTED; /* make sure we don't visit this one */
894 for(i= 0; i< img->num_needed; i++) {
895 if(!(img->needed[i]->flags & RFLAG_SORTED)) {
896 slot= topological_sort(img->needed[i], slot, init_list);
900 init_list[slot]= img;
901 return slot+1;
904 static
905 void
906 init_dependencies(image_t *img, bool init_head)
908 unsigned i;
909 unsigned slot;
910 image_t **init_list;
912 init_list= rldalloc(loaded_image_count*sizeof(image_t*));
913 FATAL((!init_list), "memory shortage in init_dependencies()");
914 memset(init_list, 0, loaded_image_count*sizeof(image_t*));
916 img->flags|= RFLAG_SORTED; /* make sure we don't visit this one */
917 slot= 0;
918 for(i= 0; i< img->num_needed; i++) {
919 if(!(img->needed[i]->flags & RFLAG_SORTED)) {
920 slot= topological_sort(img->needed[i], slot, init_list);
924 if(init_head) {
925 init_list[slot]= img;
926 slot+= 1;
929 for(i= 0; i< slot; i++) {
930 addr_t _initf= init_list[i]->entry_point;
931 libinit_f *initf= (libinit_f *)(_initf);
933 if(initf) {
934 initf(init_list[i]->imageid, uspa);
938 rldfree(init_list);
942 static
943 void
944 put_image(image_t *img)
946 img->refcount-= 1;
947 if(img->refcount== 0) {
948 size_t i;
950 dequeue_image(&loaded_images, img);
951 enqueue_image(&disposable_images, img);
953 for(i= 0; i< img->num_needed; i++) {
954 put_image(img->needed[i]);
961 * exported functions:
963 * + load_program()
964 * + load_library()
965 * + load_addon()
966 * + unload_program()
967 * + unload_library()
968 * + unload_addon()
969 * + dynamic_symbol()
971 dynmodule_id
972 load_program(char const *path, void **entry)
974 image_t *image;
975 image_t *iter;
977 image = load_container(path, NEWOS_MAGIC_APPNAME, true);
979 iter= loaded_images.head;
980 while(iter) {
981 load_dependencies(iter);
983 iter= iter->next;
986 iter= loaded_images.head;
987 while(iter) {
988 bool relocate_success;
990 relocate_success= relocate_image(iter);
991 FATAL(!relocate_success, "troubles relocating\n");
993 iter= iter->next;
996 init_dependencies(loaded_images.head, false);
998 *entry= (void*)(image->entry_point);
999 return image->imageid;
1002 dynmodule_id
1003 load_library(char const *path)
1005 image_t *image;
1006 image_t *iter;
1009 image = find_image(path);
1010 if(image) {
1011 image->refcount+= 1;
1012 return image->imageid;
1015 image = load_container(path, path, false);
1017 iter= loaded_images.head;
1018 while(iter) {
1019 load_dependencies(iter);
1021 iter= iter->next;
1024 iter= loaded_images.head;
1025 while(iter) {
1026 bool relocate_success;
1028 relocate_success= relocate_image(iter);
1029 FATAL(!relocate_success, "troubles relocating\n");
1031 iter= iter->next;
1034 init_dependencies(image, true);
1036 return image->imageid;
1039 dynmodule_id
1040 unload_library(dynmodule_id imid)
1042 int retval;
1043 image_t *iter;
1046 * we only check images that have been already initialized
1048 iter= loaded_images.head;
1049 while(iter) {
1050 if(iter->imageid== imid) {
1052 * do the unloading
1054 put_image(iter);
1056 break;
1059 iter= iter->next;
1062 if(iter) {
1063 retval= 0;
1064 } else {
1065 retval= -1;
1068 iter= disposable_images.head;
1069 while(iter) {
1070 // call image fini here...
1072 dequeue_image(&disposable_images, iter);
1073 unmap_image(iter);
1075 destroy_image(iter);
1076 iter= disposable_images.head;
1080 return retval;
1083 void *
1084 dynamic_symbol(dynmodule_id imid, char const *symname)
1086 image_t *iter;
1089 * we only check images that have been already initialized
1091 iter= loaded_images.head;
1092 while(iter) {
1093 if(iter->imageid== imid) {
1094 struct Elf32_Sym *sym= find_symbol_xxx(iter, symname);
1096 if(sym) {
1097 return (void*)(sym->st_value + iter->regions[0].delta);
1101 iter= iter->next;
1104 return NULL;
1108 * init routine, just get hold of the uspa args
1110 void
1111 rldelf_init(struct uspace_prog_args_t const *_uspa)
1113 uspa= _uspa;
1115 rld_sem= _kern_sem_create(1, "rld_lock\n");