PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
erl.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
16#define DEBUG 1
17#define STANDALONE 1
18#define FORCE_ALIGN 1
19
20#undef DEBUG
21#undef STANDALONE
22
23/**** Note this code should compile on PC-side, mainly for direct check purposes though ****/
24
25#ifdef DEBUG
26#ifdef FULLDEBUG
27#define dprintf(fmt, args...) printf("(%s:%s:%i): " fmt, __FILE__, __FUNCTION__, __LINE__, ## args)
28#else
29#define dprintf(fmt, args...) printf(fmt, ## args)
30#endif
31#define rprintf(fmt, args...) printf(fmt, ## args)
32#else
33#define dprintf(a...) do { } while(0)
34#define rprintf(a...) do { } while(0)
35#endif
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <string.h>
40#include <sys/fcntl.h>
41#include <sys/unistd.h>
42
43#ifdef __linux__
44#include <sys/types.h>
45#include <sys/stat.h>
46#endif
47
48#ifdef _WIN32
49#include <io.h>
50#endif
51
52#include <erl.h>
53
54#include <hashtab.h>
55#include <recycle.h>
56#undef align
57
58
59#ifdef _EE
60#include <tamtypes.h>
61#include <kernel.h>
62#else
63typedef unsigned char u8;
64typedef unsigned short u16;
65typedef unsigned int u32;
66typedef signed char s8;
67typedef signed short s16;
68typedef signed int s32;
69#endif
70
71#ifdef DEBUG
72
73static char * elf_classes[] = {
74 "Invalid class",
75 "32-bit objects",
76 "64-bit objects",
77};
78
79static char * elf_encodings[] = {
80 "Invalid encoding",
81 "Little endian",
82 "Big endian",
83};
84
85static char * elf_types[] = {
86 "No file type",
87 "Relocatable file",
88 "Executable file",
89 "Shared object file",
90 "Core file",
91};
92
93static char * elf_machines[] = {
94 "No machine",
95 "AT&T WE 32100",
96 "SPARC",
97 "Intel Architecture",
98 "Motorola 68000",
99 "Motorola 88000",
100 "Intel 80860",
101 "MIPS RS3000 Big-Endian",
102 "MIPS RS4000 Big-Endian",
103};
104
105static char * section_types[] = {
106 "Null",
107 "Progbits",
108 "Symtab",
109 "Strtab",
110 "Rela",
111 "Hash",
112 "Dynamic",
113 "Note",
114 "Nobits",
115 "Rel",
116 "Shlib",
117 "Dynsym",
118};
119
120static char * section_flags[] = {
121 "---",
122 "--W",
123 "-R-",
124 "-RW",
125 "X--",
126 "X-W",
127 "XR-",
128 "XRW",
129};
130
131static char * symbol_types[] = {
132 "NoType",
133 "Object",
134 "Func",
135 "Section",
136 "File",
137 "?? (5)",
138 "?? (6)",
139 "?? (7)",
140 "?? (8)",
141 "?? (9)",
142 "?? (10)",
143 "?? (11)",
144 "?? (12)",
145 "LoProc",
146 "?? (14)",
147 "HiProc",
148};
149
150static char * binding_types[] = {
151 "Local",
152 "Global",
153 "Weak",
154 "?? (3)",
155 "?? (4)",
156 "?? (5)",
157 "?? (6)",
158 "?? (7)",
159 "?? (8)",
160 "?? (9)",
161 "?? (10)",
162 "?? (11)",
163 "?? (12)",
164 "LoProc",
165 "?? (14)",
166 "HiProc",
167};
168
169static char * reloc_types[] = {
170 "R_MIPS_NONE",
171 "R_MIPS_16",
172 "R_MIPS_32",
173 "R_MIPS_REL32",
174 "R_MIPS_26",
175 "R_MIPS_HI16",
176 "R_MIPS_LO16",
177 "R_MIPS_GPREL16",
178 "R_MIPS_LITERAL",
179 "R_MIPS_GOT16",
180 "R_MIPS_PC16",
181 "R_MIPS_CALL16",
182 "R_MIPS_GPREL32"
183};
184
185#endif
186
187#define REL_TYPE 1
188#define PROGBITS 1
189#define NOBITS 8
190#define REL 9
191#define RELA 4
192#define GLOBAL 1
193#define WEAK 2
194#define NOTYPE 0
195#define OBJECT 1
196#define FUNC 2
197#define SECTION 3
198#define R_MIPS_32 2
199#define R_MIPS_26 4
200#define R_MIPS_HI16 5
201#define R_MIPS_LO16 6
202
203
204/* These global names will not be 'exported' to the global space. */
205
206static const char * local_names[] = {
207 "_init",
208 "_fini",
209 "erl_id",
210 "erl_dependancies",
211 "erl_copyright",
212 "erl_version",
213 "_start",
214 0
215};
216
217
218/* Structures mapped onto the loaded erl file. */
219
220struct elf_header_t {
221 union {
222 u8 raw[16];
223 struct e_ident_t {
224 u8 ei_magic[4];
225 u8 ei_class;
226 u8 ei_data;
227 u8 ei_version;
228 } cook;
229 } e_ident;
230 u16 e_type;
231 u16 e_machine;
232 u32 e_version;
233 u32 e_entry;
234 u32 e_phoff;
235 u32 e_shoff;
236 u32 e_flags;
237 u16 e_ehsize;
238 u16 e_phentsize;
239 u16 e_phnum;
240 u16 e_shentsize;
241 u16 e_shnum;
242 u16 e_shstrndx;
243};
244
246 u32 sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size;
247 u32 sh_link, sh_info, sh_addralign, sh_entsize;
248};
249
251 u32 st_name, st_value, st_size;
252 u8 st_info, st_other;
253 u16 st_shndx;
254};
255
257 u32 r_offset, r_info;
258};
259
261 u32 r_offset, r_info, r_addend;
262};
263
264/* Our internal structures. */
265
266struct loosy_t {
267 u8 * reloc;
268 int type;
269 struct loosy_t * next;
270 struct erl_record_t * erl;
271};
272
274 struct erl_record_t * depender, * provider;
275 struct dependancy_t * next, * prev;
276};
277
278
279/* And our global variables. */
280static struct erl_record_t * erl_record_root = 0;
281
282static htab * global_symbols = 0;
283static htab * loosy_relocs = 0;
284
285char _init_erl_prefix[256] = "";
286
287static struct dependancy_t * dependancy_root = 0;
288
289
290static u32 align(u32 x, int align) {
291#ifdef FORCE_ALIGN
292 if (align < 16)
293 align = 16;
294#endif
295
296 align--;
297
298 if (x & align) {
299 x |= align;
300 x++;
301 }
302
303 return x;
304}
305
306static struct loosy_t * create_loosy(struct erl_record_t * erl, u8 * reloc, int type) {
307 struct loosy_t * r;
308
309 if (!(r = (struct loosy_t *) malloc(sizeof(struct loosy_t))))
310 return 0;
311
312 r->reloc = reloc;
313 r->type = type;
314 r->next = 0;
315 r->erl = erl;
316
317 return r;
318}
319
320static void destroy_loosy(struct loosy_t * l) {
321 free(l);
322}
323
324static void r_destroy_loosy(struct loosy_t * l) {
325 if (!l)
326 return;
327
328 r_destroy_loosy(l->next);
329
330 destroy_loosy(l);
331}
332
333static reroot * symbol_recycle = 0;
334
335static struct symbol_t * create_symbol(struct erl_record_t * provider, u32 address) {
336 struct symbol_t * r;
337
338 if (!symbol_recycle)
339 symbol_recycle = remkroot(sizeof(struct symbol_t));
340
341 r = (struct symbol_t *) renew(symbol_recycle);
342
343 r->provider = provider;
344 r->address = address;
345
346 return r;
347}
348
349static void destroy_symbol(struct symbol_t * s) {
350 redel(symbol_recycle, s);
351}
352
353static struct erl_record_t * allocate_erl_record() {
354 struct erl_record_t * r;
355
356 if (!(r = (struct erl_record_t *) malloc(sizeof(struct erl_record_t))))
357 return 0;
358
359 r->bytes = NULL;
360 r->symbols = hcreate(6);
361
362 if ((r->next = erl_record_root))
363 r->next->prev = r;
364 r->prev = 0;
365 erl_record_root = r;
366
367 r->flags = 0;
368
369 return r;
370}
371
372static void destroy_erl_record(struct erl_record_t * erl) {
373 if (!erl)
374 return;
375
376 if (erl->bytes) {
377 if (erl->flags & ERL_FLAG_CLEAR)
378 memset(erl->bytes, 0, erl->fullsize);
379 if (!(erl->flags & ERL_FLAG_STATIC))
380 free(erl->bytes);
381 }
382
383 erl_flush_symbols(erl);
384
385 if (erl->prev)
386 erl->prev->next = erl->next;
387 else
388 erl_record_root = erl->next;
389
390 if (erl->next)
391 erl->next->prev = erl->prev;
392
393 free(erl);
394}
395
396static int apply_reloc(u8 * reloc, int type, u32 addr) {
397 u32 u_current_data;
398 s32 s_current_data;
399 u32 newstate;
400
401 if (((u32)reloc)&0x3)
402 {
403 printf("Unaligned reloc (%p) type=%d!\n", reloc, type);
404 }
405 memcpy(&u_current_data, reloc, 4);
406 memcpy(&s_current_data, reloc, 4);
407
408 switch (type) {
409 case R_MIPS_32:
410 newstate = s_current_data + addr;
411 break;
412 case R_MIPS_26:
413 newstate = (u_current_data & 0xfc000000) | (((u_current_data & 0x03ffffff) + (addr >> 2)) & 0x3ffffff);
414 break;
415 case R_MIPS_HI16:
416 newstate = (u_current_data & 0xffff0000) | ((((s_current_data << 16) >> 16) + (addr >> 16) + ((addr & 0xffff) >= 0x8000 ? 1 : 0)) & 0xffff);
417 break;
418 case R_MIPS_LO16:
419 newstate = (u_current_data & 0xffff0000) | ((((s_current_data << 16) >> 16) + (addr & 0xffff)) & 0xffff);
420 break;
421 default:
422 return -1;
423 }
424
425 memcpy(reloc, &newstate, 4);
426
427 dprintf("Changed data at %08X from %08X to %08X.\n", reloc, u_current_data, newstate);
428 return 0;
429}
430
431struct symbol_t * erl_find_local_symbol(const char * symbol, struct erl_record_t * erl) {
432 if (!erl)
433 return 0;
434 if (hfind(erl->symbols, symbol, strlen(symbol)))
435 return hstuff(erl->symbols);
436 return 0;
437}
438
439static struct symbol_t * r_find_symbol(const char * symbol, struct erl_record_t * erl) {
440 if (!erl)
441 return 0;
442 if (hfind(erl->symbols, symbol, strlen(symbol)))
443 return hstuff(erl->symbols);
444 return r_find_symbol(symbol, erl->next);
445}
446
447struct symbol_t * erl_find_symbol(const char * symbol) {
448 if (global_symbols)
449 if (hfind(global_symbols, symbol, strlen(symbol)))
450 return hstuff(global_symbols);
451 return r_find_symbol(symbol, erl_record_root);
452}
453
454static struct dependancy_t * add_dependancy(struct erl_record_t * depender, struct erl_record_t * provider) {
455 struct dependancy_t * d;
456
457 if (depender == provider)
458 return 0;
459
460 if (!(d = (struct dependancy_t *) malloc(sizeof(struct dependancy_t))))
461 return 0;
462
463 d->depender = depender;
464 d->provider = provider;
465
466 if ((d->next = dependancy_root))
467 d->next->prev = d;
468
469 d->prev = 0;
470 dependancy_root = d;
471
472 return d;
473}
474
475static void destroy_dependancy(struct dependancy_t * d) {
476 if (d->prev)
477 d->prev->next = d->next;
478 else
479 dependancy_root = d->next;
480
481 if (d->next)
482 d->next->prev = d->prev;
483
484 free(d);
485}
486
487static void r_destroy_dependancy_r(struct erl_record_t * erl, struct dependancy_t * d) {
488 if (!d)
489 return;
490
491 r_destroy_dependancy_r(erl, d->next);
492
493 if (erl == d->depender)
494 destroy_dependancy(d);
495
496 return;
497}
498
499static void destroy_dependancy_r(struct erl_record_t * erl) {
500 r_destroy_dependancy_r(erl, dependancy_root);
501}
502
503static void add_loosy(struct erl_record_t * erl, u8 * reloc, int type, const char * symbol) {
504 struct loosy_t * l;
505
506 l = create_loosy(erl, reloc, type);
507
508 if (!loosy_relocs)
509 loosy_relocs = hcreate(6);
510
511 if (!hadd(loosy_relocs, symbol, strlen(symbol), l)) {
512 l->next = hstuff(loosy_relocs);
513 hstuff(loosy_relocs) = l;
514 } else {
515 hkey(loosy_relocs) = (ub1 *)strdup(symbol);
516 }
517}
518
519static int fix_loosy(struct erl_record_t * provider, const char * symbol, u32 address) {
520 struct loosy_t * l;
521 int count = 0;
522
523 if (!loosy_relocs)
524 return count;
525
526 if (hfind(loosy_relocs, symbol, strlen(symbol))) {
527 for (l = hstuff(loosy_relocs); l; l = l->next) {
528 apply_reloc(l->reloc, l->type, address);
529 add_dependancy(l->erl, provider);
530 count++;
531 }
532 r_destroy_loosy(hstuff(loosy_relocs));
533 free(hkey(loosy_relocs));
534 hdel(loosy_relocs);
535 }
536
537 return count;
538}
539
540static int is_local(const char * symbol) {
541 const char ** p;
542
543 for (p = local_names; *p; p++)
544 if (!strcmp(*p, symbol))
545 return 1;
546
547 return 0;
548}
549
550static int add_symbol(struct erl_record_t * erl, const char * symbol, u32 address) {
551 htab * symbols;
552
553 if (erl) {
554 symbols = erl->symbols;
555 } else {
556 if (!global_symbols)
557 global_symbols = hcreate(6);
558 symbols = global_symbols;
559 }
560
561 if (!is_local(symbol) && erl_find_symbol(symbol))
562 return -1;
563
564 dprintf("Adding symbol %s at address %08X\n", symbol, address);
565
566 if (fix_loosy(erl, symbol, address)) {
567#ifdef _EE
568 FlushCache(2);
569 FlushCache(0);
570#endif
571 }
572
573 hadd(symbols, strdup(symbol), strlen(symbol), create_symbol(erl, address));
574
575 return 0;
576}
577
578int erl_add_global_symbol(const char * symbol, u32 address) {
579 return add_symbol(0, symbol, address);
580}
581
582static int read_erl(int elf_handle, u8 * elf_mem, u32 addr, struct erl_record_t ** p_erl_record) {
583 struct elf_header_t head;
584 struct elf_section_t * sec = 0;
585 struct elf_symbol_t * sym = 0;
586 struct elf_reloc_t reloc;
587 int i, j;
588 // int erx_compressed; // Not used
589 char * names = 0, * strtab_names = 0, * reloc_section = 0;
590 int symtab = 0, strtab = 0, linked_strtab = 0;
591 u8 * magic;
592 u32 fullsize = 0;
593 struct erl_record_t * erl_record = 0;
594 struct symbol_t * s;
595
596 *p_erl_record = 0;
597
598#define free_and_return(code) if (!elf_mem) { \
599 if (names) free(names); \
600 if (strtab_names) free(strtab_names); \
601 if (sec) free(sec); \
602 if (sym) free(sym); \
603 if ((code < 0) && erl_record) destroy_erl_record(erl_record); \
604} \
605return code
606
607 if (!(erl_record = allocate_erl_record())) {
608 dprintf("Memory allocation error.\n");
609 free_and_return(-1);
610 }
611
612 // Reading the main ELF header.
613 if (elf_mem) {
614 memcpy(&head, elf_mem, sizeof(head));
615 } else {
616 lseek(elf_handle, 0, SEEK_SET);
617 read(elf_handle, &head, sizeof(head));
618 }
619
620 magic = head.e_ident.cook.ei_magic;
621
622 if ((magic[0] != 0x7f) || (magic[1] != 'E') || (magic[2] != 'L') || ((magic[3] != 'F') && (magic[3] != 'X'))) {
623 dprintf("Not an ELF file.\n");
624 free_and_return(-1);
625 }
626
627 // erx_compressed = magic[3] == 'X'; //not used
628
629 dprintf("ELF Class : %s\n", elf_classes[head.e_ident.cook.ei_class]);
630 dprintf("Data encoding: %s\n", elf_encodings[head.e_ident.cook.ei_data]);
631 dprintf("Elf version : %i\n", head.e_ident.cook.ei_version);
632 if (head.e_type == 0xffff) {
633 dprintf("Object type : Processor specific (hi)\n");
634 } else if (head.e_type == 0xff00) {
635 dprintf("Object type : Processor specific (lo)\n");
636 } else {
637 dprintf("Object type : %s\n", elf_types[head.e_type]);
638 }
639 dprintf("Machine type : %s\n", elf_machines[head.e_machine]);
640 dprintf("Object ver. : %i\n", head.e_version);
641 dprintf("Elf entry : %08X\n", head.e_entry);
642 dprintf("PH offset : %08X\n", head.e_phoff);
643 dprintf("SH offset : %08X\n", head.e_shoff);
644 dprintf("Flags : %08X\n", head.e_flags);
645 dprintf("Header size : %04X\n", head.e_ehsize);
646 dprintf("PH ent. size : %04X\n", head.e_phentsize);
647 dprintf("PH number : %04X\n", head.e_phnum);
648 dprintf("SH ent. size : %04X\n", head.e_shentsize);
649 dprintf("SH number : %04X\n", head.e_shnum);
650 dprintf("SH str index : %04X\n", head.e_shstrndx);
651
652 if (head.e_type != REL_TYPE) {
653 dprintf("File isn't a relocatable ELF file.\n");
654 free_and_return(-1);
655 }
656
657 // Reading the section table.
658 if (sizeof(struct elf_section_t) != head.e_shentsize) {
659 dprintf("Inconsistancy in section table entries.\n");
660 free_and_return(-1);
661 }
662
663 // **TODO** handle compession
664 if (elf_mem) {
665 sec = (struct elf_section_t *) (elf_mem + head.e_shoff);
666 } else {
667 if (!(sec = (struct elf_section_t *) malloc(sizeof(struct elf_section_t) * head.e_shnum))) {
668 dprintf("Not enough memory.\n");
669 free_and_return(-1);
670 }
671 lseek(elf_handle, head.e_shoff, SEEK_SET);
672 read(elf_handle, sec, sizeof(struct elf_section_t) * head.e_shnum);
673 }
674
675 // Reading the section names's table.
676 // **TODO** handle compession
677 if (elf_mem) {
678 names = (char *) (elf_mem + sec[head.e_shstrndx].sh_offset);
679 } else {
680 if (!(names = (char *) malloc(sec[head.e_shstrndx].sh_size))) {
681 dprintf("Not enough memory.\n");
682 free_and_return(-1);
683 }
684 lseek(elf_handle, sec[head.e_shstrndx].sh_offset, SEEK_SET);
685 read(elf_handle, names, sec[head.e_shstrndx].sh_size);
686 }
687
688
689 // Parsing the sections, and displaying them at the same time.
690 dprintf("##: type flags offset size link info align entsize name\n");
691 for (i = 1; i < head.e_shnum; i++) {
692 if (!strcmp(names + sec[i].sh_name, ".symtab")) {
693 symtab = i;
694 linked_strtab = sec[i].sh_link;
695 } else if (!strcmp(names + sec[i].sh_name, ".strtab")) {
696 strtab = i;
697 }
698
699 if ((sec[i].sh_type == PROGBITS) || (sec[i].sh_type == NOBITS)) {
700 // Let's use this, it's not filled for relocatable objects.
701 fullsize = align(fullsize, sec[i].sh_addralign);
702 sec[i].sh_addr = fullsize;
703 fullsize += sec[i].sh_size;
704 dprintf("Section to load at %08X:\n", sec[i].sh_addr);
705 }
706
707 dprintf("%2i: ", i);
708 if (sec[i].sh_type <= 0xff) {
709 rprintf("%-8s ", section_types[sec[i].sh_type]);
710 } else if (sec[i].sh_type == 0x70000006) {
711 rprintf("Reginfo ");
712 } else {
713 rprintf("UNKNOW ");
714 }
715
716 rprintf( "%3s ", section_flags[sec[i].sh_flags & 7]);
717 rprintf( "%08X ", sec[i].sh_offset);
718 rprintf( "%08X ", sec[i].sh_size);
719 rprintf( "%5i ", sec[i].sh_link);
720 rprintf( "%5i ", sec[i].sh_info);
721 rprintf( "%5i ", sec[i].sh_addralign);
722 rprintf("%5i ", sec[i].sh_entsize);
723 rprintf( "%s\n", names + sec[i].sh_name);
724 }
725
726 if (symtab) {
727 dprintf("Discovered symtab = %i\n", symtab);
728 } else {
729 dprintf("No symbol table.\n");
730 free_and_return(-1);
731 }
732
733 if (strtab) {
734 dprintf("Discovered strtab = %i\n", strtab);
735 } else {
736 dprintf("No string table.\n");
737 free_and_return(-1);
738 }
739
740 if (strtab != linked_strtab) {
741 dprintf("Warning, inconsistancy: strtab != symtab.sh_link (%i != %i)\n", strtab, linked_strtab);
742 free_and_return(-1);
743 }
744
745 if (sizeof(struct elf_symbol_t) != sec[symtab].sh_entsize) {
746 dprintf("Symbol entries not consistant.\n");
747 free_and_return(-1);
748 }
749
750 dprintf("Computed needed size to load the erl file: %i\n", fullsize);
751
752 // Loading progbits sections.
753 if (addr == ERL_DYN_ADDR) {
754 erl_record->bytes = (u8 *) malloc(fullsize);
755 if (!erl_record->bytes) {
756 dprintf("Cannot allocate ERL bytes.\n");
757 free_and_return(-1);
758 }
759 } else {
760 erl_record->bytes = (u8 *) addr;
761 erl_record->flags |= ERL_FLAG_STATIC;
762 }
763
764 erl_record->fullsize = fullsize;
765 dprintf("Base address: %08X\n", erl_record->bytes);
766 for (i = 1; i < head.e_shnum; i++) {
767 switch (sec[i].sh_type) {
768 case PROGBITS:
769 // **TODO** handle compession
770 dprintf("Reading section %s at %08X.\n", names + sec[i].sh_name, erl_record->bytes + sec[i].sh_addr);
771 if (elf_mem) {
772 memcpy(erl_record->bytes + sec[i].sh_addr, elf_mem + sec[i].sh_offset, sec[i].sh_size);
773 } else {
774 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
775 read(elf_handle, erl_record->bytes + sec[i].sh_addr, sec[i].sh_size);
776 }
777 break;
778 case NOBITS:
779 dprintf("Zeroing section %s at %08X.\n", names + sec[i].sh_name, erl_record->bytes + sec[i].sh_addr);
780 memset(erl_record->bytes + sec[i].sh_addr, 0, sec[i].sh_size);
781 break;
782 }
783 }
784
785
786 // Loading strtab.
787 // **TODO** handle compession
788 if (elf_mem) {
789 strtab_names = (char *) (elf_mem + sec[strtab].sh_offset);
790 } else {
791 if (!(strtab_names = (char *) malloc(sec[strtab].sh_size))) {
792 dprintf("Not enough memory.\n");
793 free_and_return(-1);
794 }
795 lseek(elf_handle, sec[strtab].sh_offset, SEEK_SET);
796 read(elf_handle, strtab_names, sec[strtab].sh_size);
797 }
798
799
800 // Loading symtab.
801 // **TODO** handle compession
802 if (elf_mem) {
803 sym = (struct elf_symbol_t *) (elf_mem + sec[symtab].sh_offset);
804 } else {
805 if (!(sym = (struct elf_symbol_t *) malloc(sec[symtab].sh_size))) {
806 dprintf("Not enough memory.\n");
807 free_and_return(-1);
808 }
809 lseek(elf_handle, sec[symtab].sh_offset, SEEK_SET);
810 read(elf_handle, sym, sec[symtab].sh_size);
811 }
812
813 // Parsing sections to find relocation sections.
814 for (i = 0; i < head.e_shnum; i++) {
815 if (sec[i].sh_type != REL && sec[i].sh_type != RELA)
816 continue;
817 dprintf("Section %i (%s) contains relocations for section %i (%s):\n",
818 i, names + sec[i].sh_name, sec[i].sh_info, names + sec[sec[i].sh_info].sh_name);
819
820 if (sec[i].sh_entsize != sizeof(struct elf_reloc_t) && sec[i].sh_entsize != sizeof(struct elf_rela_t)) {
821 dprintf("Warning: inconsistancy in relocation table.\n");
822 free_and_return(-1);
823 }
824
825 // Loading relocation section.
826 // **TODO** handle compession
827 if (elf_mem) {
828 reloc_section = (char *)(elf_mem + sec[i].sh_offset);
829 } else {
830 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
831 if (!(reloc_section = (char *) malloc(sec[i].sh_size))) {
832 dprintf("Not enough memory.\n");
833 free_and_return(-1);
834 }
835 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
836 read(elf_handle, reloc_section, sec[i].sh_size);
837 }
838
839 // We found one relocation section, let's parse it to relocate.
840 dprintf(" Num: Offset Type Symbol\n");
841 for (j = 0; (u32)j < (sec[i].sh_size / sec[i].sh_entsize); j++) {
842 int sym_n;
843
844 reloc = *((struct elf_reloc_t *) (reloc_section + j * sec[i].sh_entsize));
845
846 sym_n = reloc.r_info >> 8;
847 dprintf("%6i: %08X %-14s %3i: ", j, reloc.r_offset, reloc_types[reloc.r_info & 255], sym_n);
848
849 switch(sym[sym_n].st_info & 15) {
850 case NOTYPE:
851 rprintf("external symbol reloc to symbol %s\n", strtab_names + sym[sym_n].st_name);
852 if (!(s = erl_find_symbol(strtab_names + sym[sym_n].st_name))) {
853 printf("%s: Symbol not found, adding as loosy relocation.\n", strtab_names + sym[sym_n].st_name);
854 add_loosy(erl_record, erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, strtab_names + sym[sym_n].st_name);
855 } else {
856 dprintf("Found symbol at %08X, relocating.\n", s->address);
857 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, s->address) < 0) {
858 dprintf("Something went wrong in relocation.");
859 free_and_return(-1);
860 }
861 add_dependancy(erl_record, s->provider);
862 }
863 break;
864 case SECTION:
865 rprintf("internal section reloc to section %i (%s)\n", sym[sym_n].st_shndx, names + sec[sym[sym_n].st_shndx].sh_name);
866 dprintf("Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr);
867 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, (u32) (erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr)) < 0) {
868 dprintf("Something went wrong in relocation.");
869 free_and_return(-1);
870 }
871 break;
872 case OBJECT:
873 case FUNC:
874 rprintf("internal relocation to symbol %s\n", strtab_names + sym[sym_n].st_name);
875 if ((s = erl_find_symbol(strtab_names + sym[sym_n].st_name))) {
876 dprintf("Symbol already exists at %08X. Let's use it instead.\n", s->address);
877 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, s->address) < 0) {
878 dprintf("Something went wrong in relocation.");
879 free_and_return(-1);
880 }
881 add_dependancy(erl_record, s->provider);
882 } else {
883 dprintf("Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr + sym[sym_n].st_value);
884 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, (u32) (erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr + sym[sym_n].st_value)) < 0) {
885 dprintf("Something went wrong in relocation.");
886 free_and_return(-1);
887 }
888 }
889 break;
890 default:
891 rprintf("Unknown relocation. Bug inside.\n");
892 free_and_return(-1);
893 }
894 }
895 if (!elf_mem)
896 free(reloc_section);
897 }
898
899 dprintf(" Num: Value Size Type Bind Ndx Name\n");
900 for (i = 0; (u32)i < sec[symtab].sh_size / sec[symtab].sh_entsize; i++) {
901 if (((sym[i].st_info >> 4) == GLOBAL) || ((sym[i].st_info >> 4) == WEAK)) {
902 if ((sym[i].st_info & 15) != NOTYPE) {
903 dprintf("Export symbol:\n");
904 if (add_symbol(erl_record, strtab_names + sym[i].st_name, ((u32)erl_record->bytes) + sec[sym[i].st_shndx].sh_addr + sym[i].st_value) < 0) {
905 dprintf("Symbol probably already exists, let's ignore that.\n");
906// free_and_return(-1);
907 }
908 }
909 }
910
911 dprintf("%6i: %08X %08X %-7s %-6s %6i %-10s : %s\n", i,
912 sym[i].st_value, sym[i].st_size, symbol_types[sym[i].st_info & 15],
913 binding_types[sym[i].st_info >> 4], sym[i].st_shndx,
914 sym[i].st_name ? strtab_names + sym[i].st_name : "(null)",
915 sym[i].st_shndx ? names + sec[sym[i].st_shndx].sh_name : "(null)");
916 }
917
918#ifdef _EE
919 FlushCache(2);
920 FlushCache(0);
921#endif
922
923 *p_erl_record = erl_record;
924
925 free_and_return(0);
926}
927
928#ifndef O_BINARY
929#define O_BINARY 0
930#endif
931
932typedef int (*func_t)(void);
933typedef int (*start_t)(int argc, char ** argv);
934
935static struct erl_record_t * _init_load_erl_wrapper_from_file(char * erl_id) {
936 char tmpnam[256];
937 strcpy(tmpnam, erl_id);
938 strcat(tmpnam, ".erl");
939 return _init_load_erl_from_file(tmpnam, erl_id);
940}
941
942erl_loader_t _init_load_erl = _init_load_erl_wrapper_from_file;
943
944static struct erl_record_t * load_erl(const char * fname, u8 * elf_mem, u32 addr, int argc, char ** argv) {
945 struct erl_record_t * r;
946 struct symbol_t * s;
947 int elf_handle = 0;
948
949 dprintf("Reading ERL file.\n");
950
951 if (fname) {
952 if ((elf_handle = open(fname, O_RDONLY | O_BINARY)) < 0) {
953 dprintf("Error operning erl file: %s\n", fname);
954 return 0;
955 }
956 }
957
958 if (read_erl(elf_handle, elf_mem, addr, &r) < 0) {
959 dprintf("Error loading erl file.\n");
960 if (fname) {
961 close(elf_handle);
962 }
963 return 0;
964 }
965
966 if (fname) {
967 close(elf_handle);
968 }
969
970 if ((s = erl_find_local_symbol("erl_id", r))) {
971 r->name = *(char **) s->address;
972 } else {
973 r->name = 0;
974 }
975
976 dprintf("erl_id = %08X.\n", r->name);
977
978 if ((s = erl_find_local_symbol("erl_dependancies", r))) {
979 r->dependancies = (char **) s->address;
980 } else {
981 r->dependancies = 0;
982 }
983
984 dprintf("erl_dependancies = %08X.\n", r->dependancies);
985
986 if (r->dependancies) {
987 char ** d;
988 for (d = r->dependancies; *d; d++) {
989 dprintf("Loading dependancy: %s.\n", *d);
990 _init_load_erl(*d);
991 }
992 }
993
994 if ((s = erl_find_local_symbol("_init", r))) {
995 dprintf("_init = %08X\n", s->address);
996#ifdef _EE
997 ((func_t)s->address)();
998#endif
999 }
1000
1001 if ((s = erl_find_local_symbol("_start", r))) {
1002 dprintf("_start = %08X\n", s->address);
1003#ifdef _EE
1004 int _start_ret;
1005 if ((_start_ret = ((start_t)s->address)(argc, argv))) {
1006 dprintf("Module's _start returned %i, unloading module.\n", _start_ret);
1007 if (unload_erl(r))
1008 return 0;
1009 }
1010#endif
1011 }
1012
1013 return r;
1014}
1015
1016struct erl_record_t * _init_load_erl_from_file(const char * fname, char * erl_id) {
1017 char tfname[1024];
1018 char * argv[2];
1019
1020 if (erl_id) {
1021 struct erl_record_t * r;
1022 if ((r = find_erl(erl_id)))
1023 return r;
1024 }
1025
1026 argv[0] = erl_id;
1027 argv[1] = 0;
1028
1029 strcpy(tfname, _init_erl_prefix);
1030 strcat(tfname, fname);
1031
1032 return load_erl_from_file(tfname, 1, argv);
1033}
1034
1035struct erl_record_t * load_erl_from_file(const char * fname, int argc, char ** argv) {
1036 return load_erl(fname, 0, ERL_DYN_ADDR, argc, argv);
1037}
1038
1039struct erl_record_t * load_erl_from_mem(u8 * mem, int argc, char ** argv) {
1040 return load_erl(0, mem, ERL_DYN_ADDR, argc, argv);
1041}
1042
1043/*
1044 * Load ERL from memory and relocate it at a specific memory address.
1045 */
1046struct erl_record_t * load_erl_from_mem_to_addr(u8 * mem, u32 addr, int argc, char ** argv) {
1047 return load_erl(0, mem, addr, argc, argv);
1048}
1049
1050/*
1051 * Load ERL from file and relocate it at a specific memory address.
1052 */
1053struct erl_record_t * load_erl_from_file_to_addr(const char * fname, u32 addr, int argc, char ** argv) {
1054 return load_erl(fname, 0, addr, argc, argv);
1055}
1056
1057/*
1058 * Load ERL from file and relocate it at a specific memory address. Prepend _init_erl_prefix to filename.
1059 */
1060struct erl_record_t * _init_load_erl_from_file_to_addr(const char * fname, u32 addr, char * erl_id) {
1061 char tfname[1024];
1062 char * argv[2];
1063
1064 if (erl_id) {
1065 struct erl_record_t * r;
1066 if ((r = find_erl(erl_id)))
1067 return r;
1068 }
1069
1070 argv[0] = erl_id;
1071 argv[1] = 0;
1072
1073 strcpy(tfname, _init_erl_prefix);
1074 strcat(tfname, fname);
1075
1076 return load_erl_from_file_to_addr(tfname, addr, 1, argv);
1077}
1078
1079void r_unload_dependancies(char ** d) {
1080 struct erl_record_t * erl;
1081 if (!(*d))
1082 return;
1083
1084 r_unload_dependancies(d + 1);
1085
1086 if ((erl = find_erl(*d)))
1087 unload_erl(erl);
1088}
1089
1090int unload_erl(struct erl_record_t * erl) {
1091 struct symbol_t * s;
1092 struct dependancy_t * p;
1093
1094 dprintf("Unloading module %s.\n", erl->name ? erl->name : "(noname)");
1095
1096 if ((erl->flags) & ERL_FLAG_STICKY) {
1097 dprintf("Module is sticky, won't unload.\n");
1098 return 0;
1099 }
1100
1101 for (p = dependancy_root; p; p = p->next) {
1102 if (p->provider == erl) {
1103 dprintf("Other modules depend on it, won't unload.\n");
1104 return 0;
1105 }
1106 }
1107
1108 if ((s = erl_find_local_symbol("_fini", erl))) {
1109 dprintf("_fini = %08X\n", s->address);
1110#ifdef _EE
1111 ((func_t)s->address)();
1112#endif
1113 }
1114
1115 if (erl->dependancies)
1116 r_unload_dependancies(erl->dependancies);
1117
1118 erl_flush_symbols(erl);
1119
1120 destroy_dependancy_r(erl);
1121
1122 destroy_erl_record(erl);
1123
1124 return 1;
1125}
1126
1127struct erl_record_t * erl_resolve(u32 address) {
1128 struct erl_record_t * r;
1129
1130 for (r = erl_record_root; r; r = r->next) {
1131 u32 r_ptr = (u32) r->bytes;
1132 if ((address >= r_ptr) && (address < (r_ptr + r->fullsize)))
1133 return r;
1134 }
1135
1136 return 0;
1137}
1138
1139struct erl_record_t * find_erl(const char * name) {
1140 struct erl_record_t * r;
1141
1142 for (r = erl_record_root; r; r = r->next) {
1143 if (r->name)
1144 if (!strcmp(name, r->name))
1145 return r;
1146 }
1147
1148 return 0;
1149}
1150
1151void erl_flush_symbols(struct erl_record_t * erl) {
1152 if (!erl->symbols)
1153 return;
1154
1155 if (hfirst(erl->symbols)) do {
1156 destroy_symbol((struct symbol_t *) hstuff(erl->symbols));
1157 free(hkey(erl->symbols));
1158 hdel(erl->symbols);
1159 } while (hcount(erl->symbols));
1160
1161 hdestroy(erl->symbols);
1162
1163 erl->symbols = 0;
1164}
1165
1166#ifdef STANDALONE
1167
1168int main(int argc, char *argv[]) {
1169 struct erl_record_t * erl;
1170 char * fname;
1171
1172 erl_add_global_symbol("printf", (u32) printf);
1173
1174 if (argc == 2) {
1175 fname = argv[1];
1176 } else {
1177 fname = "host:hello-erl.erl";
1178 }
1179
1180 if (!(erl = load_erl_from_file(fname))) {
1181 dprintf("Error while loading erl file.\n");
1182 return -1;
1183 }
1184
1185 return 0;
1186}
1187
1188#endif
Definition erl.c:266
#define ERL_FLAG_CLEAR
Definition erl.h:28
#define ERL_FLAG_STATIC
Definition erl.h:26
#define ERL_FLAG_STICKY
Definition erl.h:24
Definition erl.h:42
Definition hashtab.h:56
Definition main.c:242
u32 count
start sector of fragmented bd/file