27#define dprintf(fmt, args...) printf("(%s:%s:%i): " fmt, __FILE__, __FUNCTION__, __LINE__, ## args)
29#define dprintf(fmt, args...) printf(fmt, ## args)
31#define rprintf(fmt, args...) printf(fmt, ## args)
33#define dprintf(a...) do { } while(0)
34#define rprintf(a...) do { } while(0)
41#include <sys/unistd.h>
63typedef unsigned char u8;
64typedef unsigned short u16;
65typedef unsigned int u32;
66typedef signed char s8;
67typedef signed short s16;
68typedef signed int s32;
73static char * elf_classes[] = {
79static char * elf_encodings[] = {
85static char * elf_types[] = {
93static char * elf_machines[] = {
101 "MIPS RS3000 Big-Endian",
102 "MIPS RS4000 Big-Endian",
105static char * section_types[] = {
120static char * section_flags[] = {
131static char * symbol_types[] = {
150static char * binding_types[] = {
169static char * reloc_types[] = {
206static const char * local_names[] = {
246 u32 sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size;
247 u32 sh_link, sh_info, sh_addralign, sh_entsize;
251 u32 st_name, st_value, st_size;
252 u8 st_info, st_other;
257 u32 r_offset, r_info;
261 u32 r_offset, r_info, r_addend;
282static htab * global_symbols = 0;
283static htab * loosy_relocs = 0;
285char _init_erl_prefix[256] =
"";
290static u32 align(u32 x,
int align) {
320static void destroy_loosy(
struct loosy_t * l) {
324static void r_destroy_loosy(
struct loosy_t * l) {
328 r_destroy_loosy(l->next);
333static reroot * symbol_recycle = 0;
339 symbol_recycle = remkroot(
sizeof(
struct symbol_t));
341 r = (
struct symbol_t *) renew(symbol_recycle);
343 r->provider = provider;
344 r->address = address;
349static void destroy_symbol(
struct symbol_t * s) {
350 redel(symbol_recycle, s);
360 r->symbols = hcreate(6);
362 if ((r->next = erl_record_root))
372static void destroy_erl_record(
struct erl_record_t * erl) {
378 memset(erl->bytes, 0, erl->fullsize);
383 erl_flush_symbols(erl);
386 erl->prev->next = erl->next;
388 erl_record_root = erl->next;
391 erl->next->prev = erl->prev;
396static int apply_reloc(u8 * reloc,
int type, u32 addr) {
401 if (((u32)reloc)&0x3)
403 printf(
"Unaligned reloc (%p) type=%d!\n", reloc, type);
405 memcpy(&u_current_data, reloc, 4);
406 memcpy(&s_current_data, reloc, 4);
410 newstate = s_current_data + addr;
413 newstate = (u_current_data & 0xfc000000) | (((u_current_data & 0x03ffffff) + (addr >> 2)) & 0x3ffffff);
416 newstate = (u_current_data & 0xffff0000) | ((((s_current_data << 16) >> 16) + (addr >> 16) + (((addr & 0xffff) >= 0x8000) && !(u_current_data & 0xf)? 1 : 0)) & 0xffff);
419 newstate = (u_current_data & 0xffff0000) | ((((s_current_data << 16) >> 16) + (addr & 0xffff)) & 0xffff);
425 memcpy(reloc, &newstate, 4);
427 dprintf(
"Changed data at %08X from %08X to %08X.\n", reloc, u_current_data, newstate);
435 return hstuff(erl->symbols);
443 return hstuff(erl->symbols);
444 return r_find_symbol(
symbol, erl->next);
450 return hstuff(global_symbols);
451 return r_find_symbol(
symbol, erl_record_root);
457 if (depender == provider)
463 d->depender = depender;
464 d->provider = provider;
466 if ((d->next = dependancy_root))
475static void destroy_dependancy(
struct dependancy_t * d) {
477 d->prev->next = d->next;
479 dependancy_root = d->next;
482 d->next->prev = d->prev;
491 r_destroy_dependancy_r(erl, d->next);
493 if (erl == d->depender)
494 destroy_dependancy(d);
499static void destroy_dependancy_r(
struct erl_record_t * erl) {
500 r_destroy_dependancy_r(erl, dependancy_root);
503static void add_loosy(
struct erl_record_t * erl, u8 * reloc,
int type,
const char *
symbol) {
506 l = create_loosy(erl, reloc, type);
509 loosy_relocs = hcreate(6);
512 l->next = hstuff(loosy_relocs);
513 hstuff(loosy_relocs) = l;
515 hkey(loosy_relocs) = (ub1 *)strdup(
symbol);
519static int fix_loosy(
struct erl_record_t * provider,
const char *
symbol, u32 address) {
527 for (l = hstuff(loosy_relocs); l; l = l->next) {
528 apply_reloc(l->reloc, l->type, address);
529 add_dependancy(l->erl, provider);
532 r_destroy_loosy(hstuff(loosy_relocs));
533 free(hkey(loosy_relocs));
540static int is_local(
const char *
symbol) {
543 for (p = local_names; *p; p++)
554 symbols = erl->symbols;
557 global_symbols = hcreate(6);
558 symbols = global_symbols;
564 dprintf(
"Adding symbol %s at address %08X\n",
symbol, address);
566 if (fix_loosy(erl,
symbol, address)) {
573 hadd(symbols, strdup(
symbol), strlen(
symbol), create_symbol(erl, address));
578int erl_add_global_symbol(
const char *
symbol, u32 address) {
579 return add_symbol(0,
symbol, address);
582static int read_erl(
int elf_handle, u8 * elf_mem, u32 addr,
struct erl_record_t ** p_erl_record) {
589 char * names = 0, * strtab_names = 0, * reloc_section = 0;
590 int symtab = 0, strtab = 0, linked_strtab = 0;
597 int has_next_reloc = 0;
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); \
610 if (!(erl_record = allocate_erl_record())) {
611 dprintf(
"Memory allocation error.\n");
617 memcpy(&head, elf_mem,
sizeof(head));
619 lseek(elf_handle, 0, SEEK_SET);
620 read(elf_handle, &head,
sizeof(head));
623 magic = head.e_ident.cook.ei_magic;
625 if ((magic[0] != 0x7f) || (magic[1] !=
'E') || (magic[2] !=
'L') || ((magic[3] !=
'F') && (magic[3] !=
'X'))) {
626 dprintf(
"Not an ELF file.\n");
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");
640 dprintf(
"Object type : %s\n", elf_types[head.e_type]);
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);
655 if (head.e_type != REL_TYPE) {
656 dprintf(
"File isn't a relocatable ELF file.\n");
662 dprintf(
"Inconsistancy in section table entries.\n");
671 dprintf(
"Not enough memory.\n");
674 lseek(elf_handle, head.e_shoff, SEEK_SET);
675 read(elf_handle, sec,
sizeof(
struct elf_section_t) * head.e_shnum);
681 names = (
char *) (elf_mem + sec[head.e_shstrndx].sh_offset);
683 if (!(names = (
char *) malloc(sec[head.e_shstrndx].sh_size))) {
684 dprintf(
"Not enough memory.\n");
687 lseek(elf_handle, sec[head.e_shstrndx].sh_offset, SEEK_SET);
688 read(elf_handle, names, sec[head.e_shstrndx].sh_size);
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")) {
697 linked_strtab = sec[i].sh_link;
698 }
else if (!strcmp(names + sec[i].sh_name,
".strtab")) {
702 if ((sec[i].sh_type == PROGBITS) || (sec[i].sh_type == NOBITS)) {
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);
711 if (sec[i].sh_type <= 0xff) {
712 rprintf(
"%-8s ", section_types[sec[i].sh_type]);
713 }
else if (sec[i].sh_type == 0x70000006) {
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);
730 dprintf(
"Discovered symtab = %i\n", symtab);
732 dprintf(
"No symbol table.\n");
737 dprintf(
"Discovered strtab = %i\n", strtab);
739 dprintf(
"No string table.\n");
743 if (strtab != linked_strtab) {
744 dprintf(
"Warning, inconsistancy: strtab != symtab.sh_link (%i != %i)\n", strtab, linked_strtab);
748 if (
sizeof(
struct elf_symbol_t) != sec[symtab].sh_entsize) {
749 dprintf(
"Symbol entries not consistant.\n");
753 dprintf(
"Computed needed size to load the erl file: %i\n", fullsize);
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");
763 erl_record->bytes = (u8 *) addr;
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) {
773 dprintf(
"Reading section %s at %08X.\n", names + sec[i].sh_name, erl_record->bytes + sec[i].sh_addr);
775 memcpy(erl_record->bytes + sec[i].sh_addr, elf_mem + sec[i].sh_offset, sec[i].sh_size);
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);
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);
792 strtab_names = (
char *) (elf_mem + sec[strtab].sh_offset);
794 if (!(strtab_names = (
char *) malloc(sec[strtab].sh_size))) {
795 dprintf(
"Not enough memory.\n");
798 lseek(elf_handle, sec[strtab].sh_offset, SEEK_SET);
799 read(elf_handle, strtab_names, sec[strtab].sh_size);
806 sym = (
struct elf_symbol_t *) (elf_mem + sec[symtab].sh_offset);
808 if (!(sym = (
struct elf_symbol_t *) malloc(sec[symtab].sh_size))) {
809 dprintf(
"Not enough memory.\n");
812 lseek(elf_handle, sec[symtab].sh_offset, SEEK_SET);
813 read(elf_handle, sym, sec[symtab].sh_size);
817 for (i = 0; i < head.e_shnum; i++) {
818 if (sec[i].sh_type != REL && sec[i].sh_type != RELA)
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);
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");
831 reloc_section = (
char *)(elf_mem + sec[i].sh_offset);
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");
838 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
839 read(elf_handle, reloc_section, sec[i].sh_size);
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;
847 addend = (sec[i].sh_type == RELA? ((
struct elf_rela_t *)(reloc_section + j * sec[i].sh_entsize))->r_addend : 0);
849 reloc = *((
struct elf_reloc_t *) (reloc_section + j * sec[i].sh_entsize));
851 sym_n = reloc.r_info >> 8;
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;
860 dprintf(
"%6i: %08X %-14s %3i: ", j, reloc.r_offset, reloc_types[reloc.r_info & 255], sym_n);
862 switch(sym[sym_n].st_info & 15) {
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);
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.");
874 add_dependancy(erl_record, s->provider);
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);
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
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);
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.");
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.");
904 add_dependancy(erl_record, s->provider);
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.");
914 rprintf(
"Unknown relocation. Bug inside.\n");
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");
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)");
946 *p_erl_record = erl_record;
955typedef int (*func_t)(void);
956typedef int (*start_t)(
int argc,
char ** argv);
958static struct erl_record_t * _init_load_erl_wrapper_from_file(
char * erl_id) {
960 strcpy(tmpnam, erl_id);
961 strcat(tmpnam,
".erl");
962 return _init_load_erl_from_file(tmpnam, erl_id);
965erl_loader_t _init_load_erl = _init_load_erl_wrapper_from_file;
967static struct erl_record_t * load_erl(
const char * fname, u8 * elf_mem, u32 addr,
int argc,
char ** argv) {
972 dprintf(
"Reading ERL file.\n");
975 if ((elf_handle = open(fname, O_RDONLY | O_BINARY)) < 0) {
976 dprintf(
"Error operning erl file: %s\n", fname);
981 if (read_erl(elf_handle, elf_mem, addr, &r) < 0) {
982 dprintf(
"Error loading erl file.\n");
993 if ((s = erl_find_local_symbol(
"erl_id", r))) {
994 r->name = *(
char **) s->address;
999 dprintf(
"erl_id = %08X.\n", r->name);
1001 if ((s = erl_find_local_symbol(
"erl_dependancies", r))) {
1002 r->dependancies = (
char **) s->address;
1004 r->dependancies = 0;
1007 dprintf(
"erl_dependancies = %08X.\n", r->dependancies);
1009 if (r->dependancies) {
1011 for (d = r->dependancies; *d; d++) {
1012 dprintf(
"Loading dependancy: %s.\n", *d);
1017 if ((s = erl_find_local_symbol(
"_init", r))) {
1018 dprintf(
"_init = %08X\n", s->address);
1020 ((func_t)s->address)();
1024 if ((s = erl_find_local_symbol(
"_start", r))) {
1025 dprintf(
"_start = %08X\n", s->address);
1028 if ((_start_ret = ((start_t)s->address)(argc, argv))) {
1029 dprintf(
"Module's _start returned %i, unloading module.\n", _start_ret);
1039struct erl_record_t * _init_load_erl_from_file(
const char * fname,
char * erl_id) {
1045 if ((r = find_erl(erl_id)))
1052 strcpy(tfname, _init_erl_prefix);
1053 strcat(tfname, fname);
1055 return load_erl_from_file(tfname, 1, argv);
1058struct erl_record_t * load_erl_from_file(
const char * fname,
int argc,
char ** argv) {
1059 return load_erl(fname, 0, ERL_DYN_ADDR, argc, argv);
1062struct erl_record_t * load_erl_from_mem(u8 * mem,
int argc,
char ** argv) {
1063 return load_erl(0, mem, ERL_DYN_ADDR, argc, argv);
1069struct erl_record_t * load_erl_from_mem_to_addr(u8 * mem, u32 addr,
int argc,
char ** argv) {
1070 return load_erl(0, mem, addr, argc, argv);
1076struct erl_record_t * load_erl_from_file_to_addr(
const char * fname, u32 addr,
int argc,
char ** argv) {
1077 return load_erl(fname, 0, addr, argc, argv);
1083struct erl_record_t * _init_load_erl_from_file_to_addr(
const char * fname, u32 addr,
char * erl_id) {
1089 if ((r = find_erl(erl_id)))
1096 strcpy(tfname, _init_erl_prefix);
1097 strcat(tfname, fname);
1099 return load_erl_from_file_to_addr(tfname, addr, 1, argv);
1102void r_unload_dependancies(
char ** d) {
1107 r_unload_dependancies(d + 1);
1109 if ((erl = find_erl(*d)))
1117 dprintf(
"Unloading module %s.\n", erl->name ? erl->name :
"(noname)");
1120 dprintf(
"Module is sticky, won't unload.\n");
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");
1131 if ((s = erl_find_local_symbol(
"_fini", erl))) {
1132 dprintf(
"_fini = %08X\n", s->address);
1134 ((func_t)s->address)();
1138 if (erl->dependancies)
1139 r_unload_dependancies(erl->dependancies);
1141 erl_flush_symbols(erl);
1143 destroy_dependancy_r(erl);
1145 destroy_erl_record(erl);
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)))
1165 for (r = erl_record_root; r; r = r->next) {
1167 if (!strcmp(name, r->name))
1178 if (hfirst(erl->symbols))
do {
1179 destroy_symbol((
struct symbol_t *) hstuff(erl->symbols));
1180 free(hkey(erl->symbols));
1182 }
while (hcount(erl->symbols));
1184 hdestroy(erl->symbols);
1191int main(
int argc,
char *argv[]) {
1195 erl_add_global_symbol(
"printf", (u32) printf);
1200 fname =
"host:hello-erl.erl";
1203 if (!(erl = load_erl_from_file(fname))) {
1204 dprintf(
"Error while loading erl file.\n");
u32 count
start sector of fragmented bd/file