Shift Fixes

This commit is contained in:
jdflyer 2022-01-16 15:16:08 -07:00
parent 8a9f18c45f
commit db9079ede2
10 changed files with 450 additions and 481 deletions

View File

@ -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)

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -1,98 +1,106 @@
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <sys/param.h>
#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<phnum; i++) {
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(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; 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));
}
}
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; 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)));
}
}
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<size; i++)
fputc(0, dst);
}
#define BLOCK (1024 * 1024)
void write_dol(DOL_map *map, const char *dol)
{
FILE *dolf;
int written;
int i;
void fcpy(FILE* dst, FILE* src, uint32_t dst_off, uint32_t src_off, uint32_t dst_size, uint32_t src_size) {
int left = src_size;
int read;
int written;
int block;
void* blockbuf;
char empty_buffer[8] = { 0,0,0,0,0,0,0,0 };
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;
}
left = dst_size - src_size;
while (left) {
block = MIN(sizeof(empty_buffer), left);
fwrite(empty_buffer, 1, block, dst);
left -= block;
}
free(blockbuf);
if(verbosity >= 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; i<MAX(1,map->text_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; i<MAX(1,map->data_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; i<ARRAY_COUNT(aligned_header.text_size); i++)
aligned_header.text_size[i] = swap32(DOL_ALIGN(swap32(aligned_header.text_size[i])));
for(i=0; i<ARRAY_COUNT(aligned_header.data_size); i++)
aligned_header.data_size[i] = swap32(DOL_ALIGN(swap32(aligned_header.data_size[i])));
written = fwrite(&aligned_header, sizeof(DOL_hdr), 1, dolf);
if(written != 1)
ferrordie(dolf, "writing DOL header");
for(i=0; i<map->text_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; i<map->data_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;
}

View File

@ -7,4 +7,5 @@ colorama
ansiwrap
watchdog
python-Levenshtein
cxxfilt
cxxfilt
oead