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 * 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 ** 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  strcpy(tmpnam, erl_id);
961  strcat(tmpnam, ".erl");
962  return _init_load_erl_from_file(tmpnam, erl_id);
963 }
964 
965 erl_loader_t _init_load_erl = _init_load_erl_wrapper_from_file;
966 
967 static 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 
1039 struct 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 
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  strcpy(tfname, _init_erl_prefix);
1097  strcat(tfname, fname);
1098 
1099  return load_erl_from_file_to_addr(tfname, addr, 1, argv);
1100 }
1101 
1102 void 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 
1113 int 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 
1150 struct 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 
1162 struct 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 
1174 void 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((void *)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 
1191 int 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
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