diff --git a/Makefile b/Makefile index b3a8a8bcc8..63fed2bb70 100644 --- a/Makefile +++ b/Makefile @@ -140,7 +140,7 @@ $(ELF): $(LIBS) $(O_FILES) @$(PYTHON) tools/lcf.py dol --output $(LDSCRIPT) $(LD) -application $(LDFLAGS) -o $@ -lcf $(LDSCRIPT) @build/o_files $(LIBS) -$(ELF_SHIFT): $(LIBS) $(O_FILES) +$(ELF_SHIFT): $(DOL) @echo $(O_FILES) > build/o_files @$(PYTHON) tools/lcf.py dol_shift --output $(LDSCRIPT) $(LD) -application $(LDFLAGS) -o $@ -lcf $(LDSCRIPT) @build/o_files $(LIBS) diff --git a/asm/dolphin/os/OS/OSInit.s b/asm/dolphin/os/OS/OSInit.s index 482078ac8e..c5ebfc66a6 100644 --- a/asm/dolphin/os/OS/OSInit.s +++ b/asm/dolphin/os/OS/OSInit.s @@ -71,8 +71,8 @@ lbl_8033A060: /* 8033A06C 80 63 00 30 */ lwz r3, 0x30(r3) /* 8033A070 28 03 00 00 */ cmplwi r3, 0 /* 8033A074 40 82 00 10 */ bne lbl_8033A084 -/* 8033A078 3C 60 80 46 */ lis r3, 0x8046 /* 0x80459BE0@ha */ -/* 8033A07C 38 63 9B E0 */ addi r3, r3, 0x9BE0 /* 0x80459BE0@l */ +/* 8033A078 3C 60 80 46 */ lis r3, _stack_end+0x3018@ha /* 0x80459BE0@ha */ +/* 8033A07C 38 63 9B E0 */ addi r3, r3, _stack_end+0x3018@l /* 0x80459BE0@l */ /* 8033A080 48 00 00 04 */ b lbl_8033A084 lbl_8033A084: /* 8033A084 48 00 12 21 */ bl OSSetArenaLo @@ -86,8 +86,8 @@ lbl_8033A084: /* 8033A0A4 80 03 00 00 */ lwz r0, 0(r3) /* 8033A0A8 28 00 00 02 */ cmplwi r0, 2 /* 8033A0AC 40 80 00 18 */ bge lbl_8033A0C4 -/* 8033A0B0 3C 60 80 45 */ lis r3, 0x8045 /* 0x80457BC8@ha */ -/* 8033A0B4 38 63 7B C8 */ addi r3, r3, 0x7BC8 /* 0x80457BC8@l */ +/* 8033A0B0 3C 60 80 45 */ lis r3, _stack_end+0x1000@ha /* 0x80457BC8@ha */ +/* 8033A0B4 38 63 7B C8 */ addi r3, r3, _stack_end+0x1000@l /* 0x80457BC8@l */ /* 8033A0B8 38 03 00 1F */ addi r0, r3, 0x1f /* 8033A0BC 54 03 00 34 */ rlwinm r3, r0, 0, 0, 0x1a /* 8033A0C0 48 00 11 E5 */ bl OSSetArenaLo @@ -96,8 +96,8 @@ lbl_8033A0C4: /* 8033A0C8 80 63 00 34 */ lwz r3, 0x34(r3) /* 8033A0CC 28 03 00 00 */ cmplwi r3, 0 /* 8033A0D0 40 82 00 10 */ bne lbl_8033A0E0 -/* 8033A0D4 3C 60 81 70 */ lis r3, 0x8170 /* 0x81700000@ha */ -/* 8033A0D8 38 63 00 00 */ addi r3, r3, 0x0000 /* 0x81700000@l */ +/* 8033A0D4 3C 60 81 70 */ lis r3, __ArenaHi@ha /* 0x81700000@ha */ +/* 8033A0D8 38 63 00 00 */ addi r3, r3, __ArenaHi@l /* 0x81700000@l */ /* 8033A0DC 48 00 00 04 */ b lbl_8033A0E0 lbl_8033A0E0: /* 8033A0E0 48 00 11 BD */ bl OSSetArenaHi diff --git a/asm/dolphin/os/OSThread/__OSThreadInit.s b/asm/dolphin/os/OSThread/__OSThreadInit.s index a71f328cda..538e9e5d8f 100644 --- a/asm/dolphin/os/OSThread/__OSThreadInit.s +++ b/asm/dolphin/os/OSThread/__OSThreadInit.s @@ -31,11 +31,11 @@ lbl_80340B1C: /* 80340B90 4B FF B4 71 */ bl OSClearContext /* 80340B94 7F E3 FB 78 */ mr r3, r31 /* 80340B98 4B FF B2 A1 */ bl OSSetCurrentContext -/* 80340B9C 3C 60 80 45 */ lis r3, 0x8045 /* 0x80457BC8@ha */ -/* 80340BA0 38 03 7B C8 */ addi r0, r3, 0x7BC8 /* 0x80457BC8@l */ -/* 80340BA4 3C 60 80 45 */ lis r3, 0x8045 /* 0x80456BC8@ha */ +/* 80340B9C 3C 60 80 45 */ lis r3, _stack_end+0x1000@ha /* 0x80457BC8@ha */ +/* 80340BA0 38 03 7B C8 */ addi r0, r3, _stack_end+0x1000@l /* 0x80457BC8@l */ +/* 80340BA4 3C 60 80 45 */ lis r3, _stack_end@ha /* 0x80456BC8@ha */ /* 80340BA8 90 1C 07 1C */ stw r0, 0x71c(r28) -/* 80340BAC 38 03 6B C8 */ addi r0, r3, 0x6BC8 /* 0x80456BC8@l */ +/* 80340BAC 38 03 6B C8 */ addi r0, r3, _stack_end@l /* 0x80456BC8@l */ /* 80340BB0 90 1C 07 20 */ stw r0, 0x720(r28) /* 80340BB4 3C 60 DE AE */ lis r3, 0xDEAE /* 0xDEADBABE@ha */ /* 80340BB8 38 03 BA BE */ addi r0, r3, 0xBABE /* 0xDEADBABE@l */ diff --git a/asm/init/__init_registers.s b/asm/init/__init_registers.s index 3b5461325c..638d815523 100644 --- a/asm/init/__init_registers.s +++ b/asm/init/__init_registers.s @@ -28,10 +28,10 @@ lbl_800032B0: /* 80003318 3B A0 00 00 */ li r29, 0 /* 8000331C 3B C0 00 00 */ li r30, 0 /* 80003320 3B E0 00 00 */ li r31, 0 -/* 80003324 3C 20 80 45 */ lis r1, 0x8045 /* 0x80457BC8@h */ -/* 80003328 60 21 7B C8 */ ori r1, r1, 0x7BC8 /* 0x80457BC8@l */ -/* 8000332C 3C 40 80 45 */ lis r2, 0x8045 /* 0x80459A00@h */ -/* 80003330 60 42 9A 00 */ ori r2, r2, 0x9A00 /* 0x80459A00@l */ -/* 80003334 3D A0 80 45 */ lis r13, 0x8045 /* 0x80458580@h */ -/* 80003338 61 AD 85 80 */ ori r13, r13, 0x8580 /* 0x80458580@l */ +/* 80003324 3C 20 80 45 */ lis r1, _stack_end+0x1000@h /* 0x80457BC8@h */ +/* 80003328 60 21 7B C8 */ ori r1, r1, _stack_end+0x1000@l /* 0x80457BC8@l */ +/* 8000332C 3C 40 80 45 */ lis r2, _SDA2_BASE_@h /* 0x80459A00@h */ +/* 80003330 60 42 9A 00 */ ori r2, r2, _SDA2_BASE_@l /* 0x80459A00@l */ +/* 80003334 3D A0 80 45 */ lis r13, _SDA_BASE_@h /* 0x80458580@h */ +/* 80003338 61 AD 85 80 */ ori r13, r13, _SDA_BASE_@l /* 0x80458580@l */ /* 8000333C 4E 80 00 20 */ blr diff --git a/libs/dolphin/os/OS.cpp b/libs/dolphin/os/OS.cpp index 51e546482c..f9272dcc78 100644 --- a/libs/dolphin/os/OS.cpp +++ b/libs/dolphin/os/OS.cpp @@ -497,6 +497,9 @@ u8 __OSStartTime[4]; extern u8 data_80451634[4]; u8 data_80451634[4]; +extern void* __ArenaHi; +extern void* _stack_end; + /* 80339F60-8033A440 3348A0 04E0+00 0/0 2/2 0/0 .text OSInit */ #pragma push #pragma optimization_level 0 diff --git a/libs/dolphin/os/OSThread.cpp b/libs/dolphin/os/OSThread.cpp index ed39bb20f3..19b72d3afa 100644 --- a/libs/dolphin/os/OSThread.cpp +++ b/libs/dolphin/os/OSThread.cpp @@ -119,6 +119,9 @@ static u8 RunQueueHint[4]; static u8 Reschedule[4 + 4 /* padding */]; /* 80340B1C-80340C74 33B45C 0158+00 0/0 1/1 0/0 .text __OSThreadInit */ + +extern void* _stack_end; + #pragma push #pragma optimization_level 0 #pragma optimizewithasm off diff --git a/src/DynamicLink.cpp b/src/DynamicLink.cpp index 097227d06d..a4ae041f7e 100644 --- a/src/DynamicLink.cpp +++ b/src/DynamicLink.cpp @@ -342,19 +342,19 @@ bool DynamicModuleControl::do_load() { snprintf(buffer,64,"%s.rel",mName); if(mModule==NULL&&sArchive!=NULL) { if(mModule==NULL) { - mModule = (OSModuleInfo*)JKRArchive::getGlbResource(0x4D4D454D,buffer,sArchive); + mModule = (OSModuleInfo*)JKRArchive::getGlbResource(0x4D4D454D/*MMEM*/,buffer,sArchive); if(mModule!=NULL) { mResourceType = 1; } } if(mModule==NULL) { - mModule = (OSModuleInfo*)JKRArchive::getGlbResource(0x414D454D,buffer,sArchive); + mModule = (OSModuleInfo*)JKRArchive::getGlbResource(0x414D454D/*AMEM*/,buffer,sArchive); if(mModule!=NULL) { mResourceType = 2; } } if(mModule==NULL) { - mModule = (OSModuleInfo*)JKRArchive::getGlbResource(0x444D454D,buffer,sArchive); + mModule = (OSModuleInfo*)JKRArchive::getGlbResource(0x444D454D/*DMEM*/,buffer,sArchive); if(mModule!=NULL) { mResourceType = 3; } diff --git a/src/init.cpp b/src/init.cpp index f787ad2eea..121b6fa7f0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -102,6 +102,10 @@ SECTION_INIT asm void __start() { } #pragma pop +extern void* _stack_end; +extern void* _SDA2_BASE_; +extern void* _SDA_BASE_; + /* 800032B0-80003340 0001B0 0090+00 1/1 0/0 0/0 .init __init_registers */ #pragma push #pragma optimization_level 0 diff --git a/tools/elf2dol/elf2dol.c b/tools/elf2dol/elf2dol.c index aaa360ee2b..86320dafd5 100644 --- a/tools/elf2dol/elf2dol.c +++ b/tools/elf2dol/elf2dol.c @@ -1,98 +1,106 @@ -#include -#include -#include #include +#include +#include +#include #include #include #ifndef MAX //! Get the maximum of two values -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef MIN //! Get the minimum of two values -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif -#define EI_NIDENT 16 +#define ARRAY_COUNT(arr) (sizeof(arr)/sizeof((arr)[0])) + +#define EI_NIDENT 16 typedef struct { - unsigned char e_ident[EI_NIDENT]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; - uint32_t e_entry; - uint32_t e_phoff; - uint32_t e_shoff; - uint32_t e_flags; - uint16_t e_ehsize; - uint16_t e_phentsize; - uint16_t e_phnum; - uint16_t e_shentsize; - uint16_t e_shnum; - uint16_t e_shstrndx; + unsigned char e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; } Elf32_Ehdr; -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_PAD 7 -#define EI_NIDENT 16 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 -#define ELFCLASS32 1 -#define ELFDATA2MSB 2 -#define EV_CURRENT 1 +#define ELFCLASS32 1 +#define ELFDATA2MSB 2 +#define EV_CURRENT 1 -#define ET_EXEC 2 -#define EM_PPC 20 +#define ET_EXEC 2 +#define EM_PPC 20 typedef struct { - uint32_t p_type; - uint32_t p_offset; - uint32_t p_vaddr; - uint32_t p_paddr; - uint32_t p_filesz; - uint32_t p_memsz; - uint32_t p_flags; - uint32_t p_align; + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; } Elf32_Phdr; -#define PT_LOAD 1 -#define PF_R 4 -#define PF_W 2 -#define PF_X 1 +#define PT_LOAD 1 +#define PF_R 4 +#define PF_W 2 +#define PF_X 1 int verbosity = 0; #if BYTE_ORDER == BIG_ENDIAN #define swap32(x) (x) -#define swaf16(x) (x) +#define swap16(x) (x) #else -static inline uint32_t swap32(uint32_t v) { - return (v >> 24) | ((v >> 8) & 0x0000FF00) | ((v << 8) & 0x00FF0000) | (v << 24); +static inline uint32_t swap32(uint32_t v) +{ + return (v >> 24) | + ((v >> 8) & 0x0000FF00) | + ((v << 8) & 0x00FF0000) | + (v << 24); } -static inline uint16_t swaf16(uint16_t v) { - return (v >> 8) | (v << 8); +static inline uint16_t swap16(uint16_t v) +{ + return (v >> 8) | (v << 8); } #endif /* BIG_ENDIAN */ typedef struct { - uint32_t text_off[7]; - uint32_t data_off[11]; - uint32_t text_addr[7]; - uint32_t data_addr[11]; - uint32_t text_size[7]; - uint32_t data_size[11]; - uint32_t bss_addr; - uint32_t bss_size; - uint32_t entry; - uint32_t pad[7]; + + uint32_t text_off[7]; + uint32_t data_off[11]; + uint32_t text_addr[7]; + uint32_t data_addr[11]; + uint32_t text_size[7]; + uint32_t data_size[11]; + uint32_t bss_addr; + uint32_t bss_size; + uint32_t entry; + uint32_t pad[7]; } DOL_hdr; #define HAVE_BSS 1 @@ -105,435 +113,385 @@ typedef struct { #define DOL_ALIGN(x) (((x) + DOL_ALIGNMENT - 1) & ~(DOL_ALIGNMENT - 1)) typedef struct { - DOL_hdr header; - int text_cnt; - int data_cnt; - uint32_t text_elf_off[7]; - uint32_t text_elf_size[7]; - uint32_t data_elf_off[11]; - uint32_t data_elf_size[11]; - uint32_t flags; - FILE* elf; + DOL_hdr header; + int text_cnt; + int data_cnt; + uint32_t text_elf_off[7]; + uint32_t data_elf_off[11]; + uint32_t flags; + FILE *elf; } DOL_map; -// We need to track 2 PDHR sizes in the event this is for Wii, but for Gamecube -// we only need the first element(s). -uint32_t sdataSizes[2] = {0, 0}; -uint32_t sbssSizes[2] = {0, 0}; - -uint32_t skip_phdr[32] = { 0 }; - -void usage(const char* name) { - fprintf(stderr, "Usage: %s [-h] [-v] [-s phdr] [--] elf-file dol-file\n", name); - fprintf(stderr, " Convert an ELF file to a DOL file (by segments)\n"); - fprintf(stderr, " Options:\n"); - fprintf(stderr, " -h Show this help\n"); - fprintf(stderr, " -v Be more verbose (twice for even more)\n"); - fprintf(stderr, " -s Skip PHDR\n"); +void usage(const char *name) +{ + fprintf(stderr, "Usage: %s [-h] [-v] [--] elf-file dol-file\n", name); + fprintf(stderr, " Convert an ELF file to a DOL file (by segments)\n"); + fprintf(stderr, " Options:\n"); + fprintf(stderr, " -h Show this help\n"); + fprintf(stderr, " -v Be more verbose (twice for even more)\n"); } -#define die(x) \ - { \ - fprintf(stderr, x "\n"); \ - exit(1); \ - } -#define perrordie(x) \ - { \ - perror(x); \ - exit(1); \ - } +#define die(x) { fprintf(stderr, x "\n"); exit(1); } +#define perrordie(x) { perror(x); exit(1); } -void ferrordie(FILE* f, const char* str) { - if (ferror(f)) { - fprintf(stderr, "Error while "); - perrordie(str); - } else if (feof(f)) { - fprintf(stderr, "EOF while %s\n", str); - exit(1); - } else { - fprintf(stderr, "Unknown error while %s\n", str); - exit(1); - } +void ferrordie(FILE *f, const char *str) +{ + if(ferror(f)) { + fprintf(stderr, "Error while "); + perrordie(str); + } else if(feof(f)) { + fprintf(stderr, "EOF while %s\n", str); + exit(1); + } else { + fprintf(stderr, "Unknown error while %s\n", str); + exit(1); + } } -void add_bss(DOL_map* map, uint32_t paddr, uint32_t memsz) { - if (map->flags & HAVE_BSS) { - uint32_t start = swap32(map->header.bss_addr); - uint32_t size = swap32(map->header.bss_size); - uint32_t addr = (start + size); - if (addr == paddr) { - map->header.bss_size = swap32(size + memsz); - } - } else { - map->header.bss_addr = swap32(paddr); - map->header.bss_size = swap32(memsz); - map->flags |= HAVE_BSS; - } +void add_bss(DOL_map *map, uint32_t paddr, uint32_t memsz) +{ + if(map->flags & HAVE_BSS) { + uint32_t curr_start = swap32(map->header.bss_addr); + uint32_t curr_size = swap32(map->header.bss_size); + if (paddr < curr_start) + map->header.bss_addr = swap32(paddr); + // Total BSS size should be the end of the last bss section minus the + // start of the first bss section. + if (paddr + memsz > curr_start + curr_size) + map->header.bss_size = swap32(paddr + memsz - curr_start); + } else { + map->header.bss_addr = swap32(paddr); + map->header.bss_size = swap32(memsz); + map->flags |= HAVE_BSS; + } } -void increment_bss_size(DOL_map* map, uint32_t memsz) { - // because it can be byte swapped, we need to force the add via a temporary. - uint32_t preAdd = swap32(map->header.bss_size); - preAdd += memsz; - map->header.bss_size = swap32(preAdd); +void read_elf_segments(DOL_map *map, const char *elf) +{ + int read, i; + Elf32_Ehdr ehdr; + + if(verbosity >= 2) + fprintf(stderr, "Reading ELF file...\n"); + + map->elf = fopen(elf, "rb"); + if(!map->elf) + perrordie("Could not open ELF file"); + + read = fread(&ehdr, sizeof(ehdr), 1, map->elf); + if(read != 1) + ferrordie(map->elf, "reading ELF header"); + + if(memcmp(&ehdr.e_ident[0], "\177ELF", 4)) + die("Invalid ELF header"); + if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) + die("Invalid ELF class"); + if(ehdr.e_ident[EI_DATA] != ELFDATA2MSB) + die("Invalid ELF byte order"); + if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) + die("Invalid ELF ident version"); + if(swap32(ehdr.e_version) != EV_CURRENT) + die("Invalid ELF version"); + if(swap16(ehdr.e_type) != ET_EXEC) + die("ELF is not an executable"); + if(swap16(ehdr.e_machine) != EM_PPC) + die("Machine is not PowerPC"); + if(!swap32(ehdr.e_entry)) + die("ELF has no entrypoint"); + + map->header.entry = ehdr.e_entry; + + if(verbosity >= 2) + fprintf(stderr, "Valid ELF header found\n"); + + uint16_t phnum = swap16(ehdr.e_phnum); + uint32_t phoff = swap32(ehdr.e_phoff); + Elf32_Phdr *phdrs; + + if(!phnum || !phoff) + die("ELF has no program headers"); + + if(swap16(ehdr.e_phentsize) != sizeof(Elf32_Phdr)) + die("Invalid program header entry size"); + + phdrs = malloc(phnum * sizeof(Elf32_Phdr)); + + if(fseek(map->elf, phoff, SEEK_SET) < 0) + ferrordie(map->elf, "reading ELF program headers"); + read = fread(phdrs, sizeof(Elf32_Phdr), phnum, map->elf); + if(read != phnum) + ferrordie(map->elf, "reading ELF program headers"); + + for(i=0; i= 2) + fprintf(stderr, "PHDR %d: 0x%x [0x%x] -> 0x%08x [0x%x] flags 0x%x\n", + i, offset, filesz, paddr, memsz, flags); + if(flags & PF_X) { + // TEXT segment + if(!(flags & PF_R)) + fprintf(stderr, "Warning: non-readable segment %d\n", i); + if(flags & PF_W) + fprintf(stderr, "Warning: writable and executable segment %d\n", i); + if(filesz > memsz) { + fprintf(stderr, "Error: TEXT segment %d memory size (0x%x) smaller than file size (0x%x)\n", + i, memsz, filesz); + exit(1); + } else if (memsz > filesz) { + add_bss(map, paddr + filesz, memsz - filesz); + } + if(map->text_cnt >= MAX_TEXT_SEGMENTS) { + die("Error: Too many TEXT segments"); + } + map->header.text_addr[map->text_cnt] = swap32(paddr); + map->header.text_size[map->text_cnt] = swap32(filesz); + map->text_elf_off[map->text_cnt] = offset; + map->text_cnt++; + } else { + // DATA or BSS segment + if(!(flags & PF_R)) + fprintf(stderr, "Warning: non-readable segment %d\n", i); + if(filesz == 0) { + // BSS segment + add_bss(map, paddr, memsz); + } else { + // DATA segment + if(filesz > memsz) { + fprintf(stderr, "Error: segment %d memory size (0x%x) is smaller than file size (0x%x)\n", + i, memsz, filesz); + exit(1); + } + if(map->data_cnt >= MAX_DATA_SEGMENTS) { + die("Error: Too many DATA segments"); + } + map->header.data_addr[map->data_cnt] = swap32(paddr); + map->header.data_size[map->data_cnt] = swap32(filesz); + map->data_elf_off[map->data_cnt] = offset; + map->data_cnt++; + } + } + + } else { + if(verbosity >= 1) + fprintf(stderr, "Skipping empty program header %d\n", i); + } + } else if(verbosity >= 1) { + fprintf(stderr, "Skipping program header %d of type %d\n", i, swap32(phdrs[i].p_type)); + } + } + if(verbosity >= 2) { + fprintf(stderr, "Segments:\n"); + for(i=0; itext_cnt; i++) { + fprintf(stderr, " TEXT %d: 0x%08x [0x%x] from ELF offset 0x%x\n", + i, swap32(map->header.text_addr[i]), swap32(map->header.text_size[i]), + map->text_elf_off[i]); + } + for(i=0; idata_cnt; i++) { + fprintf(stderr, " DATA %d: 0x%08x [0x%x] from ELF offset 0x%x\n", + i, swap32(map->header.data_addr[i]), swap32(map->header.data_size[i]), + map->data_elf_off[i]); + } + if(map->flags & HAVE_BSS) + fprintf(stderr, " BSS segment: 0x%08x [0x%x]\n", swap32(map->header.bss_addr), + swap32(map->header.bss_size)); + } } -void align_bss_size(DOL_map* map) { - map->header.bss_size = swap32(DOL_ALIGN(swap32(map->header.bss_size))); +void map_dol(DOL_map *map) +{ + uint32_t fpos; + int i; + + if(verbosity >= 2) + fprintf(stderr, "Laying out DOL file...\n"); + + fpos = DOL_ALIGN(sizeof(DOL_hdr)); + + for(i=0; itext_cnt; i++) { + if(verbosity >= 2) + fprintf(stderr, " TEXT segment %d at 0x%x\n", i, fpos); + map->header.text_off[i] = swap32(fpos); + fpos = DOL_ALIGN(fpos + swap32(map->header.text_size[i])); + } + for(i=0; idata_cnt; i++) { + if(verbosity >= 2) + fprintf(stderr, " DATA segment %d at 0x%x\n", i, fpos); + map->header.data_off[i] = swap32(fpos); + fpos = DOL_ALIGN(fpos + swap32(map->header.data_size[i])); + } + + if(map->text_cnt == 0) { + if(verbosity >= 1) + fprintf(stderr, "Note: adding dummy TEXT segment to work around IOS bug\n"); + map->header.text_off[0] = swap32(DOL_ALIGN(sizeof(DOL_hdr))); + } + if(map->data_cnt == 0) { + if(verbosity >= 1) + fprintf(stderr, "Note: adding dummy DATA segment to work around IOS bug\n"); + map->header.data_off[0] = swap32(DOL_ALIGN(sizeof(DOL_hdr))); + } } -void read_elf_segments(DOL_map* map, const char* elf, uint32_t sdata_pdhr, uint32_t sbss_pdhr, - const char* platform) { - int read, i; - Elf32_Ehdr ehdr; - int isWii = !(strcmp(platform, "wii")) ? 1 : 0; +#define BLOCK (1024*1024) - if (verbosity >= 2) - fprintf(stderr, "Reading ELF file...\n"); +void fcpy(FILE *dst, FILE *src, uint32_t dst_off, uint32_t src_off, uint32_t size) +{ + int left = size; + int read; + int written; + int block; + void *blockbuf; - map->elf = fopen(elf, "rb"); - if (!map->elf) - perrordie("Could not open ELF file"); - - read = fread(&ehdr, sizeof(ehdr), 1, map->elf); - if (read != 1) - ferrordie(map->elf, "reading ELF header"); - - if (memcmp(&ehdr.e_ident[0], "\177ELF", 4)) - die("Invalid ELF header"); - if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) - die("Invalid ELF class"); - if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) - die("Invalid ELF byte order"); - if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) - die("Invalid ELF ident version"); - if (swap32(ehdr.e_version) != EV_CURRENT) - die("Invalid ELF version"); - if (swaf16(ehdr.e_type) != ET_EXEC) - die("ELF is not an executable"); - if (swaf16(ehdr.e_machine) != EM_PPC) - die("Machine is not PowerPC"); - if (!swap32(ehdr.e_entry)) - die("ELF has no entrypoint"); - - map->header.entry = ehdr.e_entry; - - if (verbosity >= 2) - fprintf(stderr, "Valid ELF header found\n"); - - uint16_t phnum = swaf16(ehdr.e_phnum); - uint32_t phoff = swap32(ehdr.e_phoff); - Elf32_Phdr* phdrs; - - if (!phnum || !phoff) - die("ELF has no program headers"); - - if (swaf16(ehdr.e_phentsize) != sizeof(Elf32_Phdr)) - die("Invalid program header entry size"); - - phdrs = malloc(phnum * sizeof(Elf32_Phdr)); - - if (fseek(map->elf, phoff, SEEK_SET) < 0) - ferrordie(map->elf, "reading ELF program headers"); - read = fread(phdrs, sizeof(Elf32_Phdr), phnum, map->elf); - if (read != phnum) - ferrordie(map->elf, "reading ELF program headers"); - - for (i = 0; i < phnum; i++) { - if(skip_phdr[i]) { - if(verbosity >= 1) - fprintf(stderr, "Skipping program header %d because -s\n", i); - continue; - } - - if (swap32(phdrs[i].p_type) == PT_LOAD) { - uint32_t offset = swap32(phdrs[i].p_offset); - uint32_t paddr = swap32(phdrs[i].p_vaddr); - uint32_t filesz = swap32(phdrs[i].p_filesz); - uint32_t memsz = swap32(phdrs[i].p_memsz); - uint32_t flags = swap32(phdrs[i].p_flags); - if (memsz) { - if (verbosity >= 2) - fprintf(stderr, "PHDR %d: 0x%x [0x%x] -> 0x%08x [0x%x] flags 0x%x\n", i, offset, - filesz, paddr, memsz, flags); - if (flags & PF_X) { - // TEXT segment - if (!(flags & PF_R)) - fprintf(stderr, "Warning: non-readable segment %d\n", i); - if (flags & PF_W) - fprintf(stderr, "Warning: writable and executable segment %d\n", i); - if (filesz > memsz) { - fprintf(stderr, - "Error: TEXT segment %d memory size (0x%x) smaller than file size " - "(0x%x)\n", - i, memsz, filesz); - exit(1); - } else if (memsz > filesz) { - add_bss(map, paddr + filesz, memsz - filesz); - } - if (map->text_cnt >= MAX_TEXT_SEGMENTS) { - die("Error: Too many TEXT segments"); - } - map->header.text_addr[map->text_cnt] = swap32(paddr); - map->header.text_size[map->text_cnt] = swap32(DOL_ALIGN(filesz)); - map->text_elf_off[map->text_cnt] = offset; - map->text_elf_size[map->text_cnt] = filesz; - map->text_cnt++; - } else { - // DATA or BSS segment - if (!(flags & PF_R)) - fprintf(stderr, "Warning: non-readable segment %d\n", i); - if (filesz == 0) { - // BSS segment - add_bss(map, paddr, memsz); - - // We need to keep PHDF sizes, so track these. - if (i == sbss_pdhr) { - sbssSizes[0] = memsz; - } else if (isWii && i == sbss_pdhr + 2) { - sbssSizes[1] = memsz; - } - } else { - // DATA segment - if (filesz > memsz) { - fprintf(stderr, - "Error: segment %d memory size (0x%x) is smaller than file " - "size (0x%x)\n", - i, memsz, filesz); - exit(1); - } - if (map->data_cnt >= MAX_DATA_SEGMENTS) { - die("Error: Too many DATA segments"); - } - // Track sdata as well. - if (i == sdata_pdhr) { - sdataSizes[0] = memsz; - } else if (isWii && i == sdata_pdhr + 2) { - sdataSizes[1] = memsz; - } - - map->header.data_addr[map->data_cnt] = swap32(paddr); - map->header.data_size[map->data_cnt] = swap32(DOL_ALIGN(filesz)); - map->data_elf_off[map->data_cnt] = offset; - map->data_elf_size[map->data_cnt] = filesz; - map->data_cnt++; - } - } - - } else { - if (verbosity >= 1) - fprintf(stderr, "Skipping empty program header %d\n", i); - } - } else if (verbosity >= 1) { - fprintf(stderr, "Skipping program header %d of type %d\n", i, swap32(phdrs[i].p_type)); - } - } - align_bss_size(map); - increment_bss_size(map, sdataSizes[0]); - align_bss_size(map); - increment_bss_size(map, sdataSizes[1]); - align_bss_size(map); - increment_bss_size(map, sbssSizes[0]); - align_bss_size(map); - // .sbss2 is added without aligning the size - increment_bss_size(map, sbssSizes[1]); - if (verbosity >= 2) { - fprintf(stderr, "Segments:\n"); - for (i = 0; i < map->text_cnt; i++) { - fprintf(stderr, " TEXT %d: 0x%08x [0x%x] from ELF offset 0x%x\n", i, - swap32(map->header.text_addr[i]), swap32(map->header.text_size[i]), - map->text_elf_off[i]); - } - for (i = 0; i < map->data_cnt; i++) { - fprintf(stderr, " DATA %d: 0x%08x [0x%x] from ELF offset 0x%x\n", i, - swap32(map->header.data_addr[i]), swap32(map->header.data_size[i]), - map->data_elf_off[i]); - } - if (map->flags & HAVE_BSS) - fprintf(stderr, " BSS segment: 0x%08x [0x%x]\n", swap32(map->header.bss_addr), - swap32(map->header.bss_size)); - } + if(fseek(src, src_off, SEEK_SET) < 0) + ferrordie(src, "reading ELF segment data"); + if(fseek(dst, dst_off, SEEK_SET) < 0) + ferrordie(dst, "writing DOL segment data"); + + blockbuf = malloc(MIN(BLOCK, left)); + + while(left) { + block = MIN(BLOCK, left); + read = fread(blockbuf, 1, block, src); + if(read != block) { + free(blockbuf); + ferrordie(src, "reading ELF segment data"); + } + written = fwrite(blockbuf, 1, block, dst); + if(written != block) { + free(blockbuf); + ferrordie(dst, "writing DOL segment data"); + } + left -= block; + } + free(blockbuf); } -void map_dol(DOL_map* map) { - uint32_t fpos; - int i; +void fpad(FILE *dst, uint32_t dst_off, uint32_t size) +{ + uint32_t i; - if (verbosity >= 2) - fprintf(stderr, "Laying out DOL file...\n"); - - fpos = DOL_ALIGN(sizeof(DOL_hdr)); - - for (i = 0; i < map->text_cnt; i++) { - if (verbosity >= 2) - fprintf(stderr, " TEXT segment %d at 0x%x\n", i, fpos); - map->header.text_off[i] = swap32(fpos); - fpos = DOL_ALIGN(fpos + swap32(map->header.text_size[i])); - } - for (i = 0; i < map->data_cnt; i++) { - if (verbosity >= 2) - fprintf(stderr, " DATA segment %d at 0x%x\n", i, fpos); - map->header.data_off[i] = swap32(fpos); - fpos = DOL_ALIGN(fpos + swap32(map->header.data_size[i])); - } - - if (map->text_cnt == 0) { - if (verbosity >= 1) - fprintf(stderr, "Note: adding dummy TEXT segment to work around IOS bug\n"); - map->header.text_off[0] = swap32(DOL_ALIGN(sizeof(DOL_hdr))); - } - if (map->data_cnt == 0) { - if (verbosity >= 1) - fprintf(stderr, "Note: adding dummy DATA segment to work around IOS bug\n"); - map->header.data_off[0] = swap32(DOL_ALIGN(sizeof(DOL_hdr))); - } + if(fseek(dst, dst_off, SEEK_SET) < 0) + ferrordie(dst, "writing DOL segment data"); + for(i=0; i= 2) + fprintf(stderr, "Writing DOL file...\n"); + + dolf = fopen(dol, "wb"); + if(!dolf) + perrordie("Could not open DOL file"); + + if(verbosity >= 2) { + fprintf(stderr, "DOL header:\n"); + for(i=0; itext_cnt); i++) + fprintf(stderr, " TEXT %d @ 0x%08x [0x%x] off 0x%x\n", i, + swap32(map->header.text_addr[i]), swap32(map->header.text_size[i]), + swap32(map->header.text_off[i])); + for(i=0; idata_cnt); i++) + fprintf(stderr, " DATA %d @ 0x%08x [0x%x] off 0x%x\n", i, + swap32(map->header.data_addr[i]), swap32(map->header.data_size[i]), + swap32(map->header.data_off[i])); + if(swap32(map->header.bss_addr) && swap32(map->header.bss_size)) + fprintf(stderr, " BSS @ 0x%08x [0x%x]\n", swap32(map->header.bss_addr), + swap32(map->header.bss_size)); + fprintf(stderr, " Entry: 0x%08x\n", swap32(map->header.entry)); + fprintf(stderr, "Writing DOL header...\n"); + } + + // Write DOL header with aligned text and data section sizes + DOL_hdr aligned_header = map->header; + for(i=0; itext_cnt; i++) { + uint32_t size = swap32(map->header.text_size[i]); + uint32_t padded_size = DOL_ALIGN(size); + if(verbosity >= 2) + fprintf(stderr, "Writing TEXT segment %d...\n", i); + fcpy(dolf, map->elf, swap32(map->header.text_off[i]), map->text_elf_off[i], size); + if (padded_size > size) + fpad(dolf, swap32(map->header.text_off[i]) + size, padded_size - size); + } + for(i=0; idata_cnt; i++) { + uint32_t size = swap32(map->header.data_size[i]); + uint32_t padded_size = DOL_ALIGN(size); + if(verbosity >= 2) + fprintf(stderr, "Writing DATA segment %d...\n", i); + fcpy(dolf, map->elf, swap32(map->header.data_off[i]), map->data_elf_off[i], size); + if (padded_size > size) + fpad(dolf, swap32(map->header.data_off[i]) + size, padded_size - size); + } + + if(verbosity >= 2) + fprintf(stderr, "All done!\n"); + + fclose(map->elf); + fclose(dolf); } -void write_dol(DOL_map* map, const char* dol) { - FILE* dolf; - int written; - int i; +int main(int argc, char **argv) +{ + char **arg; - if (verbosity >= 2) - fprintf(stderr, "Writing DOL file...\n"); + if(argc < 2) { + usage(argv[0]); + return 1; + } + arg = &argv[1]; + argc--; - dolf = fopen(dol, "wb"); - if (!dolf) - perrordie("Could not open DOL file"); + while(argc && *arg[0] == '-') { + if(!strcmp(*arg, "-h")) { + usage(argv[0]); + return 1; + } else if(!strcmp(*arg, "-v")) { + verbosity++; + } else if(!strcmp(*arg, "--")) { + arg++; + argc--; + break; + } else { + fprintf(stderr, "Unrecognized option %s\n", *arg); + usage(argv[0]); + return 1; + } + arg++; + argc--; + } + if(argc < 2) { + usage(argv[0]); + exit(1); + } - if (verbosity >= 2) { - fprintf(stderr, "DOL header:\n"); - for (i = 0; i < MAX(1, map->text_cnt); i++) - fprintf(stderr, " TEXT %d @ 0x%08x [0x%06x] off 0x%08x\n", i, - swap32(map->header.text_addr[i]), swap32(map->header.text_size[i]), - swap32(map->header.text_off[i])); - for (i = 0; i < MAX(1, map->data_cnt); i++) - fprintf(stderr, " DATA %d @ 0x%08x [0x%06x] off 0x%08x\n", i, - swap32(map->header.data_addr[i]), swap32(map->header.data_size[i]), - swap32(map->header.data_off[i])); - if (swap32(map->header.bss_addr) && swap32(map->header.bss_size)) - fprintf(stderr, " BSS @ 0x%08x [0x%06x]\n", swap32(map->header.bss_addr), - swap32(map->header.bss_size)); - fprintf(stderr, " Entry: 0x%08x\n", swap32(map->header.entry)); - fprintf(stderr, "Writing DOL header...\n"); - } + const char *elf_file = arg[0]; + const char *dol_file = arg[1]; - written = fwrite(&map->header, sizeof(DOL_hdr), 1, dolf); - if (written != 1) - ferrordie(dolf, "writing DOL header"); + DOL_map map; - for (i = 0; i < map->text_cnt; i++) { - if (verbosity >= 2) - fprintf(stderr, "Writing TEXT segment %d...\n", i); - fcpy(dolf, map->elf, swap32(map->header.text_off[i]), map->text_elf_off[i], - swap32(map->header.text_size[i]), map->text_elf_size[i]); - } - for (i = 0; i < map->data_cnt; i++) { - if (verbosity >= 2) - fprintf(stderr, "Writing DATA segment %d...\n", i); - fcpy(dolf, map->elf, swap32(map->header.data_off[i]), map->data_elf_off[i], - swap32(map->header.data_size[i]), map->data_elf_size[i]); - } + memset(&map, 0, sizeof(map)); - if (verbosity >= 2) - fprintf(stderr, "All done!\n"); - - fclose(map->elf); - fclose(dolf); -} - -int main(int argc, char** argv) { - char** arg; - - if (argc < 2) { - usage(argv[0]); - return 1; - } - arg = &argv[1]; - argc--; - - while (argc && *arg[0] == '-') { - if (!strcmp(*arg, "-h")) { - usage(argv[0]); - return 1; - } else if (!strcmp(*arg, "-v")) { - verbosity++; - } else if (!strcmp(*arg, "-s")) { - arg++; - argc--; - skip_phdr[atoi(arg[0])] = 1; - } else if (!strcmp(*arg, "--")) { - arg++; - argc--; - break; - } else { - fprintf(stderr, "Unrecognized option %s\n", *arg); - usage(argv[0]); - return 1; - } - arg++; - argc--; - } - if (argc < 2) { - usage(argv[0]); - exit(1); - } - - const char* elf_file = arg[0]; - const char* dol_file = arg[1]; - uint32_t sdata_pdhr = atoi(arg[2]); - uint32_t sbss_pdhr = atoi(arg[3]); - const char* platform = arg[4]; - - DOL_map map; - - memset(&map, 0, sizeof(map)); - - read_elf_segments(&map, elf_file, sdata_pdhr, sbss_pdhr, platform); - map_dol(&map); - write_dol(&map, dol_file); - - return 0; -} + read_elf_segments(&map, elf_file); + map_dol(&map); + write_dol(&map, dol_file); + + return 0; +} \ No newline at end of file diff --git a/tools/requirements.txt b/tools/requirements.txt index 8becbe26de..bcc34c4116 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -7,4 +7,5 @@ colorama ansiwrap watchdog python-Levenshtein -cxxfilt \ No newline at end of file +cxxfilt +oead \ No newline at end of file