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) && !(u_current_data & 0xf)? 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, next_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 u32 addend = 0;
596
597 int has_next_reloc = 0;
598
599 *p_erl_record = 0;
600
601#define free_and_return(code) if (!elf_mem) { \
602 if (names) free(names); \
603 if (strtab_names) free(strtab_names); \
604 if (sec) free(sec); \
605 if (sym) free(sym); \
606 if ((code < 0) && erl_record) destroy_erl_record(erl_record); \
607} \
608return code
609
610 if (!(erl_record = allocate_erl_record())) {
611 dprintf("Memory allocation error.\n");
612 free_and_return(-1);
613 }
614
615 // Reading the main ELF header.
616 if (elf_mem) {
617 memcpy(&head, elf_mem, sizeof(head));
618 } else {
619 lseek(elf_handle, 0, SEEK_SET);
620 read(elf_handle, &head, sizeof(head));
621 }
622
623 magic = head.e_ident.cook.ei_magic;
624
625 if ((magic[0] != 0x7f) || (magic[1] != 'E') || (magic[2] != 'L') || ((magic[3] != 'F') && (magic[3] != 'X'))) {
626 dprintf("Not an ELF file.\n");
627 free_and_return(-1);
628 }
629
630 // erx_compressed = magic[3] == 'X'; //not used
631
632 dprintf("ELF Class : %s\n", elf_classes[head.e_ident.cook.ei_class]);
633 dprintf("Data encoding: %s\n", elf_encodings[head.e_ident.cook.ei_data]);
634 dprintf("Elf version : %i\n", head.e_ident.cook.ei_version);
635 if (head.e_type == 0xffff) {
636 dprintf("Object type : Processor specific (hi)\n");
637 } else if (head.e_type == 0xff00) {
638 dprintf("Object type : Processor specific (lo)\n");
639 } else {
640 dprintf("Object type : %s\n", elf_types[head.e_type]);
641 }
642 dprintf("Machine type : %s\n", elf_machines[head.e_machine]);
643 dprintf("Object ver. : %i\n", head.e_version);
644 dprintf("Elf entry : %08X\n", head.e_entry);
645 dprintf("PH offset : %08X\n", head.e_phoff);
646 dprintf("SH offset : %08X\n", head.e_shoff);
647 dprintf("Flags : %08X\n", head.e_flags);
648 dprintf("Header size : %04X\n", head.e_ehsize);
649 dprintf("PH ent. size : %04X\n", head.e_phentsize);
650 dprintf("PH number : %04X\n", head.e_phnum);
651 dprintf("SH ent. size : %04X\n", head.e_shentsize);
652 dprintf("SH number : %04X\n", head.e_shnum);
653 dprintf("SH str index : %04X\n", head.e_shstrndx);
654
655 if (head.e_type != REL_TYPE) {
656 dprintf("File isn't a relocatable ELF file.\n");
657 free_and_return(-1);
658 }
659
660 // Reading the section table.
661 if (sizeof(struct elf_section_t) != head.e_shentsize) {
662 dprintf("Inconsistancy in section table entries.\n");
663 free_and_return(-1);
664 }
665
666 // **TODO** handle compession
667 if (elf_mem) {
668 sec = (struct elf_section_t *) (elf_mem + head.e_shoff);
669 } else {
670 if (!(sec = (struct elf_section_t *) malloc(sizeof(struct elf_section_t) * head.e_shnum))) {
671 dprintf("Not enough memory.\n");
672 free_and_return(-1);
673 }
674 lseek(elf_handle, head.e_shoff, SEEK_SET);
675 read(elf_handle, sec, sizeof(struct elf_section_t) * head.e_shnum);
676 }
677
678 // Reading the section names's table.
679 // **TODO** handle compession
680 if (elf_mem) {
681 names = (char *) (elf_mem + sec[head.e_shstrndx].sh_offset);
682 } else {
683 if (!(names = (char *) malloc(sec[head.e_shstrndx].sh_size))) {
684 dprintf("Not enough memory.\n");
685 free_and_return(-1);
686 }
687 lseek(elf_handle, sec[head.e_shstrndx].sh_offset, SEEK_SET);
688 read(elf_handle, names, sec[head.e_shstrndx].sh_size);
689 }
690
691
692 // Parsing the sections, and displaying them at the same time.
693 dprintf("##: type flags offset size link info align entsize name\n");
694 for (i = 1; i < head.e_shnum; i++) {
695 if (!strcmp(names + sec[i].sh_name, ".symtab")) {
696 symtab = i;
697 linked_strtab = sec[i].sh_link;
698 } else if (!strcmp(names + sec[i].sh_name, ".strtab")) {
699 strtab = i;
700 }
701
702 if ((sec[i].sh_type == PROGBITS) || (sec[i].sh_type == NOBITS)) {
703 // Let's use this, it's not filled for relocatable objects.
704 fullsize = align(fullsize, sec[i].sh_addralign);
705 sec[i].sh_addr = fullsize;
706 fullsize += sec[i].sh_size;
707 dprintf("Section to load at %08X:\n", sec[i].sh_addr);
708 }
709
710 dprintf("%2i: ", i);
711 if (sec[i].sh_type <= 0xff) {
712 rprintf("%-8s ", section_types[sec[i].sh_type]);
713 } else if (sec[i].sh_type == 0x70000006) {
714 rprintf("Reginfo ");
715 } else {
716 rprintf("UNKNOW ");
717 }
718
719 rprintf( "%3s ", section_flags[sec[i].sh_flags & 7]);
720 rprintf( "%08X ", sec[i].sh_offset);
721 rprintf( "%08X ", sec[i].sh_size);
722 rprintf( "%5i ", sec[i].sh_link);
723 rprintf( "%5i ", sec[i].sh_info);
724 rprintf( "%5i ", sec[i].sh_addralign);
725 rprintf("%5i ", sec[i].sh_entsize);
726 rprintf( "%s\n", names + sec[i].sh_name);
727 }
728
729 if (symtab) {
730 dprintf("Discovered symtab = %i\n", symtab);
731 } else {
732 dprintf("No symbol table.\n");
733 free_and_return(-1);
734 }
735
736 if (strtab) {
737 dprintf("Discovered strtab = %i\n", strtab);
738 } else {
739 dprintf("No string table.\n");
740 free_and_return(-1);
741 }
742
743 if (strtab != linked_strtab) {
744 dprintf("Warning, inconsistancy: strtab != symtab.sh_link (%i != %i)\n", strtab, linked_strtab);
745 free_and_return(-1);
746 }
747
748 if (sizeof(struct elf_symbol_t) != sec[symtab].sh_entsize) {
749 dprintf("Symbol entries not consistant.\n");
750 free_and_return(-1);
751 }
752
753 dprintf("Computed needed size to load the erl file: %i\n", fullsize);
754
755 // Loading progbits sections.
756 if (addr == ERL_DYN_ADDR) {
757 erl_record->bytes = (u8 *) malloc(fullsize);
758 if (!erl_record->bytes) {
759 dprintf("Cannot allocate ERL bytes.\n");
760 free_and_return(-1);
761 }
762 } else {
763 erl_record->bytes = (u8 *) addr;
764 erl_record->flags |= ERL_FLAG_STATIC;
765 }
766
767 erl_record->fullsize = fullsize;
768 dprintf("Base address: %08X\n", erl_record->bytes);
769 for (i = 1; i < head.e_shnum; i++) {
770 switch (sec[i].sh_type) {
771 case PROGBITS:
772 // **TODO** handle compession
773 dprintf("Reading section %s at %08X.\n", names + sec[i].sh_name, erl_record->bytes + sec[i].sh_addr);
774 if (elf_mem) {
775 memcpy(erl_record->bytes + sec[i].sh_addr, elf_mem + sec[i].sh_offset, sec[i].sh_size);
776 } else {
777 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
778 read(elf_handle, erl_record->bytes + sec[i].sh_addr, sec[i].sh_size);
779 }
780 break;
781 case NOBITS:
782 dprintf("Zeroing section %s at %08X.\n", names + sec[i].sh_name, erl_record->bytes + sec[i].sh_addr);
783 memset(erl_record->bytes + sec[i].sh_addr, 0, sec[i].sh_size);
784 break;
785 }
786 }
787
788
789 // Loading strtab.
790 // **TODO** handle compession
791 if (elf_mem) {
792 strtab_names = (char *) (elf_mem + sec[strtab].sh_offset);
793 } else {
794 if (!(strtab_names = (char *) malloc(sec[strtab].sh_size))) {
795 dprintf("Not enough memory.\n");
796 free_and_return(-1);
797 }
798 lseek(elf_handle, sec[strtab].sh_offset, SEEK_SET);
799 read(elf_handle, strtab_names, sec[strtab].sh_size);
800 }
801
802
803 // Loading symtab.
804 // **TODO** handle compession
805 if (elf_mem) {
806 sym = (struct elf_symbol_t *) (elf_mem + sec[symtab].sh_offset);
807 } else {
808 if (!(sym = (struct elf_symbol_t *) malloc(sec[symtab].sh_size))) {
809 dprintf("Not enough memory.\n");
810 free_and_return(-1);
811 }
812 lseek(elf_handle, sec[symtab].sh_offset, SEEK_SET);
813 read(elf_handle, sym, sec[symtab].sh_size);
814 }
815
816 // Parsing sections to find relocation sections.
817 for (i = 0; i < head.e_shnum; i++) {
818 if (sec[i].sh_type != REL && sec[i].sh_type != RELA)
819 continue;
820 dprintf("Section %i (%s) contains relocations for section %i (%s):\n",
821 i, names + sec[i].sh_name, sec[i].sh_info, names + sec[sec[i].sh_info].sh_name);
822
823 if (sec[i].sh_entsize != sizeof(struct elf_reloc_t) && sec[i].sh_entsize != sizeof(struct elf_rela_t)) {
824 dprintf("Warning: inconsistancy in relocation table.\n");
825 free_and_return(-1);
826 }
827
828 // Loading relocation section.
829 // **TODO** handle compession
830 if (elf_mem) {
831 reloc_section = (char *)(elf_mem + sec[i].sh_offset);
832 } else {
833 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
834 if (!(reloc_section = (char *) malloc(sec[i].sh_size))) {
835 dprintf("Not enough memory.\n");
836 free_and_return(-1);
837 }
838 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
839 read(elf_handle, reloc_section, sec[i].sh_size);
840 }
841
842 // We found one relocation section, let's parse it to relocate.
843 dprintf(" Num: Offset Type Symbol\n");
844 for (j = 0; (u32)j < (sec[i].sh_size / sec[i].sh_entsize); j++) {
845 int sym_n, next_sym_n;
846
847 addend = (sec[i].sh_type == RELA? ((struct elf_rela_t *)(reloc_section + j * sec[i].sh_entsize))->r_addend : 0);
848
849 reloc = *((struct elf_reloc_t *) (reloc_section + j * sec[i].sh_entsize));
850
851 sym_n = reloc.r_info >> 8;
852
853 has_next_reloc = 0;
854 if ((u32)j+1 < (sec[i].sh_size / sec[i].sh_entsize)) {
855 next_reloc = *((struct elf_reloc_t *) (reloc_section + ((j+1) * sec[i].sh_entsize)));
856 next_sym_n = reloc.r_info >> 8;
857 has_next_reloc = 1;
858 }
859
860 dprintf("%6i: %08X %-14s %3i: ", j, reloc.r_offset, reloc_types[reloc.r_info & 255], sym_n);
861
862 switch(sym[sym_n].st_info & 15) {
863 case NOTYPE:
864 rprintf("external symbol reloc to symbol %s\n", strtab_names + sym[sym_n].st_name);
865 if (!(s = erl_find_symbol(strtab_names + sym[sym_n].st_name))) {
866 printf("%s: Symbol not found, adding as loosy relocation.\n", strtab_names + sym[sym_n].st_name);
867 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);
868 } else {
869 dprintf("Found symbol at %08X, relocating.\n", s->address);
870 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, s->address+addend) < 0) {
871 dprintf("Something went wrong in relocation.");
872 free_and_return(-1);
873 }
874 add_dependancy(erl_record, s->provider);
875 }
876 break;
877 case SECTION:
878 rprintf("internal section reloc to section %i (%s)\n", sym[sym_n].st_shndx, names + sec[sym[sym_n].st_shndx].sh_name);
879 dprintf("Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr);
880
881 if ((reloc.r_info & 255) == R_MIPS_HI16 &&
882 (has_next_reloc && ((next_reloc.r_info & 255) == R_MIPS_LO16)) &&
883 (sec[sym[sym_n].st_shndx].sh_addr == sec[sym[next_sym_n].st_shndx].sh_addr) &&
884 (*(u16*)(erl_record->bytes + sec[sec[i].sh_info].sh_addr + next_reloc.r_offset) + (((u32) (erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr)+addend) & 0x0000ffff)) >= 0x8000
885 ) {
886 u32 data = *(u32*)(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset);
887 *(u32*)(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset) = data + !(data & 0xf);
888 }
889
890 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)+addend) < 0) {
891 dprintf("Something went wrong in relocation.");
892 free_and_return(-1);
893 }
894 break;
895 case OBJECT:
896 case FUNC:
897 rprintf("internal relocation to symbol %s\n", strtab_names + sym[sym_n].st_name);
898 if ((s = erl_find_symbol(strtab_names + sym[sym_n].st_name))) {
899 dprintf("Symbol already exists at %08X. Let's use it instead.\n", s->address);
900 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, s->address+addend) < 0) {
901 dprintf("Something went wrong in relocation.");
902 free_and_return(-1);
903 }
904 add_dependancy(erl_record, s->provider);
905 } else {
906 dprintf("Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr + sym[sym_n].st_value);
907 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)+addend) < 0) {
908 dprintf("Something went wrong in relocation.");
909 free_and_return(-1);
910 }
911 }
912 break;
913 default:
914 rprintf("Unknown relocation. Bug inside.\n");
915 free_and_return(-1);
916 }
917 }
918 if (!elf_mem)
919 free(reloc_section);
920 }
921
922 dprintf(" Num: Value Size Type Bind Ndx Name\n");
923 for (i = 0; (u32)i < sec[symtab].sh_size / sec[symtab].sh_entsize; i++) {
924 if (((sym[i].st_info >> 4) == GLOBAL) || ((sym[i].st_info >> 4) == WEAK)) {
925 if ((sym[i].st_info & 15) != NOTYPE) {
926 dprintf("Export symbol:\n");
927 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) {
928 dprintf("Symbol probably already exists, let's ignore that.\n");
929// free_and_return(-1);
930 }
931 }
932 }
933
934 dprintf("%6i: %08X %08X %-7s %-6s %6i %-10s : %s\n", i,
935 sym[i].st_value, sym[i].st_size, symbol_types[sym[i].st_info & 15],
936 binding_types[sym[i].st_info >> 4], sym[i].st_shndx,
937 sym[i].st_name ? strtab_names + sym[i].st_name : "(null)",
938 sym[i].st_shndx ? names + sec[sym[i].st_shndx].sh_name : "(null)");
939 }
940
941#ifdef _EE
942 FlushCache(2);
943 FlushCache(0);
944#endif
945
946 *p_erl_record = erl_record;
947
948 free_and_return(0);
949}
950
951#ifndef O_BINARY
952#define O_BINARY 0
953#endif
954
955typedef int (*func_t)(void);
956typedef int (*start_t)(int argc, char ** argv);
957
958static struct erl_record_t * _init_load_erl_wrapper_from_file(char * erl_id) {
959 char tmpnam[256];
960 strcpy(tmpnam, erl_id);
961 strcat(tmpnam, ".erl");
962 return _init_load_erl_from_file(tmpnam, erl_id);
963}
964
965erl_loader_t _init_load_erl = _init_load_erl_wrapper_from_file;
966
967static struct erl_record_t * load_erl(const char * fname, u8 * elf_mem, u32 addr, int argc, char ** argv) {
968 struct erl_record_t * r;
969 struct symbol_t * s;
970 int elf_handle = 0;
971
972 dprintf("Reading ERL file.\n");
973
974 if (fname) {
975 if ((elf_handle = open(fname, O_RDONLY | O_BINARY)) < 0) {
976 dprintf("Error operning erl file: %s\n", fname);
977 return 0;
978 }
979 }
980
981 if (read_erl(elf_handle, elf_mem, addr, &r) < 0) {
982 dprintf("Error loading erl file.\n");
983 if (fname) {
984 close(elf_handle);
985 }
986 return 0;
987 }
988
989 if (fname) {
990 close(elf_handle);
991 }
992
993 if ((s = erl_find_local_symbol("erl_id", r))) {
994 r->name = *(char **) s->address;
995 } else {
996 r->name = 0;
997 }
998
999 dprintf("erl_id = %08X.\n", r->name);
1000
1001 if ((s = erl_find_local_symbol("erl_dependancies", r))) {
1002 r->dependancies = (char **) s->address;
1003 } else {
1004 r->dependancies = 0;
1005 }
1006
1007 dprintf("erl_dependancies = %08X.\n", r->dependancies);
1008
1009 if (r->dependancies) {
1010 char ** d;
1011 for (d = r->dependancies; *d; d++) {
1012 dprintf("Loading dependancy: %s.\n", *d);
1013 _init_load_erl(*d);
1014 }
1015 }
1016
1017 if ((s = erl_find_local_symbol("_init", r))) {
1018 dprintf("_init = %08X\n", s->address);
1019#ifdef _EE
1020 ((func_t)s->address)();
1021#endif
1022 }
1023
1024 if ((s = erl_find_local_symbol("_start", r))) {
1025 dprintf("_start = %08X\n", s->address);
1026#ifdef _EE
1027 int _start_ret;
1028 if ((_start_ret = ((start_t)s->address)(argc, argv))) {
1029 dprintf("Module's _start returned %i, unloading module.\n", _start_ret);
1030 if (unload_erl(r))
1031 return 0;
1032 }
1033#endif
1034 }
1035
1036 return r;
1037}
1038
1039struct erl_record_t * _init_load_erl_from_file(const char * fname, char * erl_id) {
1040 char tfname[1024];
1041 char * argv[2];
1042
1043 if (erl_id) {
1044 struct erl_record_t * r;
1045 if ((r = find_erl(erl_id)))
1046 return r;
1047 }
1048
1049 argv[0] = erl_id;
1050 argv[1] = 0;
1051
1052 strcpy(tfname, _init_erl_prefix);
1053 strcat(tfname, fname);
1054
1055 return load_erl_from_file(tfname, 1, argv);
1056}
1057
1058struct erl_record_t * load_erl_from_file(const char * fname, int argc, char ** argv) {
1059 return load_erl(fname, 0, ERL_DYN_ADDR, argc, argv);
1060}
1061
1062struct erl_record_t * load_erl_from_mem(u8 * mem, int argc, char ** argv) {
1063 return load_erl(0, mem, ERL_DYN_ADDR, argc, argv);
1064}
1065
1066/*
1067 * Load ERL from memory and relocate it at a specific memory address.
1068 */
1069struct erl_record_t * load_erl_from_mem_to_addr(u8 * mem, u32 addr, int argc, char ** argv) {
1070 return load_erl(0, mem, addr, argc, argv);
1071}
1072
1073/*
1074 * Load ERL from file and relocate it at a specific memory address.
1075 */
1076struct erl_record_t * load_erl_from_file_to_addr(const char * fname, u32 addr, int argc, char ** argv) {
1077 return load_erl(fname, 0, addr, argc, argv);
1078}
1079
1080/*
1081 * Load ERL from file and relocate it at a specific memory address. Prepend _init_erl_prefix to filename.
1082 */
1083struct erl_record_t * _init_load_erl_from_file_to_addr(const char * fname, u32 addr, char * erl_id) {
1084 char tfname[1024];
1085 char * argv[2];
1086
1087 if (erl_id) {
1088 struct erl_record_t * r;
1089 if ((r = find_erl(erl_id)))
1090 return r;
1091 }
1092
1093 argv[0] = erl_id;
1094 argv[1] = 0;
1095
1096 strcpy(tfname, _init_erl_prefix);
1097 strcat(tfname, fname);
1098
1099 return load_erl_from_file_to_addr(tfname, addr, 1, argv);
1100}
1101
1102void r_unload_dependancies(char ** d) {
1103 struct erl_record_t * erl;
1104 if (!(*d))
1105 return;
1106
1107 r_unload_dependancies(d + 1);
1108
1109 if ((erl = find_erl(*d)))
1110 unload_erl(erl);
1111}
1112
1113int unload_erl(struct erl_record_t * erl) {
1114 struct symbol_t * s;
1115 struct dependancy_t * p;
1116
1117 dprintf("Unloading module %s.\n", erl->name ? erl->name : "(noname)");
1118
1119 if ((erl->flags) & ERL_FLAG_STICKY) {
1120 dprintf("Module is sticky, won't unload.\n");
1121 return 0;
1122 }
1123
1124 for (p = dependancy_root; p; p = p->next) {
1125 if (p->provider == erl) {
1126 dprintf("Other modules depend on it, won't unload.\n");
1127 return 0;
1128 }
1129 }
1130
1131 if ((s = erl_find_local_symbol("_fini", erl))) {
1132 dprintf("_fini = %08X\n", s->address);
1133#ifdef _EE
1134 ((func_t)s->address)();
1135#endif
1136 }
1137
1138 if (erl->dependancies)
1139 r_unload_dependancies(erl->dependancies);
1140
1141 erl_flush_symbols(erl);
1142
1143 destroy_dependancy_r(erl);
1144
1145 destroy_erl_record(erl);
1146
1147 return 1;
1148}
1149
1150struct erl_record_t * erl_resolve(u32 address) {
1151 struct erl_record_t * r;
1152
1153 for (r = erl_record_root; r; r = r->next) {
1154 u32 r_ptr = (u32) r->bytes;
1155 if ((address >= r_ptr) && (address < (r_ptr + r->fullsize)))
1156 return r;
1157 }
1158
1159 return 0;
1160}
1161
1162struct erl_record_t * find_erl(const char * name) {
1163 struct erl_record_t * r;
1164
1165 for (r = erl_record_root; r; r = r->next) {
1166 if (r->name)
1167 if (!strcmp(name, r->name))
1168 return r;
1169 }
1170
1171 return 0;
1172}
1173
1174void erl_flush_symbols(struct erl_record_t * erl) {
1175 if (!erl->symbols)
1176 return;
1177
1178 if (hfirst(erl->symbols)) do {
1179 destroy_symbol((struct symbol_t *) hstuff(erl->symbols));
1180 free(hkey(erl->symbols));
1181 hdel(erl->symbols);
1182 } while (hcount(erl->symbols));
1183
1184 hdestroy(erl->symbols);
1185
1186 erl->symbols = 0;
1187}
1188
1189#ifdef STANDALONE
1190
1191int main(int argc, char *argv[]) {
1192 struct erl_record_t * erl;
1193 char * fname;
1194
1195 erl_add_global_symbol("printf", (u32) printf);
1196
1197 if (argc == 2) {
1198 fname = argv[1];
1199 } else {
1200 fname = "host:hello-erl.erl";
1201 }
1202
1203 if (!(erl = load_erl_from_file(fname))) {
1204 dprintf("Error while loading erl file.\n");
1205 return -1;
1206 }
1207
1208 return 0;
1209}
1210
1211#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