PS2SDK
PS2 Homebrew Libraries
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
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 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 
206 static const char * const 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 
220 struct 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 
250 struct elf_symbol_t {
251  u32 st_name, st_value, st_size;
252  u8 st_info, st_other;
253  u16 st_shndx;
254 };
255 
256 struct elf_reloc_t {
257  u32 r_offset, r_info;
258 };
259 
260 struct elf_rela_t {
261  u32 r_offset, r_info, r_addend;
262 };
263 
264 /* Our internal structures. */
265 
266 struct loosy_t {
267  u8 * reloc;
268  int type;
269  struct loosy_t * next;
270  struct erl_record_t * erl;
271 };
272 
273 struct dependancy_t {
274  struct erl_record_t * depender, * provider;
275  struct dependancy_t * next, * prev;
276 };
277 
278 
279 /* And our global variables. */
280 static struct erl_record_t * erl_record_root = 0;
281 
282 static htab * global_symbols = 0;
283 static htab * loosy_relocs = 0;
284 
285 char _init_erl_prefix[256] = "";
286 
287 static struct dependancy_t * dependancy_root = 0;
288 
289 
290 static 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 
306 static 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 
320 static void destroy_loosy(struct loosy_t * l) {
321  free(l);
322 }
323 
324 static 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 
333 static reroot * symbol_recycle = 0;
334 
335 static 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 
349 static void destroy_symbol(struct symbol_t * s) {
350  redel(symbol_recycle, s);
351 }
352 
353 static 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 
372 static 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 
396 static 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 
431 struct 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 
439 static 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 
447 struct 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 
454 static 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 
475 static 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 
487 static 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 
499 static void destroy_dependancy_r(struct erl_record_t * erl) {
500  r_destroy_dependancy_r(erl, dependancy_root);
501 }
502 
503 static 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) = strdup(symbol);
516  }
517 }
518 
519 static 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((void *)hkey(loosy_relocs));
534  hdel(loosy_relocs);
535  }
536 
537  return count;
538 }
539 
540 static int is_local(const char * symbol) {
541  const char * const * p;
542 
543  for (p = local_names; *p; p++)
544  if (!strcmp(*p, symbol))
545  return 1;
546 
547  return 0;
548 }
549 
550 static 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 
578 int erl_add_global_symbol(const char * symbol, u32 address) {
579  return add_symbol(0, symbol, address);
580 }
581 
582 static 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 } \
608 return 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 
955 typedef int (*func_t)(void);
956 typedef int (*start_t)(int argc, char ** argv);
957 
958 static struct erl_record_t * _init_load_erl_wrapper_from_file(char * erl_id) {
959  char tmpnam[256];
960  snprintf(tmpnam, sizeof(tmpnam), "%s.erl", erl_id);
961  return _init_load_erl_from_file(tmpnam, erl_id);
962 }
963 
964 erl_loader_t _init_load_erl;
965 
966 static struct erl_record_t * load_erl(const char * fname, u8 * elf_mem, u32 addr, int argc, char ** argv) {
967  struct erl_record_t * r;
968  struct symbol_t * s;
969  int elf_handle = 0;
970 
971  dprintf("Reading ERL file.\n");
972 
973  if (fname) {
974  if ((elf_handle = open(fname, O_RDONLY | O_BINARY)) < 0) {
975  dprintf("Error operning erl file: %s\n", fname);
976  return 0;
977  }
978  }
979 
980  if (read_erl(elf_handle, elf_mem, addr, &r) < 0) {
981  dprintf("Error loading erl file.\n");
982  if (fname) {
983  close(elf_handle);
984  }
985  return 0;
986  }
987 
988  if (fname) {
989  close(elf_handle);
990  }
991 
992  if ((s = erl_find_local_symbol("erl_id", r))) {
993  r->name = *(char **) s->address;
994  } else {
995  r->name = 0;
996  }
997 
998  dprintf("erl_id = %08X.\n", r->name);
999 
1000  if ((s = erl_find_local_symbol("erl_dependancies", r))) {
1001  r->dependancies = (char **) s->address;
1002  } else {
1003  r->dependancies = 0;
1004  }
1005 
1006  dprintf("erl_dependancies = %08X.\n", r->dependancies);
1007 
1008  if (r->dependancies) {
1009  if (!_init_load_erl)
1010  _init_load_erl = _init_load_erl_wrapper_from_file;
1011  char ** d;
1012  for (d = r->dependancies; *d; d++) {
1013  dprintf("Loading dependancy: %s.\n", *d);
1014  _init_load_erl(*d);
1015  }
1016  }
1017 
1018  if ((s = erl_find_local_symbol("_init", r))) {
1019  dprintf("_init = %08X\n", s->address);
1020 #ifdef _EE
1021  ((func_t)s->address)();
1022 #endif
1023  }
1024 
1025  if ((s = erl_find_local_symbol("_start", r))) {
1026  dprintf("_start = %08X\n", s->address);
1027 #ifdef _EE
1028  int _start_ret;
1029  if ((_start_ret = ((start_t)s->address)(argc, argv))) {
1030  dprintf("Module's _start returned %i, unloading module.\n", _start_ret);
1031  if (unload_erl(r))
1032  return 0;
1033  }
1034 #endif
1035  }
1036 
1037  return r;
1038 }
1039 
1040 struct erl_record_t * _init_load_erl_from_file(const char * fname, char * erl_id) {
1041  char tfname[1024];
1042  char * argv[2];
1043 
1044  if (erl_id) {
1045  struct erl_record_t * r;
1046  if ((r = find_erl(erl_id)))
1047  return r;
1048  }
1049 
1050  argv[0] = erl_id;
1051  argv[1] = 0;
1052 
1053  snprintf(tfname, sizeof(tfname), "%.*s%s", sizeof(_init_erl_prefix), _init_erl_prefix, fname);
1054 
1055  return load_erl_from_file(tfname, 1, argv);
1056 }
1057 
1058 struct 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 
1062 struct 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  */
1069 struct 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  */
1076 struct 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  */
1083 struct 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  snprintf(tfname, sizeof(tfname), "%.*s%s", sizeof(_init_erl_prefix), _init_erl_prefix, fname);
1097 
1098  return load_erl_from_file_to_addr(tfname, addr, 1, argv);
1099 }
1100 
1101 void r_unload_dependancies(char ** d) {
1102  struct erl_record_t * erl;
1103  if (!(*d))
1104  return;
1105 
1106  r_unload_dependancies(d + 1);
1107 
1108  if ((erl = find_erl(*d)))
1109  unload_erl(erl);
1110 }
1111 
1112 int unload_erl(struct erl_record_t * erl) {
1113  struct symbol_t * s;
1114  struct dependancy_t * p;
1115 
1116  dprintf("Unloading module %s.\n", erl->name ? erl->name : "(noname)");
1117 
1118  if ((erl->flags) & ERL_FLAG_STICKY) {
1119  dprintf("Module is sticky, won't unload.\n");
1120  return 0;
1121  }
1122 
1123  for (p = dependancy_root; p; p = p->next) {
1124  if (p->provider == erl) {
1125  dprintf("Other modules depend on it, won't unload.\n");
1126  return 0;
1127  }
1128  }
1129 
1130  if ((s = erl_find_local_symbol("_fini", erl))) {
1131  dprintf("_fini = %08X\n", s->address);
1132 #ifdef _EE
1133  ((func_t)s->address)();
1134 #endif
1135  }
1136 
1137  if (erl->dependancies)
1138  r_unload_dependancies(erl->dependancies);
1139 
1140  erl_flush_symbols(erl);
1141 
1142  destroy_dependancy_r(erl);
1143 
1144  destroy_erl_record(erl);
1145 
1146  return 1;
1147 }
1148 
1149 struct erl_record_t * erl_resolve(u32 address) {
1150  struct erl_record_t * r;
1151 
1152  for (r = erl_record_root; r; r = r->next) {
1153  u32 r_ptr = (u32) r->bytes;
1154  if ((address >= r_ptr) && (address < (r_ptr + r->fullsize)))
1155  return r;
1156  }
1157 
1158  return 0;
1159 }
1160 
1161 struct erl_record_t * find_erl(const char * name) {
1162  struct erl_record_t * r;
1163 
1164  for (r = erl_record_root; r; r = r->next) {
1165  if (r->name)
1166  if (!strcmp(name, r->name))
1167  return r;
1168  }
1169 
1170  return 0;
1171 }
1172 
1173 void erl_flush_symbols(struct erl_record_t * erl) {
1174  if (!erl->symbols)
1175  return;
1176 
1177  if (hfirst(erl->symbols)) do {
1178  destroy_symbol((struct symbol_t *) hstuff(erl->symbols));
1179  free((void *)hkey(erl->symbols));
1180  hdel(erl->symbols);
1181  } while (hcount(erl->symbols));
1182 
1183  hdestroy(erl->symbols);
1184 
1185  erl->symbols = 0;
1186 }
1187 
1188 #ifdef STANDALONE
1189 
1190 int main(int argc, char *argv[]) {
1191  struct erl_record_t * erl;
1192  char * fname;
1193 
1194  erl_add_global_symbol("printf", (u32) printf);
1195 
1196  if (argc == 2) {
1197  fname = argv[1];
1198  } else {
1199  fname = "host:hello-erl.erl";
1200  }
1201 
1202  if (!(erl = load_erl_from_file(fname))) {
1203  dprintf("Error while loading erl file.\n");
1204  return -1;
1205  }
1206 
1207  return 0;
1208 }
1209 
1210 #endif
kernel.h
symbol_t
Definition: erl.h:42
ERL_FLAG_CLEAR
#define ERL_FLAG_CLEAR
Definition: erl.h:28
elf_symbol_t
Definition: erl.c:250
loosy_t
Definition: erl.c:266
erl_record_t
Definition: erl.h:30
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
elf_section_t
Definition: erl.c:245
ERL_FLAG_STATIC
#define ERL_FLAG_STATIC
Definition: erl.h:26
elf_rela_t
Definition: erl.c:260
reroot
Definition: recycle.h:34
elf_reloc_t
Definition: erl.c:256
htab
Definition: hashtab.h:53
tamtypes.h
dependancy_t
Definition: erl.c:273
stdio.h
erl.h
symbol
Definition: main.c:241
ERL_FLAG_STICKY
#define ERL_FLAG_STICKY
Definition: erl.h:24
stdlib.h
elf_header_t
Definition: elf.h:20