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