2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <kernel/kernel.h>
6 #include <sys/errors.h>
7 #include <kernel/elf.h>
8 #include <kernel/vfs.h>
10 #include <kernel/thread.h>
11 #include <kernel/debug.h>
12 #include <kernel/heap.h>
13 #include <kernel/arch/cpu.h>
15 #include <sys/elf32.h>
17 #include <libc/string.h>
18 #include <libc/printf.h>
27 struct elf_image_info
{
28 struct elf_image_info
*next
;
31 struct elf_region regions
[2]; // describes the text and data regions
32 addr dynamic_ptr
; // pointer to the dynamic section
34 // pointer to symbol participation data structures
36 unsigned int *symhash
;
37 struct Elf32_Sym
*syms
;
39 struct Elf32_Rel
*rel
;
41 struct Elf32_Rela
*rela
;
45 static struct elf_image_info
*kernel_images
= NULL
;
46 static struct elf_image_info
*kernel_image
= NULL
;
47 static mutex image_lock
;
48 static mutex image_load_lock
;
49 static image_id next_image_id
= 0;
51 #define STRING(image, offset) ((char *)(&(image)->strtab[(offset)]))
52 #define SYMNAME(image, sym) STRING(image, (sym)->st_name)
53 #define SYMBOL(image, num) ((struct Elf32_Sym *)&(image)->syms[num])
54 #define HASHTABSIZE(image) ((image)->symhash[0])
55 #define HASHBUCKETS(image) ((unsigned int *)&(image)->symhash[2])
56 #define HASHCHAINS(image) ((unsigned int *)&(image)->symhash[2+HASHTABSIZE(image)])
58 static void insert_image_in_list(struct elf_image_info
*image
)
60 mutex_lock(&image_lock
);
62 image
->next
= kernel_images
;
63 kernel_images
= image
;
65 mutex_unlock(&image_lock
);
68 static struct elf_image_info
*find_image(image_id id
)
70 struct elf_image_info
*image
;
72 mutex_lock(&image_lock
);
74 for(image
= kernel_images
; image
; image
= image
->next
) {
78 mutex_unlock(&image_lock
);
83 static struct elf_image_info
*find_image_by_vnode(void *vnode
)
85 struct elf_image_info
*image
;
87 mutex_lock(&image_lock
);
89 for(image
= kernel_images
; image
; image
= image
->next
) {
90 if(image
->vnode
== vnode
)
93 mutex_unlock(&image_lock
);
98 static struct elf_image_info
*create_image_struct()
100 struct elf_image_info
*image
;
102 image
= kmalloc(sizeof(struct elf_image_info
));
105 memset(image
, 0, sizeof(struct elf_image_info
));
106 image
->regions
[0].id
= -1;
107 image
->regions
[1].id
= -1;
108 image
->id
= atomic_add(&next_image_id
, 1);
112 static unsigned long elf_hash(const unsigned char *name
)
114 unsigned long hash
= 0;
118 hash
= (hash
<< 4) + *name
++;
119 if((temp
= hash
& 0xf0000000))
126 static void dump_image_info(struct elf_image_info
*image
)
130 dprintf("elf_image_info at 0x%x:\n", image
);
131 dprintf(" next 0x%x\n", image
->next
);
132 dprintf(" id 0x%x\n", image
->id
);
134 dprintf(" regions[%d].id 0x%x\n", i
, image
->regions
[i
].id
);
135 dprintf(" regions[%d].start 0x%x\n", i
, image
->regions
[i
].start
);
136 dprintf(" regions[%d].size 0x%x\n", i
, image
->regions
[i
].size
);
137 dprintf(" regions[%d].delta %d\n", i
, image
->regions
[i
].delta
);
139 dprintf(" dynamic_ptr 0x%x\n", image
->dynamic_ptr
);
140 dprintf(" needed 0x%x\n", image
->needed
);
141 dprintf(" symhash 0x%x\n", image
->symhash
);
142 dprintf(" syms 0x%x\n", image
->syms
);
143 dprintf(" strtab 0x%x\n", image
->strtab
);
144 dprintf(" rel 0x%x\n", image
->rel
);
145 dprintf(" rel_len 0x%x\n", image
->rel_len
);
146 dprintf(" rela 0x%x\n", image
->rela
);
147 dprintf(" rela_len 0x%x\n", image
->rela_len
);
150 static void dump_symbol(struct elf_image_info
*image
, struct Elf32_Sym
*sym
)
153 dprintf("symbol at 0x%x, in image 0x%x\n", sym
, image
);
155 dprintf(" name index %d, '%s'\n", sym
->st_name
, SYMNAME(image
, sym
));
156 dprintf(" st_value 0x%x\n", sym
->st_value
);
157 dprintf(" st_size %d\n", sym
->st_size
);
158 dprintf(" st_info 0x%x\n", sym
->st_info
);
159 dprintf(" st_other 0x%x\n", sym
->st_other
);
160 dprintf(" st_shndx %d\n", sym
->st_shndx
);
163 static struct Elf32_Sym
*elf_find_symbol(struct elf_image_info
*image
, const char *name
)
168 hash
= elf_hash(name
) % HASHTABSIZE(image
);
169 for(i
= HASHBUCKETS(image
)[hash
]; i
!= STN_UNDEF
; i
= HASHCHAINS(image
)[i
]) {
170 if(!strcmp(SYMNAME(image
, &image
->syms
[i
]), name
)) {
171 return &image
->syms
[i
];
178 addr
elf_lookup_symbol(image_id id
, const char *symbol
)
180 struct elf_image_info
*image
;
181 struct Elf32_Sym
*sym
;
183 image
= find_image(id
);
187 sym
= elf_find_symbol(image
, symbol
);
191 if(sym
->st_shndx
== SHN_UNDEF
) {
194 return sym
->st_value
+ image
->regions
[0].delta
;
197 static int elf_parse_dynamic_section(struct elf_image_info
*image
)
201 int needed_offset
= -1;
203 // dprintf("top of elf_parse_dynamic_section\n");
209 d
= (struct Elf32_Dyn
*)image
->dynamic_ptr
;
213 for(i
=0; d
[i
].d_tag
!= DT_NULL
; i
++) {
216 needed_offset
= d
[i
].d_un
.d_ptr
+ image
->regions
[0].delta
;
219 image
->symhash
= (unsigned int *)(d
[i
].d_un
.d_ptr
+ image
->regions
[0].delta
);
222 image
->strtab
= (char *)(d
[i
].d_un
.d_ptr
+ image
->regions
[0].delta
);
225 image
->syms
= (struct Elf32_Sym
*)(d
[i
].d_un
.d_ptr
+ image
->regions
[0].delta
);
228 image
->rel
= (struct Elf32_Rel
*)(d
[i
].d_un
.d_ptr
+ image
->regions
[0].delta
);
231 image
->rel_len
= d
[i
].d_un
.d_val
;
234 image
->rela
= (struct Elf32_Rela
*)(d
[i
].d_un
.d_ptr
+ image
->regions
[0].delta
);
237 image
->rela_len
= d
[i
].d_un
.d_val
;
244 // lets make sure we found all the required sections
245 if(!image
->symhash
|| !image
->syms
|| !image
->strtab
)
248 // dprintf("needed_offset = %d\n", needed_offset);
250 if(needed_offset
>= 0)
251 image
->needed
= STRING(image
, needed_offset
);
256 // this function first tries to see if the first image and it's already resolved symbol is okay, otherwise
257 // it tries to link against the shared_image
258 // XXX gross hack and needs to be done better
259 static addr
elf_resolve_symbol(struct elf_image_info
*image
, struct Elf32_Sym
*sym
, struct elf_image_info
*shared_image
)
261 struct Elf32_Sym
*sym2
;
263 switch(sym
->st_shndx
) {
265 // it's undefined, must be outside this image, try the other image
266 sym2
= elf_find_symbol(shared_image
, SYMNAME(image
, sym
));
268 dprintf("elf_resolve_symbol: could not resolve symbol '%s'\n", SYMNAME(image
, sym
));
272 // make sure they're the same type
273 if(ELF32_ST_TYPE(sym
->st_info
) != ELF32_ST_TYPE(sym2
->st_info
)) {
274 dprintf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", SYMNAME(image
, sym
));
278 if(ELF32_ST_BIND(sym2
->st_info
) != STB_GLOBAL
&& ELF32_ST_BIND(sym2
->st_info
) != STB_WEAK
) {
279 dprintf("elf_resolve_symbol: found symbol '%s' but not exported\n", SYMNAME(image
, sym
));
283 return sym2
->st_value
+ shared_image
->regions
[0].delta
;
285 return sym
->st_value
;
288 dprintf("elf_resolve_symbol: COMMON symbol, finish me!\n");
292 return sym
->st_value
+ image
->regions
[0].delta
;
296 // XXX for now just link against the kernel
297 static int elf_relocate(struct elf_image_info
*image
)
300 struct Elf32_Sym
*sym
;
308 // dprintf("top of elf_relocate\n");
310 // deal with the rels first
312 for(i
= 0; i
* (int)sizeof(struct Elf32_Rel
) < image
->rel_len
; i
++) {
313 // dprintf("looking at rel type %d, offset 0x%x\n", ELF32_R_TYPE(image->rel[i].r_info), image->rel[i].r_offset);
316 switch(ELF32_R_TYPE(image
->rel
[i
].r_info
)) {
322 sym
= SYMBOL(image
, ELF32_R_SYM(image
->rel
[i
].r_info
));
324 S
= elf_resolve_symbol(image
, sym
, kernel_image
);
325 // dprintf("S 0x%x\n", S);
328 switch(ELF32_R_TYPE(image
->rel
[i
].r_info
)) {
336 A
= *(addr
*)(image
->regions
[0].delta
+ image
->rel
[i
].r_offset
);
337 // dprintf("A 0x%x\n", A);
341 switch(ELF32_R_TYPE(image
->rel
[i
].r_info
)) {
346 P
= image
->regions
[0].delta
+ image
->rel
[i
].r_offset
;
347 // dprintf("P 0x%x\n", P);
351 switch(ELF32_R_TYPE(image
->rel
[i
].r_info
)) {
358 final_val
= S
+ A
- P
;
362 final_val
= image
->regions
[0].delta
+ A
;
365 dprintf("unhandled relocation type %d\n", ELF32_R_TYPE(image
->rel
[i
].r_info
));
366 return ERR_NOT_ALLOWED
;
368 *(addr
*)(image
->regions
[0].delta
+ image
->rel
[i
].r_offset
) = final_val
;
373 dprintf("RELA relocations not supported\n");
374 return ERR_NOT_ALLOWED
;
375 for(i
= 1; i
* (int)sizeof(struct Elf32_Rela
) < image
->rela_len
; i
++) {
376 dprintf("rela: type %d\n", ELF32_R_TYPE(image
->rela
[i
].r_info
));
382 static int verify_eheader(struct Elf32_Ehdr
*eheader
)
384 if(memcmp(eheader
->e_ident
, ELF_MAGIC
, 4) != 0)
385 return ERR_INVALID_BINARY
;
387 if(eheader
->e_ident
[4] != ELFCLASS32
)
388 return ERR_INVALID_BINARY
;
390 if(eheader
->e_phoff
== 0)
391 return ERR_INVALID_BINARY
;
393 if(eheader
->e_phentsize
< sizeof(struct Elf32_Phdr
))
394 return ERR_INVALID_BINARY
;
399 int elf_load_uspace(const char *path
, struct proc
*p
, int flags
, addr
*entry
)
401 struct Elf32_Ehdr eheader
;
402 struct Elf32_Phdr
*pheaders
= NULL
;
408 dprintf("elf_load: entry path '%s', proc 0x%x\n", path
, p
);
410 fd
= sys_open(path
, STREAM_TYPE_FILE
, 0);
414 len
= sys_read(fd
, &eheader
, 0, sizeof(eheader
));
419 if(len
!= sizeof(eheader
)) {
421 err
= ERR_INVALID_BINARY
;
424 err
= verify_eheader(&eheader
);
428 pheaders
= kmalloc(eheader
.e_phnum
* eheader
.e_phentsize
);
429 if(pheaders
== NULL
) {
430 dprintf("error allocating space for program headers\n");
435 dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader
.e_phoff
, eheader
.e_phnum
* eheader
.e_phentsize
);
436 len
= sys_read(fd
, pheaders
, eheader
.e_phoff
, eheader
.e_phnum
* eheader
.e_phentsize
);
439 dprintf("error reading in program headers\n");
442 if(len
!= eheader
.e_phnum
* eheader
.e_phentsize
) {
443 dprintf("short read while reading in program headers\n");
448 for(i
=0; i
< eheader
.e_phnum
; i
++) {
449 char region_name
[64];
453 sprintf(region_name
, "%s_seg%d", path
, i
);
455 region_addr
= (char *)ROUNDOWN(pheaders
[i
].p_vaddr
, PAGE_SIZE
);
456 id
= vm_create_anonymous_region(p
->aspace_id
, region_name
, (void **)®ion_addr
, REGION_ADDR_EXACT_ADDRESS
,
457 ROUNDUP(pheaders
[i
].p_memsz
+ (pheaders
[i
].p_vaddr
% PAGE_SIZE
), PAGE_SIZE
), REGION_WIRING_LAZY
, LOCK_RW
);
459 dprintf("error allocating region!\n");
460 err
= ERR_INVALID_BINARY
;
464 len
= sys_read(fd
, region_addr
+ (pheaders
[i
].p_vaddr
% PAGE_SIZE
), pheaders
[i
].p_offset
, pheaders
[i
].p_filesz
);
467 dprintf("error reading in seg %d\n", i
);
472 *entry
= pheaders
[i
].p_vaddr
;
475 dprintf("elf_load: done!\n");
487 image_id
elf_load_kspace(const char *path
)
489 struct Elf32_Ehdr eheader
;
490 struct Elf32_Phdr
*pheaders
;
491 struct elf_image_info
*image
;
498 dprintf("elf_load_kspace: entry path '%s'\n", path
);
500 fd
= sys_open(path
, STREAM_TYPE_FILE
, 0);
504 err
= vfs_get_vnode_from_fd(fd
, true, &vnode
);
508 // XXX awful hack to keep someone else from trying to load this image
509 // probably not a bad thing, shouldn't be too many races
510 mutex_lock(&image_load_lock
);
512 // make sure it's not loaded already. Search by vnode
513 if(find_image_by_vnode(vnode
)) {
514 err
= ERR_NOT_ALLOWED
;
518 len
= sys_read(fd
, &eheader
, 0, sizeof(eheader
));
523 if(len
!= sizeof(eheader
)) {
525 err
= ERR_INVALID_BINARY
;
528 err
= verify_eheader(&eheader
);
532 image
= create_image_struct();
537 image
->vnode
= vnode
;
539 pheaders
= kmalloc(eheader
.e_phnum
* eheader
.e_phentsize
);
540 if(pheaders
== NULL
) {
541 dprintf("error allocating space for program headers\n");
546 // dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize);
547 len
= sys_read(fd
, pheaders
, eheader
.e_phoff
, eheader
.e_phnum
* eheader
.e_phentsize
);
550 dprintf("error reading in program headers\n");
553 if(len
!= eheader
.e_phnum
* eheader
.e_phentsize
) {
554 dprintf("short read while reading in program headers\n");
559 for(i
=0; i
< eheader
.e_phnum
; i
++) {
560 char region_name
[64];
561 bool ro_segment_handled
= false;
562 bool rw_segment_handled
= false;
566 // dprintf("looking at program header %d\n", i);
568 switch(pheaders
[i
].p_type
) {
572 image
->dynamic_ptr
= pheaders
[i
].p_vaddr
;
575 dprintf("unhandled pheader type 0x%x\n", pheaders
[i
].p_type
);
579 // we're here, so it must be a PT_LOAD segment
580 if((pheaders
[i
].p_flags
& (PF_R
| PF_W
| PF_X
)) == (PF_R
| PF_W
)) {
581 // this is the writable segment
582 if(rw_segment_handled
) {
583 // we've already created this segment
586 rw_segment_handled
= true;
588 lock
= LOCK_RW
|LOCK_KERNEL
;
589 sprintf(region_name
, "%s_rw", path
);
590 } else if((pheaders
[i
].p_flags
& (PF_R
| PF_W
| PF_X
)) == (PF_R
| PF_X
)) {
591 // this is the non-writable segment
592 if(ro_segment_handled
) {
593 // we've already created this segment
596 ro_segment_handled
= true;
598 // lock = LOCK_RO|LOCK_KERNEL;
599 lock
= LOCK_RW
|LOCK_KERNEL
;
600 sprintf(region_name
, "%s_ro", path
);
602 dprintf("weird program header flags 0x%x\n", pheaders
[i
].p_flags
);
605 image
->regions
[image_region
].size
= ROUNDUP(pheaders
[i
].p_memsz
+ (pheaders
[i
].p_vaddr
% PAGE_SIZE
), PAGE_SIZE
);
606 image
->regions
[image_region
].id
= vm_create_anonymous_region(vm_get_kernel_aspace_id(), region_name
,
607 (void **)&image
->regions
[image_region
].start
, REGION_ADDR_ANY_ADDRESS
,
608 image
->regions
[image_region
].size
, REGION_WIRING_WIRED
, lock
);
609 if(image
->regions
[image_region
].id
< 0) {
610 dprintf("error allocating region!\n");
611 err
= ERR_INVALID_BINARY
;
614 image
->regions
[image_region
].delta
= image
->regions
[image_region
].start
- pheaders
[i
].p_vaddr
;
616 // dprintf("elf_load_kspace: created a region at 0x%x\n", image->regions[image_region].start);
618 len
= sys_read(fd
, (void *)(image
->regions
[image_region
].start
+ (pheaders
[i
].p_vaddr
% PAGE_SIZE
)),
619 pheaders
[i
].p_offset
, pheaders
[i
].p_filesz
);
622 dprintf("error reading in seg %d\n", i
);
627 if(image
->regions
[1].start
!= 0) {
628 if(image
->regions
[0].delta
!= image
->regions
[1].delta
) {
629 dprintf("could not load binary, fix the region problem!\n");
635 // modify the dynamic ptr by the delta of the regions
636 image
->dynamic_ptr
+= image
->regions
[0].delta
;
638 err
= elf_parse_dynamic_section(image
);
642 err
= elf_relocate(image
);
646 // dprintf("elf_load_kspace: done!\n");
653 insert_image_in_list(image
);
655 mutex_unlock(&image_load_lock
);
660 if(image
->regions
[1].id
>= 0)
661 vm_delete_region(vm_get_kernel_aspace_id(), image
->regions
[1].id
);
662 if(image
->regions
[0].id
>= 0)
663 vm_delete_region(vm_get_kernel_aspace_id(), image
->regions
[0].id
);
669 mutex_unlock(&image_load_lock
);
672 vfs_put_vnode_ptr(vnode
);
678 int elf_init(kernel_args
*ka
)
680 vm_region_info rinfo
;
683 // build a image structure for the kernel, which has already been loaded
684 kernel_image
= create_image_struct();
687 kernel_image
->regions
[0].id
= vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_ro");
688 if(kernel_image
->regions
[0].id
< 0)
689 panic("elf_init: could not look up kernel text segment region\n");
690 vm_get_region_info(kernel_image
->regions
[0].id
, &rinfo
);
691 kernel_image
->regions
[0].start
= rinfo
.base
;
692 kernel_image
->regions
[0].size
= rinfo
.size
;
695 kernel_image
->regions
[1].id
= vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_rw");
696 if(kernel_image
->regions
[1].id
< 0)
697 panic("elf_init: could not look up kernel data segment region\n");
698 vm_get_region_info(kernel_image
->regions
[1].id
, &rinfo
);
699 kernel_image
->regions
[1].start
= rinfo
.base
;
700 kernel_image
->regions
[1].size
= rinfo
.size
;
702 // we know where the dynamic section is
703 kernel_image
->dynamic_ptr
= (addr
)ka
->kernel_dynamic_section_addr
.start
;
705 // parse the dynamic section
706 if(elf_parse_dynamic_section(kernel_image
) < 0)
707 panic("elf_init: elf_parse_dynamic_section doesn't like the kernel image\n");
709 // insert it first in the list of kernel images loaded
710 kernel_images
= NULL
;
711 insert_image_in_list(kernel_image
);
713 mutex_init(&image_lock
, "kimages_lock");
714 mutex_init(&image_load_lock
, "kimages_load_lock");