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)
40 #include <sys/fcntl.h>
41 #include <sys/unistd.h>
44 #include <sys/types.h>
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;
73 static char * elf_classes[] = {
79 static char * elf_encodings[] = {
85 static char * elf_types[] = {
93 static char * elf_machines[] = {
101 "MIPS RS3000 Big-Endian",
102 "MIPS RS4000 Big-Endian",
105 static char * section_types[] = {
120 static char * section_flags[] = {
131 static char * symbol_types[] = {
150 static char * binding_types[] = {
169 static char * reloc_types[] = {
199 #define R_MIPS_HI16 5
200 #define R_MIPS_LO16 6
397 if (((
u32)reloc)&0x3)
399 printf(
"Unaligned reloc (%p) type=%d!\n", reloc, type);
401 memcpy(&u_current_data, reloc, 4);
402 memcpy(&s_current_data, reloc, 4);
406 newstate = s_current_data + addr;
409 newstate = (u_current_data & 0xfc000000) | (((u_current_data & 0x03ffffff) + (addr >> 2)) & 0x3ffffff);
412 newstate = (u_current_data & 0xffff0000) | ((((s_current_data << 16) >> 16) + (addr >> 16) + ((addr & 0xffff) >= 0x8000 ? 1 : 0)) & 0xffff);
415 newstate = (u_current_data & 0xffff0000) | ((((s_current_data << 16) >> 16) + (addr & 0xffff)) & 0xffff);
421 memcpy(reloc, &newstate, 4);
423 dprintf(
"Changed data at %08X from %08X to %08X.\n", reloc, u_current_data, newstate);
540 if (!strcmp(*p, symbol))
560 dprintf(
"Adding symbol %s at address %08X\n", symbol, address);
585 char * names = 0, * strtab_names = 0, * reloc_section = 0;
586 int symtab = 0, strtab = 0, linked_strtab = 0;
594 #define free_and_return(code) if (!elf_mem) { \
595 if (names) free(names); \
596 if (strtab_names) free(strtab_names); \
597 if (sec) free(sec); \
598 if (sym) free(sym); \
599 if ((code < 0) && erl_record) destroy_erl_record(erl_record); \
604 dprintf(
"Memory allocation error.\n");
610 memcpy(&head, elf_mem,
sizeof(head));
612 lseek(elf_handle, 0, SEEK_SET);
613 read(elf_handle, &head,
sizeof(head));
618 if ((magic[0] != 0x7f) || (magic[1] !=
'E') || (magic[2] !=
'L') || ((magic[3] !=
'F') && (magic[3] !=
'X'))) {
628 if (head.
e_type == 0xffff) {
629 dprintf(
"Object type : Processor specific (hi)\n");
630 }
else if (head.
e_type == 0xff00) {
631 dprintf(
"Object type : Processor specific (lo)\n");
649 dprintf(
"File isn't a relocatable ELF file.\n");
655 dprintf(
"Inconsistancy in section table entries.\n");
664 dprintf(
"Not enough memory.\n");
667 lseek(elf_handle, head.
e_shoff, SEEK_SET);
677 dprintf(
"Not enough memory.\n");
686 dprintf(
"##: type flags offset size link info align entsize name\n");
687 for (i = 1; i < head.
e_shnum; i++) {
688 if (!strcmp(names + sec[i].
sh_name,
".symtab")) {
690 linked_strtab = sec[i].
sh_link;
691 }
else if (!strcmp(names + sec[i].
sh_name,
".strtab")) {
706 }
else if (sec[i].
sh_type == 0x70000006) {
723 dprintf(
"Discovered symtab = %i\n", symtab);
730 dprintf(
"Discovered strtab = %i\n", strtab);
736 if (strtab != linked_strtab) {
737 dprintf(
"Warning, inconsistancy: strtab != symtab.sh_link (%i != %i)\n", strtab, linked_strtab);
742 dprintf(
"Symbol entries not consistant.\n");
746 dprintf(
"Computed needed size to load the erl file: %i\n", fullsize);
750 erl_record->
bytes = (
u8 *) malloc(fullsize);
751 if (!erl_record->
bytes) {
752 dprintf(
"Cannot allocate ERL bytes.\n");
756 erl_record->
bytes = (
u8 *) addr;
762 for (i = 1; i < head.
e_shnum; i++) {
770 lseek(elf_handle, sec[i].
sh_offset, SEEK_SET);
785 strtab_names = (
char *) (elf_mem + sec[strtab].
sh_offset);
787 if (!(strtab_names = (
char *) malloc(sec[strtab].
sh_size))) {
788 dprintf(
"Not enough memory.\n");
791 lseek(elf_handle, sec[strtab].
sh_offset, SEEK_SET);
792 read(elf_handle, strtab_names, sec[strtab].
sh_size);
799 sym = (
struct elf_symbol_t *) (elf_mem + sec[symtab].sh_offset);
801 if (!(sym = (
struct elf_symbol_t *) malloc(sec[symtab].sh_size))) {
802 dprintf(
"Not enough memory.\n");
805 lseek(elf_handle, sec[symtab].sh_offset, SEEK_SET);
806 read(elf_handle, sym, sec[symtab].sh_size);
810 for (i = 0; i < head.
e_shnum; i++) {
811 if (sec[i].sh_type !=
REL)
813 dprintf(
"Section %i (%s) contains relocations for section %i (%s):\n",
814 i, names + sec[i].sh_name, sec[i].sh_info, names + sec[sec[i].sh_info].sh_name);
816 if (sec[i].sh_entsize !=
sizeof(
struct elf_reloc_t)) {
817 dprintf(
"Warning: inconsistancy in relocation table.\n");
824 reloc_section = (
char *)(elf_mem + sec[i].sh_offset);
826 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
827 if (!(reloc_section = (
char *) malloc(sec[i].sh_size))) {
828 dprintf(
"Not enough memory.\n");
831 lseek(elf_handle, sec[i].sh_offset, SEEK_SET);
832 read(elf_handle, reloc_section, sec[i].sh_size);
836 dprintf(
" Num: Offset Type Symbol\n");
840 reloc = *((
struct elf_reloc_t *) (reloc_section + j * sec[i].sh_entsize));
842 sym_n = reloc.
r_info >> 8;
845 switch(sym[sym_n].st_info & 15) {
847 rprintf(
"external symbol reloc to symbol %s\n", strtab_names + sym[sym_n].st_name);
849 printf(
"%s: Symbol not found, adding as loosy relocation.\n", strtab_names + sym[sym_n].st_name);
852 dprintf(
"Found symbol at %08X, relocating.\n",
s->address);
854 dprintf(
"Something went wrong in relocation.");
861 rprintf(
"internal section reloc to section %i (%s)\n", sym[sym_n].st_shndx, names + sec[sym[sym_n].st_shndx].sh_name);
864 dprintf(
"Something went wrong in relocation.");
870 rprintf(
"internal relocation to symbol %s\n", strtab_names + sym[sym_n].st_name);
872 dprintf(
"Symbol already exists at %08X. Let's use it instead.\n",
s->address);
874 dprintf(
"Something went wrong in relocation.");
881 dprintf(
"Something went wrong in relocation.");
887 rprintf(
"Unknown relocation. Bug inside.\n");
895 dprintf(
" Num: Value Size Type Bind Ndx Name\n");
897 if (((sym[i].st_info >> 4) ==
GLOBAL) || ((sym[i].st_info >> 4) ==
WEAK)) {
898 if ((sym[i].st_info & 15) !=
NOTYPE) {
901 dprintf(
"Symbol probably already exists, let's ignore that.\n");
907 dprintf(
"%6i: %08X %08X %-7s %-6s %6i %-10s : %s\n", i,
908 sym[i].st_value, sym[i].st_size, symbol_types[sym[i].st_info & 15],
909 binding_types[sym[i].st_info >> 4], sym[i].st_shndx,
910 sym[i].st_name ? strtab_names + sym[i].st_name :
"(null)",
911 sym[i].st_shndx ? names + sec[sym[i].st_shndx].sh_name :
"(null)");
919 *p_erl_record = erl_record;
929 typedef int (*
start_t)(
int argc,
char ** argv);
934 strcat(tmpnam,
".erl");
945 dprintf(
"Reading ERL file.\n");
948 if ((elf_handle = open(fname, O_RDONLY |
O_BINARY)) < 0) {
949 dprintf(
"Error operning erl file: %s\n", fname);
954 if (
read_erl(elf_handle, elf_mem, addr, &r) < 0) {
955 dprintf(
"Error loading erl file.\n");
967 r->
name = *(
char **)
s->address;
985 dprintf(
"Loading dependancy: %s.\n", *d);
991 dprintf(
"_init = %08X\n",
s->address);
999 dprintf(
"_start = %08X\n",
s->address);
1001 if ((_start_ret = ((
start_t)
s->address)(argc, argv))) {
1002 dprintf(
"Module's _start returned %i, unloading module.\n", _start_ret);
1025 strcat(tfname, fname);
1042 return load_erl(0, mem, addr, argc, argv);
1049 return load_erl(fname, 0, addr, argc, argv);
1068 strcat(tfname, fname);
1088 dprintf(
"Unloading module %s.\n", erl->
name ? erl->
name :
"(noname)");
1091 dprintf(
"Module is sticky, won't unload.\n");
1097 dprintf(
"Other modules depend on it, won't unload.\n");
1103 dprintf(
"_fini = %08X\n",
s->address);
1126 if ((address >= r_ptr) && (address < (r_ptr + r->
fullsize)))
1162 int main(
int argc,
char ** argv) {
1171 fname =
"host:hello-erl.erl";
1175 dprintf(
"Error while loading erl file.\n");
static const char * local_names[]
static htab * global_symbols
static void destroy_loosy(struct loosy_t *l)
int erl_add_global_symbol(const char *symbol, u32 address)
static struct loosy_t * create_loosy(struct erl_record_t *erl, u8 *reloc, int type)
static struct symbol_t * create_symbol(struct erl_record_t *provider, u32 address)
int unload_erl(struct erl_record_t *erl)
static struct erl_record_t * allocate_erl_record()
struct erl_record_t * load_erl_from_mem_to_addr(u8 *mem, u32 addr, int argc, char **argv)
struct erl_record_t * load_erl_from_file_to_addr(const char *fname, u32 addr, int argc, char **argv)
struct symbol_t * erl_find_symbol(const char *symbol)
struct erl_record_t * load_erl_from_file(const char *fname, int argc, char **argv)
struct symbol_t * erl_find_local_symbol(const char *symbol, struct erl_record_t *erl)
static void destroy_erl_record(struct erl_record_t *erl)
static struct dependancy_t * add_dependancy(struct erl_record_t *depender, struct erl_record_t *provider)
void erl_flush_symbols(struct erl_record_t *erl)
static void destroy_dependancy(struct dependancy_t *d)
static int is_local(const char *symbol)
static void destroy_dependancy_r(struct erl_record_t *erl)
int(* start_t)(int argc, char **argv)
#define free_and_return(code)
static u32 align(u32 x, int align)
static int add_symbol(struct erl_record_t *erl, const char *symbol, u32 address)
static void add_loosy(struct erl_record_t *erl, u8 *reloc, int type, const char *symbol)
static struct erl_record_t * load_erl(const char *fname, u8 *elf_mem, u32 addr, int argc, char **argv)
struct erl_record_t * _init_load_erl_from_file(const char *fname, char *erl_id)
static int read_erl(int elf_handle, u8 *elf_mem, u32 addr, struct erl_record_t **p_erl_record)
struct erl_record_t * find_erl(const char *name)
struct erl_record_t * erl_resolve(u32 address)
erl_loader_t _init_load_erl
static void r_destroy_dependancy_r(struct erl_record_t *erl, struct dependancy_t *d)
static struct dependancy_t * dependancy_root
static void destroy_symbol(struct symbol_t *s)
static struct symbol_t * r_find_symbol(const char *symbol, struct erl_record_t *erl)
static struct erl_record_t * _init_load_erl_wrapper_from_file(char *erl_id)
struct erl_record_t * load_erl_from_mem(u8 *mem, int argc, char **argv)
static void r_destroy_loosy(struct loosy_t *l)
void r_unload_dependancies(char **d)
static htab * loosy_relocs
static reroot * symbol_recycle
struct erl_record_t * _init_load_erl_from_file_to_addr(const char *fname, u32 addr, char *erl_id)
static int fix_loosy(struct erl_record_t *provider, const char *symbol, u32 address)
static struct erl_record_t * erl_record_root
char _init_erl_prefix[256]
static int apply_reloc(u8 *reloc, int type, u32 addr)
void FlushCache(s32 operation)
#define redel(root, item)
struct erl_record_t * provider
struct dependancy_t * next
struct erl_record_t * depender
struct dependancy_t * prev
struct erl_record_t * next
struct erl_record_t * prev
struct erl_record_t * erl
struct erl_record_t * provider