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 ? 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;
598#define free_and_return(code) if (!elf_mem) { \
599 if (names) free(names); \
600 if (strtab_names) free(strtab_names); \
601 if (sec) free(sec); \
602 if (sym) free(sym); \
603 if ((code < 0) && erl_record) destroy_erl_record(erl_record); \
607 if (!(erl_record = allocate_erl_record())) {
608 dprintf(
"Memory allocation error.\n");
614 memcpy(&head, elf_mem,
sizeof(head));
616 lseek(elf_handle, 0, SEEK_SET);
617 read(elf_handle, &head,
sizeof(head));
620 magic = head.e_ident.cook.ei_magic;
622 if ((magic[0] != 0x7f) || (magic[1] !=
'E') || (magic[2] !=
'L') || ((magic[3] !=
'F') && (magic[3] !=
'X'))) {
623 dprintf(
"Not an ELF file.\n");
629 dprintf(
"ELF Class : %s\n", elf_classes[head.e_ident.cook.ei_class]);
630 dprintf(
"Data encoding: %s\n", elf_encodings[head.e_ident.cook.ei_data]);
631 dprintf(
"Elf version : %i\n", head.e_ident.cook.ei_version);
632 if (head.e_type == 0xffff) {
633 dprintf(
"Object type : Processor specific (hi)\n");
634 }
else if (head.e_type == 0xff00) {
635 dprintf(
"Object type : Processor specific (lo)\n");
637 dprintf(
"Object type : %s\n", elf_types[head.e_type]);
639 dprintf(
"Machine type : %s\n", elf_machines[head.e_machine]);
640 dprintf(
"Object ver. : %i\n", head.e_version);
641 dprintf(
"Elf entry : %08X\n", head.e_entry);
642 dprintf(
"PH offset : %08X\n", head.e_phoff);
643 dprintf(
"SH offset : %08X\n", head.e_shoff);
644 dprintf(
"Flags : %08X\n", head.e_flags);
645 dprintf(
"Header size : %04X\n", head.e_ehsize);
646 dprintf(
"PH ent. size : %04X\n", head.e_phentsize);
647 dprintf(
"PH number : %04X\n", head.e_phnum);
648 dprintf(
"SH ent. size : %04X\n", head.e_shentsize);
649 dprintf(
"SH number : %04X\n", head.e_shnum);
650 dprintf(
"SH str index : %04X\n", head.e_shstrndx);
652 if (head.e_type != REL_TYPE) {
653 dprintf(
"File isn't a relocatable ELF file.\n");
659 dprintf(
"Inconsistancy in section table entries.\n");
668 dprintf(
"Not enough memory.\n");
671 lseek(elf_handle, head.e_shoff, SEEK_SET);
672 read(elf_handle, sec,
sizeof(
struct elf_section_t) * head.e_shnum);
678 names = (
char *) (elf_mem + sec[head.e_shstrndx].sh_offset);
680 if (!(names = (
char *) malloc(sec[head.e_shstrndx].sh_size))) {
681 dprintf(
"Not enough memory.\n");
684 lseek(elf_handle, sec[head.e_shstrndx].sh_offset, SEEK_SET);
685 read(elf_handle, names, sec[head.e_shstrndx].sh_size);
690 dprintf(
"##: type flags offset size link info align entsize name\n");
691 for (i = 1; i < head.e_shnum; i++) {
692 if (!strcmp(names + sec[i].sh_name,
".symtab")) {
694 linked_strtab = sec[i].sh_link;
695 }
else if (!strcmp(names + sec[i].sh_name,
".strtab")) {
699 if ((sec[i].sh_type == PROGBITS) || (sec[i].sh_type == NOBITS)) {
701 fullsize = align(fullsize, sec[i].sh_addralign);
702 sec[i].sh_addr = fullsize;
703 fullsize += sec[i].sh_size;
704 dprintf(
"Section to load at %08X:\n", sec[i].sh_addr);
708 if (sec[i].sh_type <= 0xff) {
709 rprintf(
"%-8s ", section_types[sec[i].sh_type]);
710 }
else if (sec[i].sh_type == 0x70000006) {
716 rprintf(
"%3s ", section_flags[sec[i].sh_flags & 7]);
717 rprintf(
"%08X ", sec[i].sh_offset);
718 rprintf(
"%08X ", sec[i].sh_size);
719 rprintf(
"%5i ", sec[i].sh_link);
720 rprintf(
"%5i ", sec[i].sh_info);
721 rprintf(
"%5i ", sec[i].sh_addralign);
722 rprintf(
"%5i ", sec[i].sh_entsize);
723 rprintf(
"%s\n", names + sec[i].sh_name);
727 dprintf(
"Discovered symtab = %i\n", symtab);
729 dprintf(
"No symbol table.\n");
734 dprintf(
"Discovered strtab = %i\n", strtab);
736 dprintf(
"No string table.\n");
740 if (strtab != linked_strtab) {
741 dprintf(
"Warning, inconsistancy: strtab != symtab.sh_link (%i != %i)\n", strtab, linked_strtab);
745 if (
sizeof(
struct elf_symbol_t) != sec[symtab].sh_entsize) {
746 dprintf(
"Symbol entries not consistant.\n");
750 dprintf(
"Computed needed size to load the erl file: %i\n", fullsize);
753 if (addr == ERL_DYN_ADDR) {
754 erl_record->bytes = (u8 *) malloc(fullsize);
755 if (!erl_record->bytes) {
756 dprintf(
"Cannot allocate ERL bytes.\n");
760 erl_record->bytes = (u8 *) addr;
764 erl_record->fullsize = fullsize;
765 dprintf(
"Base address: %08X\n", erl_record->bytes);
766 for (i = 1; i < head.e_shnum; i++) {
767 switch (sec[i].sh_type) {
770 dprintf(
"Reading section %s at %08X.\n", names + sec[i].sh_name, erl_record->bytes + sec[i].sh_addr);
772 memcpy(erl_record->bytes + sec[i].sh_addr, elf_mem + sec[i].sh_offset, sec[i].sh_size);
774 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
775 read(elf_handle, erl_record->bytes + sec[i].sh_addr, sec[i].sh_size);
779 dprintf(
"Zeroing section %s at %08X.\n", names + sec[i].sh_name, erl_record->bytes + sec[i].sh_addr);
780 memset(erl_record->bytes + sec[i].sh_addr, 0, sec[i].sh_size);
789 strtab_names = (
char *) (elf_mem + sec[strtab].sh_offset);
791 if (!(strtab_names = (
char *) malloc(sec[strtab].sh_size))) {
792 dprintf(
"Not enough memory.\n");
795 lseek(elf_handle, sec[strtab].sh_offset, SEEK_SET);
796 read(elf_handle, strtab_names, sec[strtab].sh_size);
803 sym = (
struct elf_symbol_t *) (elf_mem + sec[symtab].sh_offset);
805 if (!(sym = (
struct elf_symbol_t *) malloc(sec[symtab].sh_size))) {
806 dprintf(
"Not enough memory.\n");
809 lseek(elf_handle, sec[symtab].sh_offset, SEEK_SET);
810 read(elf_handle, sym, sec[symtab].sh_size);
814 for (i = 0; i < head.e_shnum; i++) {
815 if (sec[i].sh_type != REL && sec[i].sh_type != RELA)
817 dprintf(
"Section %i (%s) contains relocations for section %i (%s):\n",
818 i, names + sec[i].sh_name, sec[i].sh_info, names + sec[sec[i].sh_info].sh_name);
820 if (sec[i].sh_entsize !=
sizeof(
struct elf_reloc_t) && sec[i].sh_entsize !=
sizeof(
struct elf_rela_t)) {
821 dprintf(
"Warning: inconsistancy in relocation table.\n");
828 reloc_section = (
char *)(elf_mem + sec[i].sh_offset);
830 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
831 if (!(reloc_section = (
char *) malloc(sec[i].sh_size))) {
832 dprintf(
"Not enough memory.\n");
835 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
836 read(elf_handle, reloc_section, sec[i].sh_size);
840 dprintf(
" Num: Offset Type Symbol\n");
841 for (j = 0; (u32)j < (sec[i].sh_size / sec[i].sh_entsize); j++) {
844 reloc = *((
struct elf_reloc_t *) (reloc_section + j * sec[i].sh_entsize));
846 sym_n = reloc.r_info >> 8;
847 dprintf(
"%6i: %08X %-14s %3i: ", j, reloc.r_offset, reloc_types[reloc.r_info & 255], sym_n);
849 switch(sym[sym_n].st_info & 15) {
851 rprintf(
"external symbol reloc to symbol %s\n", strtab_names + sym[sym_n].st_name);
852 if (!(s = erl_find_symbol(strtab_names + sym[sym_n].st_name))) {
853 printf(
"%s: Symbol not found, adding as loosy relocation.\n", strtab_names + sym[sym_n].st_name);
854 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);
856 dprintf(
"Found symbol at %08X, relocating.\n", s->address);
857 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, s->address) < 0) {
858 dprintf(
"Something went wrong in relocation.");
861 add_dependancy(erl_record, s->provider);
865 rprintf(
"internal section reloc to section %i (%s)\n", sym[sym_n].st_shndx, names + sec[sym[sym_n].st_shndx].sh_name);
866 dprintf(
"Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr);
867 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) {
868 dprintf(
"Something went wrong in relocation.");
874 rprintf(
"internal relocation to symbol %s\n", strtab_names + sym[sym_n].st_name);
875 if ((s = erl_find_symbol(strtab_names + sym[sym_n].st_name))) {
876 dprintf(
"Symbol already exists at %08X. Let's use it instead.\n", s->address);
877 if (apply_reloc(erl_record->bytes + sec[sec[i].sh_info].sh_addr + reloc.r_offset, reloc.r_info & 255, s->address) < 0) {
878 dprintf(
"Something went wrong in relocation.");
881 add_dependancy(erl_record, s->provider);
883 dprintf(
"Relocating at %08X.\n", erl_record->bytes + sec[sym[sym_n].st_shndx].sh_addr + sym[sym_n].st_value);
884 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) {
885 dprintf(
"Something went wrong in relocation.");
891 rprintf(
"Unknown relocation. Bug inside.\n");
899 dprintf(
" Num: Value Size Type Bind Ndx Name\n");
900 for (i = 0; (u32)i < sec[symtab].sh_size / sec[symtab].sh_entsize; i++) {
901 if (((sym[i].st_info >> 4) == GLOBAL) || ((sym[i].st_info >> 4) == WEAK)) {
902 if ((sym[i].st_info & 15) != NOTYPE) {
903 dprintf(
"Export symbol:\n");
904 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) {
905 dprintf(
"Symbol probably already exists, let's ignore that.\n");
911 dprintf(
"%6i: %08X %08X %-7s %-6s %6i %-10s : %s\n", i,
912 sym[i].st_value, sym[i].st_size, symbol_types[sym[i].st_info & 15],
913 binding_types[sym[i].st_info >> 4], sym[i].st_shndx,
914 sym[i].st_name ? strtab_names + sym[i].st_name :
"(null)",
915 sym[i].st_shndx ? names + sec[sym[i].st_shndx].sh_name :
"(null)");
923 *p_erl_record = erl_record;
932typedef int (*func_t)(void);
933typedef int (*start_t)(
int argc,
char ** argv);
935static struct erl_record_t * _init_load_erl_wrapper_from_file(
char * erl_id) {
937 strcpy(tmpnam, erl_id);
938 strcat(tmpnam,
".erl");
939 return _init_load_erl_from_file(tmpnam, erl_id);
942erl_loader_t _init_load_erl = _init_load_erl_wrapper_from_file;
944static struct erl_record_t * load_erl(
const char * fname, u8 * elf_mem, u32 addr,
int argc,
char ** argv) {
949 dprintf(
"Reading ERL file.\n");
952 if ((elf_handle = open(fname, O_RDONLY | O_BINARY)) < 0) {
953 dprintf(
"Error operning erl file: %s\n", fname);
958 if (read_erl(elf_handle, elf_mem, addr, &r) < 0) {
959 dprintf(
"Error loading erl file.\n");
970 if ((s = erl_find_local_symbol(
"erl_id", r))) {
971 r->name = *(
char **) s->address;
976 dprintf(
"erl_id = %08X.\n", r->name);
978 if ((s = erl_find_local_symbol(
"erl_dependancies", r))) {
979 r->dependancies = (
char **) s->address;
984 dprintf(
"erl_dependancies = %08X.\n", r->dependancies);
986 if (r->dependancies) {
988 for (d = r->dependancies; *d; d++) {
989 dprintf(
"Loading dependancy: %s.\n", *d);
994 if ((s = erl_find_local_symbol(
"_init", r))) {
995 dprintf(
"_init = %08X\n", s->address);
997 ((func_t)s->address)();
1001 if ((s = erl_find_local_symbol(
"_start", r))) {
1002 dprintf(
"_start = %08X\n", s->address);
1005 if ((_start_ret = ((start_t)s->address)(argc, argv))) {
1006 dprintf(
"Module's _start returned %i, unloading module.\n", _start_ret);
1016struct erl_record_t * _init_load_erl_from_file(
const char * fname,
char * erl_id) {
1022 if ((r = find_erl(erl_id)))
1029 strcpy(tfname, _init_erl_prefix);
1030 strcat(tfname, fname);
1032 return load_erl_from_file(tfname, 1, argv);
1035struct erl_record_t * load_erl_from_file(
const char * fname,
int argc,
char ** argv) {
1036 return load_erl(fname, 0, ERL_DYN_ADDR, argc, argv);
1039struct erl_record_t * load_erl_from_mem(u8 * mem,
int argc,
char ** argv) {
1040 return load_erl(0, mem, ERL_DYN_ADDR, argc, argv);
1046struct erl_record_t * load_erl_from_mem_to_addr(u8 * mem, u32 addr,
int argc,
char ** argv) {
1047 return load_erl(0, mem, addr, argc, argv);
1053struct erl_record_t * load_erl_from_file_to_addr(
const char * fname, u32 addr,
int argc,
char ** argv) {
1054 return load_erl(fname, 0, addr, argc, argv);
1060struct erl_record_t * _init_load_erl_from_file_to_addr(
const char * fname, u32 addr,
char * erl_id) {
1066 if ((r = find_erl(erl_id)))
1073 strcpy(tfname, _init_erl_prefix);
1074 strcat(tfname, fname);
1076 return load_erl_from_file_to_addr(tfname, addr, 1, argv);
1079void r_unload_dependancies(
char ** d) {
1084 r_unload_dependancies(d + 1);
1086 if ((erl = find_erl(*d)))
1094 dprintf(
"Unloading module %s.\n", erl->name ? erl->name :
"(noname)");
1097 dprintf(
"Module is sticky, won't unload.\n");
1101 for (p = dependancy_root; p; p = p->next) {
1102 if (p->provider == erl) {
1103 dprintf(
"Other modules depend on it, won't unload.\n");
1108 if ((s = erl_find_local_symbol(
"_fini", erl))) {
1109 dprintf(
"_fini = %08X\n", s->address);
1111 ((func_t)s->address)();
1115 if (erl->dependancies)
1116 r_unload_dependancies(erl->dependancies);
1118 erl_flush_symbols(erl);
1120 destroy_dependancy_r(erl);
1122 destroy_erl_record(erl);
1130 for (r = erl_record_root; r; r = r->next) {
1131 u32 r_ptr = (u32) r->bytes;
1132 if ((address >= r_ptr) && (address < (r_ptr + r->fullsize)))
1142 for (r = erl_record_root; r; r = r->next) {
1144 if (!strcmp(name, r->name))
1155 if (hfirst(erl->symbols))
do {
1156 destroy_symbol((
struct symbol_t *) hstuff(erl->symbols));
1157 free(hkey(erl->symbols));
1159 }
while (hcount(erl->symbols));
1161 hdestroy(erl->symbols);
1168int main(
int argc,
char *argv[]) {
1172 erl_add_global_symbol(
"printf", (u32) printf);
1177 fname =
"host:hello-erl.erl";
1180 if (!(erl = load_erl_from_file(fname))) {
1181 dprintf(
"Error while loading erl file.\n");
u32 count
start sector of fragmented bd/file