#include "romdir.h" #include "iopelf.h" typedef struct { u32 st_name; u32 st_value; u32 st_size; u8 st_info; u8 st_other; u16 st_shndx; } Elf32_Sym; char *sections_names; ELF_HEADER *elfHeader; ELF_PHR *elfProgH; ELF_SHR *elfSectH; u8 *elfdata; int elfsize; u32 elfbase; static int debug=1; #define _dprintf(fmt, args...) \ if (debug > 0) __printf("iopelf: " fmt, ## args) static void __memcpy(void *dest, const void *src, int n) { const u8 *s = (u8*)src; u8 *d = (u8*)dest; while (n) { *d++ = *s++; n--; } } int loadHeaders() { elfHeader = (ELF_HEADER*)elfdata; if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) { return -1; } #ifdef ELF_LOG ELF_LOG( "type: " ); #endif switch( elfHeader->e_type ) { default: #ifdef ELF_LOG ELF_LOG( "unknown %x", elfHeader->e_type ); #endif break; case 0x0: #ifdef ELF_LOG ELF_LOG( "no file type" ); #endif break; case 0x1: #ifdef ELF_LOG ELF_LOG( "relocatable" ); #endif break; case 0x2: #ifdef ELF_LOG ELF_LOG( "executable" ); #endif break; } #ifdef ELF_LOG ELF_LOG( "\n" ); ELF_LOG( "machine: " ); #endif switch ( elfHeader->e_machine ) { default: #ifdef ELF_LOG ELF_LOG( "unknown" ); #endif break; case 0x8: #ifdef ELF_LOG ELF_LOG( "mips_rs3000" ); #endif break; } #ifdef ELF_LOG ELF_LOG("\n"); ELF_LOG("version: %d\n",elfHeader->e_version); ELF_LOG("entry: %08x\n",elfHeader->e_entry); ELF_LOG("flags: %08x\n",elfHeader->e_flags); ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); ELF_LOG("\n"); #endif return 0; } int loadProgramHeaders() { int i; if (elfHeader->e_phnum == 0) { return 0; } if (elfHeader->e_phentsize != sizeof(ELF_PHR)) { return -1; } elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) { #ifdef ELF_LOG ELF_LOG( "Elf32 Program Header\n" ); ELF_LOG( "type: " ); #endif switch ( elfProgH[ i ].p_type ) { default: #ifdef ELF_LOG ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); #endif break; case 0x1: #ifdef ELF_LOG ELF_LOG("load"); #endif /* if ( elfHeader->e_shnum == 0 ) {*/ if (elfProgH[ i ].p_offset < elfsize) { int size; if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { size = elfsize - elfProgH[ i ].p_offset; } else { size = elfProgH[ i ].p_filesz; } _dprintf("loading program at %x, size=%x\n", elfProgH[ i ].p_paddr + elfbase, size); __memcpy((void*)(elfProgH[ i ].p_paddr + elfbase), &elfdata[elfProgH[ i ].p_offset], size); } #ifdef ELF_LOG ELF_LOG("\t*LOADED*"); #endif // } break; } #ifdef ELF_LOG ELF_LOG("\n"); ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); ELF_LOG("palign: %08x\n",elfProgH[i].p_align); ELF_LOG("\n"); #endif } return 0; } void _relocateElfSection(int i) { ELF_REL *rel; int size = elfSectH[i].sh_size / 4; int r = 0; u32 *ptr, *tmp; ELF_SHR *rsec = &elfSectH[elfSectH[i].sh_info]; u8 *mem = (u8*)(elfSectH[i].sh_addr + elfbase); u32 imm; int j; ptr = (u32*)(elfdata+elfSectH[i].sh_offset); // _dprintf("relocating section %s\n", §ions_names[rsec->sh_name]); // __printf("sh_addr %x\n", elfSectH[i].sh_addr); while (size > 0) { rel = (ELF_REL*)&ptr[r]; // __printf("rel size=%x: offset=%x, info=%x\n", size, rel->r_offset, rel->r_info); tmp = (u32*)&mem[rel->r_offset]; switch ((u8)rel->r_info) { case 2: // R_MIPS_32 *tmp+= elfbase; break; case 4: // R_MIPS_26 *tmp = (*tmp & 0xfc000000) | (((*tmp & 0x03ffffff) + (elfbase >> 2)) & 0x03ffffff); break; case 5: // R_MIPS_HI16 imm = (((*tmp & 0xffff) + (elfbase >> 16)) & 0xffff); for (j=(r+2)/2; jr_info == 6) break; // if ((rel->r_info >> 8) == (((ELF_REL*)&ptr[j*2])->r_info >> 8)) // break; } /* if (j != elfSectH[i].sh_size / 4)*/ { u32 *p; rel = (ELF_REL*)&ptr[j*2]; // __printf("HI16: found match: %x\n", rel->r_offset); p = (u32*)&mem[rel->r_offset]; // __printf("%x + %x = %x\n", *p, elfbase, (*p & 0xffff) + (elfbase & 0xffff)); if (((*p & 0xffff) + (elfbase & 0xffff)) & 0x8000) { // __printf("found\n"); imm++; } } *tmp = (*tmp & 0xffff0000) | imm; break; case 6: // R_MIPS_LO16 *tmp = (*tmp & 0xffff0000) | (((*tmp & 0xffff) + (elfbase & 0xffff)) & 0xffff); break; default: __printf("UNKNOWN R_MIPS REL!!\n"); break; } size-= 2; r+= 2; } } int loadSectionHeaders() { int i; int i_st = -1; int i_dt = -1; if (elfHeader->e_shnum == 0) { return -1; } elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; } for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) { #ifdef ELF_LOG ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); #endif /* if ( elfSectH[i].sh_flags & 0x2 ) { if (elfSectH[i].sh_offset < elfsize) { int size; if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { size = elfsize - elfSectH[i].sh_offset; } else { size = elfSectH[i].sh_size; } memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ], &elfdata[elfSectH[i].sh_offset], size); } #ifdef ELF_LOG ELF_LOG( "\t*LOADED*" ); #endif }*/ #ifdef ELF_LOG ELF_LOG("\n"); ELF_LOG("type: "); #endif switch ( elfSectH[ i ].sh_type ) { default: #ifdef ELF_LOG ELF_LOG("unknown %08x",elfSectH[i].sh_type); #endif break; case 0x0: #ifdef ELF_LOG ELF_LOG("null"); #endif break; case 0x1: #ifdef ELF_LOG ELF_LOG("progbits"); #endif break; case 0x2: #ifdef ELF_LOG ELF_LOG("symtab"); #endif break; case 0x3: #ifdef ELF_LOG ELF_LOG("strtab"); #endif break; case 0x4: #ifdef ELF_LOG ELF_LOG("rela"); #endif break; case 0x8: #ifdef ELF_LOG ELF_LOG("no bits"); #endif break; case 0x9: #ifdef ELF_LOG ELF_LOG("rel"); #endif break; } #ifdef ELF_LOG ELF_LOG("\n"); ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); ELF_LOG("size: %08x\n", elfSectH[i].sh_size); ELF_LOG("link: %08x\n", elfSectH[i].sh_link); ELF_LOG("info: %08x\n", elfSectH[i].sh_info); ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); #endif // dump symbol table if (elfSectH[i].sh_type == 0x02) { i_st = i; i_dt = elfSectH[i].sh_link; } } // now that we have all the stuff loaded, relocate it for (i = 0 ; i < elfHeader->e_shnum ; i++) { if (elfSectH[i].sh_type == 0x09) { // relocations _relocateElfSection(i); } } return 0; } void* loadElfFile(ROMFILE_INFO* ri, u32 offset) { imageInfo* ii; ELF_PHR* ph; ELF_IOPMOD* im; __printf("loadElfFile: base=%x, size=%x\n", ri->fileData, ri->entry->fileSize); elfdata = (u8*)(ri->fileData); elfsize = ri->entry->fileSize; elfbase = offset+0x30; loadHeaders(); // fill the image info header ph= (ELF_PHR*)((char*)elfHeader +elfHeader->e_phoff); im= (ELF_IOPMOD*)((char*)elfHeader + ph[0].p_offset); ii = (imageInfo*)offset; if( *(u16*)(elfHeader->e_ident+4) != 0x101 ) return NULL; if (elfHeader->e_machine != EM_MIPS) return NULL; if (elfHeader->e_phentsize != sizeof(ELF_PHR)) return NULL; if (elfHeader->e_phnum != 2) return NULL; if (ph[0].p_type != PT_SCE_IOPMOD) return NULL; if (elfHeader->e_type != ET_SCE_IOPRELEXEC){ if (elfHeader->e_type != elfHeader->e_phnum )//ET_EXEC) return NULL; //result->type=3; } //else result->type=4; ii->next =0; ii->name =NULL; ii->version =0; ii->flags =0; ii->modid =0; if ((int)im->moduleinfo != -1) { moduleInfo* minfo = (moduleInfo*)(im->moduleinfo+ph[1].p_vaddr); // probably wrong ii->name = minfo->name; ii->version = minfo->version; } else { ii->name = NULL; ii->version = 0; } ii->entry = im->entry; ii->gp_value = im->gp_value; ii->p1_vaddr = ph[1].p_vaddr; ii->text_size = im->text_size; ii->data_size = im->data_size; ii->bss_size = im->bss_size; loadProgramHeaders(); loadSectionHeaders(); _dprintf("loadElfFile: e_entry=%x, hdr=%x\n", elfHeader->e_entry, elfHeader); return (void*)(elfbase+elfHeader->e_entry); }