mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 23:25:40 +12:00
Add first batch of rebasing
This commit is contained in:
parent
9d0c4c150e
commit
205aedc02c
1 changed files with 255 additions and 1 deletions
|
@ -9,6 +9,229 @@ namespace LDRCommands {
|
|||
};
|
||||
}
|
||||
|
||||
static constexpr u32 CRO_HEADER_SIZE = 0x138;
|
||||
|
||||
class CRO {
|
||||
// CRO header offsets
|
||||
static constexpr u32 HEADER_ID = 0x80;
|
||||
static constexpr u32 HEADER_NAME_OFFSET = 0x84;
|
||||
static constexpr u32 HEADER_NEXT_CRO = 0x88;
|
||||
static constexpr u32 HEADER_PREV_CRO = 0x8C;
|
||||
static constexpr u32 HEADER_CODE_OFFSET = 0xB0;
|
||||
static constexpr u32 HEADER_DATA_OFFSET = 0xB8;
|
||||
static constexpr u32 HEADER_MODULE_NAME_OFFSET = 0xC0;
|
||||
static constexpr u32 HEADER_SEGMENT_TABLE_OFFSET = 0xC8;
|
||||
static constexpr u32 HEADER_SEGMENT_TABLE_SIZE = 0xCC;
|
||||
static constexpr u32 HEADER_NAMED_EXPORT_TABLE_OFFSET = 0xD0;
|
||||
static constexpr u32 HEADER_NAMED_EXPORT_TABLE_SIZE = 0xD4;
|
||||
static constexpr u32 HEADER_INDEXED_EXPORT_TABLE_OFFSET = 0xD8;
|
||||
static constexpr u32 HEADER_EXPORT_STRINGS_OFFSET = 0xE0;
|
||||
static constexpr u32 HEADER_EXPORT_TREE_OFFSET = 0xE8;
|
||||
static constexpr u32 HEADER_IMPORT_MODULE_TABLE_OFFSET = 0xF0;
|
||||
static constexpr u32 HEADER_IMPORT_MODULE_TABLE_SIZE = 0xF4;
|
||||
static constexpr u32 HEADER_IMPORT_PATCHES_OFFSET = 0xF8;
|
||||
static constexpr u32 HEADER_NAMED_IMPORT_TABLE_OFFSET = 0x100;
|
||||
static constexpr u32 HEADER_INDEXED_IMPORT_TABLE_OFFSET = 0x108;
|
||||
static constexpr u32 HEADER_ANONYMOUS_IMPORT_TABLE_OFFSET = 0x110;
|
||||
static constexpr u32 HEADER_IMPORT_STRINGS_OFFSET = 0x118;
|
||||
static constexpr u32 HEADER_STATIC_ANONYMOUS_SYMBOLS_OFFSET = 0x120;
|
||||
static constexpr u32 HEADER_RELOCATION_PATCHES_OFFSET = 0x128;
|
||||
static constexpr u32 HEADER_STATIC_ANONYMOUS_PATCHES_OFFSET = 0x130;
|
||||
|
||||
// Segment table entry offsets
|
||||
static constexpr u32 SEGMENT_OFFSET = 0;
|
||||
static constexpr u32 SEGMENT_ID = 8;
|
||||
static constexpr u32 SEGMENT_ENTRY_SIZE = 12;
|
||||
|
||||
// Segment table entry IDs
|
||||
static constexpr u32 SEGMENT_ID_TEXT = 0;
|
||||
static constexpr u32 SEGMENT_ID_RODATA = 1;
|
||||
static constexpr u32 SEGMENT_ID_DATA = 2;
|
||||
static constexpr u32 SEGMENT_ID_BSS = 3;
|
||||
|
||||
static constexpr u32 NAMED_EXPORT_ENTRY_SIZE = 8;
|
||||
|
||||
// Import module table
|
||||
static constexpr u32 IMPORT_MODULE_TABLE_NAME_OFFSET = 0;
|
||||
static constexpr u32 IMPORT_MODULE_TABLE_INDEXED_OFFSET = 8;
|
||||
static constexpr u32 IMPORT_MODULE_TABLE_ANONYMOUS_OFFSET = 16;
|
||||
static constexpr u32 IMPORT_MODULE_TABLE_ENTRY_SIZE = 20;
|
||||
|
||||
Memory &mem;
|
||||
|
||||
u32 croPointer;
|
||||
|
||||
public:
|
||||
CRO(Memory &mem, u32 croPointer) : mem(mem), croPointer(croPointer) {}
|
||||
~CRO() = default;
|
||||
|
||||
bool load() {
|
||||
const u8* header = (u8*)mem.getReadPointer(croPointer);
|
||||
|
||||
// TODO: verify SHA hashes?
|
||||
|
||||
// Verify CRO magic
|
||||
if (std::memcmp(&header[HEADER_ID], "CRO0", 4) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// These fields are initially 0, the RO service sets them on load. If non-0,
|
||||
// this CRO has already been loaded
|
||||
if ((*(u32*)&header[HEADER_NEXT_CRO] != 0) || (*(u32*)&header[HEADER_PREV_CRO] != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Modify CRO offsets to point at virtual addresses
|
||||
bool rebase(u32 mapVaddr, u32 dataVaddr, u32 bssVaddr) {
|
||||
rebaseHeader(mapVaddr);
|
||||
rebaseSegmentTable(mapVaddr, dataVaddr, bssVaddr);
|
||||
rebaseNamedExportTable(mapVaddr);
|
||||
rebaseImportModuleTable(mapVaddr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rebaseHeader(u32 mapVaddr) {
|
||||
std::puts("Rebasing CRO header");
|
||||
|
||||
const u8* header = (u8*)mem.getReadPointer(croPointer);
|
||||
|
||||
constexpr u32 headerOffsets[] = {
|
||||
HEADER_NAME_OFFSET,
|
||||
HEADER_CODE_OFFSET,
|
||||
HEADER_DATA_OFFSET,
|
||||
HEADER_MODULE_NAME_OFFSET,
|
||||
HEADER_SEGMENT_TABLE_OFFSET,
|
||||
HEADER_NAMED_EXPORT_TABLE_OFFSET,
|
||||
HEADER_INDEXED_EXPORT_TABLE_OFFSET,
|
||||
HEADER_EXPORT_STRINGS_OFFSET,
|
||||
HEADER_EXPORT_TREE_OFFSET,
|
||||
HEADER_IMPORT_MODULE_TABLE_OFFSET,
|
||||
HEADER_IMPORT_PATCHES_OFFSET,
|
||||
HEADER_NAMED_IMPORT_TABLE_OFFSET,
|
||||
HEADER_INDEXED_IMPORT_TABLE_OFFSET,
|
||||
HEADER_ANONYMOUS_IMPORT_TABLE_OFFSET,
|
||||
HEADER_IMPORT_STRINGS_OFFSET,
|
||||
HEADER_STATIC_ANONYMOUS_SYMBOLS_OFFSET, // ?
|
||||
HEADER_RELOCATION_PATCHES_OFFSET,
|
||||
HEADER_STATIC_ANONYMOUS_PATCHES_OFFSET, // ?
|
||||
};
|
||||
|
||||
for (auto offset : headerOffsets) {
|
||||
*(u32*)&header[offset] += mapVaddr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rebaseSegmentTable(u32 mapVaddr, u32 dataVaddr, u32 bssVaddr) {
|
||||
std::puts("Rebasing segment table");
|
||||
|
||||
const u8* header = (u8*)mem.getReadPointer(croPointer);
|
||||
|
||||
const u32 segmentTableAddr = *(u32*)&header[HEADER_SEGMENT_TABLE_OFFSET];
|
||||
const u32 segmentTableSize = *(u32*)&header[HEADER_SEGMENT_TABLE_SIZE];
|
||||
|
||||
if ((segmentTableAddr & 3) != 0) {
|
||||
Helpers::panic("Unaligned segment table address");
|
||||
}
|
||||
|
||||
if (segmentTableSize == 0) {
|
||||
Helpers::panic("Segment table empty");
|
||||
}
|
||||
|
||||
const u8* segmentTable = (u8*)mem.getReadPointer(segmentTableAddr);
|
||||
|
||||
for (u32 segment = 0; segment < segmentTableSize; segment++) {
|
||||
u32* segmentOffset = (u32*)&segmentTable[SEGMENT_ENTRY_SIZE * segment + SEGMENT_OFFSET];
|
||||
|
||||
const u32 segmentID = *(u32*)&segmentTable[SEGMENT_ENTRY_SIZE * segment + SEGMENT_ID];
|
||||
switch (segmentID) {
|
||||
case SEGMENT_ID_DATA: *segmentOffset = dataVaddr; break;
|
||||
case SEGMENT_ID_BSS: *segmentOffset = bssVaddr; break;
|
||||
case SEGMENT_ID_TEXT:
|
||||
case SEGMENT_ID_RODATA:
|
||||
*segmentOffset += mapVaddr; break;
|
||||
default:
|
||||
Helpers::panic("Unknown segment ID");
|
||||
}
|
||||
|
||||
std::printf("Rebasing segment table entry %u (ID = %u), addr = %X\n", segment, segmentID, *segmentOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rebaseNamedExportTable(u32 mapVaddr) {
|
||||
std::puts("Rebasing named export table");
|
||||
|
||||
const u8* header = (u8*)mem.getReadPointer(croPointer);
|
||||
|
||||
const u32 namedExportAddr = *(u32*)&header[HEADER_NAMED_EXPORT_TABLE_OFFSET];
|
||||
const u32 namedExportSize = *(u32*)&header[HEADER_NAMED_EXPORT_TABLE_SIZE];
|
||||
|
||||
if ((namedExportAddr & 3) != 0) {
|
||||
Helpers::panic("Unaligned named export table address");
|
||||
}
|
||||
|
||||
const u8* namedExportTable = (u8*)mem.getReadPointer(namedExportAddr);
|
||||
|
||||
for (u32 namedExport = 0; namedExport < namedExportSize; namedExport++) {
|
||||
u32* nameOffset = (u32*)&namedExportTable[NAMED_EXPORT_ENTRY_SIZE * namedExport];
|
||||
|
||||
assert(*nameOffset != 0);
|
||||
|
||||
*nameOffset += mapVaddr;
|
||||
|
||||
std::printf("Rebasing named export %u, addr = %X\n", namedExport, *nameOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rebaseImportModuleTable(u32 mapVaddr) {
|
||||
std::puts("Rebasing import module table");
|
||||
|
||||
const u8* header = (u8*)mem.getReadPointer(croPointer);
|
||||
|
||||
const u32 importModuleTableAddr = *(u32*)&header[HEADER_IMPORT_MODULE_TABLE_OFFSET];
|
||||
const u32 importModuleTableSize = *(u32*)&header[HEADER_IMPORT_MODULE_TABLE_SIZE];
|
||||
|
||||
if ((importModuleTableAddr & 3) != 0) {
|
||||
Helpers::panic("Unaligned import module table address");
|
||||
}
|
||||
|
||||
const u8* importModuleTable = (u8*)mem.getReadPointer(importModuleTableAddr);
|
||||
|
||||
for (u32 importModule = 0; importModule < importModuleTableSize; importModule++) {
|
||||
u32* nameOffset = (u32*)&importModuleTable[IMPORT_MODULE_TABLE_ENTRY_SIZE * importModule + IMPORT_MODULE_TABLE_NAME_OFFSET];
|
||||
|
||||
assert(*nameOffset != 0);
|
||||
|
||||
*nameOffset += mapVaddr;
|
||||
|
||||
u32 *indexedOffset = (u32*)&importModuleTable[IMPORT_MODULE_TABLE_ENTRY_SIZE * importModule + IMPORT_MODULE_TABLE_INDEXED_OFFSET];
|
||||
|
||||
assert(*indexedOffset != 0);
|
||||
|
||||
*indexedOffset += mapVaddr;
|
||||
|
||||
u32 *anonymousOffset = (u32*)&importModuleTable[IMPORT_MODULE_TABLE_ENTRY_SIZE * importModule + IMPORT_MODULE_TABLE_ANONYMOUS_OFFSET];
|
||||
|
||||
assert(*anonymousOffset != 0);
|
||||
|
||||
*anonymousOffset += mapVaddr;
|
||||
|
||||
std::printf("Rebasing import module %u, name addr = %X, indexed addr = %X, anonymous addr = %X\n", importModule, *nameOffset, *indexedOffset, *anonymousOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void LDRService::reset() {}
|
||||
|
||||
void LDRService::handleSyncRequest(u32 messagePointer) {
|
||||
|
@ -54,7 +277,38 @@ void LDRService::loadCRONew(u32 messagePointer) {
|
|||
const u32 fixLevel = mem.read32(messagePointer + 40);
|
||||
const Handle process = mem.read32(messagePointer + 52);
|
||||
|
||||
log("LDR_RO::LoadCRONew (buffer = %08X, vaddr = %08X, size = %08X, .data vaddr = %08X, .data size = %08X, .bss vaddr = %08X, .bss size = %08X, auto link = %d, fix level = %X, process = %X)\n", croPointer, mapVaddr, size, dataVaddr, dataSize, bssVaddr, bssSize, autoLink, fixLevel, process);
|
||||
std::printf("LDR_RO::LoadCRONew (buffer = %08X, vaddr = %08X, size = %08X, .data vaddr = %08X, .data size = %08X, .bss vaddr = %08X, .bss size = %08X, auto link = %d, fix level = %X, process = %X)\n", croPointer, mapVaddr, size, dataVaddr, dataSize, bssVaddr, bssSize, autoLink, fixLevel, process);
|
||||
|
||||
// Sanity checks
|
||||
if (size < CRO_HEADER_SIZE) {
|
||||
Helpers::panic("CRO too small\n");
|
||||
}
|
||||
|
||||
if ((size & mem.pageMask) != 0) {
|
||||
Helpers::panic("Unaligned CRO size\n");
|
||||
}
|
||||
|
||||
if ((croPointer & mem.pageMask) != 0) {
|
||||
Helpers::panic("Unaligned CRO pointer\n");
|
||||
}
|
||||
|
||||
if ((mapVaddr & mem.pageMask) != 0) {
|
||||
Helpers::panic("Unaligned CRO output vaddr\n");
|
||||
}
|
||||
|
||||
// Map CRO to output address
|
||||
mem.mirrorMapping(mapVaddr, croPointer, size);
|
||||
|
||||
CRO cro(mem, croPointer);
|
||||
|
||||
if (!cro.load()) {
|
||||
Helpers::panic("Failed to load CRO");
|
||||
}
|
||||
|
||||
if (!cro.rebase(mapVaddr, dataVaddr, bssVaddr)) {
|
||||
Helpers::panic("Failed to rebase CRO");
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x9, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, size);
|
||||
|
|
Loading…
Add table
Reference in a new issue