summaryrefslogtreecommitdiff
path: root/src/Dolphin/os/OSLink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Dolphin/os/OSLink.c')
-rw-r--r--src/Dolphin/os/OSLink.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/src/Dolphin/os/OSLink.c b/src/Dolphin/os/OSLink.c
new file mode 100644
index 0000000..933e55b
--- /dev/null
+++ b/src/Dolphin/os/OSLink.c
@@ -0,0 +1,556 @@
+#include "dolphin/os.h"
+
+#define SHN_UNDEF 0
+#define SHN_LORESERVE 0xff00
+#define SHN_LOPROC 0xff00
+#define SHN_HIPROC 0xff1f
+#define SHN_ABS 0xfff1
+#define SHN_COMMON 0xfff2
+#define SHN_HIRESERVE 0xffff
+
+#define ELF32_R_SYM(i) ((i) >> 8)
+#define ELF32_R_TYPE(i) ((unsigned char)(i))
+#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
+
+// Name Value Field Calculation
+#define R_PPC_NONE 0 // none none
+#define R_PPC_ADDR32 1 // word32 S + A
+#define R_PPC_ADDR24 2 // low24* (S + A) >> 2
+#define R_PPC_ADDR16 3 // half16* S + A
+#define R_PPC_ADDR16_LO 4 // half16 #lo(S + A)
+#define R_PPC_ADDR16_HI 5 // half16 #hi(S + A)
+#define R_PPC_ADDR16_HA 6 // half16 #ha(S + A)
+#define R_PPC_ADDR14 7 // low14* (S + A) >> 2
+#define R_PPC_ADDR14_BRTAKEN 8 // low14* (S + A) >> 2
+#define R_PPC_ADDR14_BRNTAKEN 9 // low14* (S + A) >> 2
+#define R_PPC_REL24 10 // low24* (S + A - P) >> 2
+#define R_PPC_REL14 11 // low14* (S + A - P) >> 2
+#define R_PPC_REL14_BRTAKEN 12 // low14* (S + A - P) >> 2
+#define R_PPC_REL14_BRNTAKEN 13 // low14* (S + A - P) >> 2
+
+#define R_PPC_GOT16 14 // half16* G + A
+#define R_PPC_GOT16_LO 15 // half16 #lo(G + A)
+#define R_PPC_GOT16_HI 16 // half16 #hi(G + A)
+#define R_PPC_GOT16_HA 17 // half16 #ha(G + A)
+#define R_PPC_PLTREL24 18 // low24* (L + A - P) >> 2
+#define R_PPC_COPY 19 // none none
+#define R_PPC_GLOB_DAT 20 // word32 S + A
+#define R_PPC_JMP_SLOT 21 // none
+#define R_PPC_RELATIVE 22 // word32 B + A
+
+#define R_PPC_LOCAL24PC 23 // low24*
+
+#define R_PPC_UADDR32 24 // word32 S + A
+#define R_PPC_UADDR16 25 // half16* S + A
+#define R_PPC_REL32 26 // word32 S + A - P
+
+#define R_PPC_PLT32 27 // word32 L + A
+#define R_PPC_PLTREL32 28 // word32 L + A - P
+#define R_PPC_PLT16_LO 29 // half16 #lo(L + A)
+#define R_PPL_PLT16_HI 30 // half16 #hi(L + A)
+#define R_PPC_PLT16_HA 31 // half16 #ha(L + A)
+
+#define R_PPC_SDAREL16 32 // half16* S + A - _SDA_BASE_
+#define R_PPC_SECTOFF 33 // half16* R + A
+#define R_PPC_SECTOFF_LO 34 // half16 #lo(R + A)
+#define R_PPC_SECTOFF_HI 35 // half16 #hi(R + A)
+#define R_PPC_SECTOFF_HA 36 // half16 #ha(R + A)
+#define R_PPC_ADDR30 37 // word30 (S + A - P) >> 2
+
+#define R_PPC_EMB_NADDR32 101 // uword32 N (A - S)
+#define R_PPC_EMB_NADDR16 102 // uhalf16 Y (A - S)
+#define R_PPC_EMB_NADDR16_LO 103 // uhalf16 N #lo(A - S)
+#define R_PPC_EMB_NADDR16_HI 104 // uhalf16 N #hi(A - S)
+#define R_PPC_EMB_NADDR16_HA 105 // uhalf16 N #ha(A - S)
+#define R_PPC_EMB_SDAI16 106 // uhalf16 Y T
+#define R_PPC_EMB_SDA2I16 107 // uhalf16 Y U
+#define R_PPC_EMB_SDA2REL 108 // uhalf16 Y S + A - _SDA2_BASE_
+#define R_PPC_EMB_SDA21 109 // ulow21 N
+#define R_PPC_EMB_MRKREF 110 // none N
+#define R_PPC_EMB_RELSEC16 111 // uhalf16 Y V + A
+#define R_PPC_EMB_RELST_LO 112 // uhalf16 N #lo(W + A)
+#define R_PPC_EMB_RELST_HI 113 // uhalf16 N #hi(W + A)
+#define R_PPC_EMB_RELST_HA 114 // uhalf16 N #ha(W + A)
+#define R_PPC_EMB_BIT_FLD 115 // uword32 Y
+#define R_PPC_EMB_RELSDA 116 // uhalf16 Y
+
+OSModuleQueue __OSModuleInfoList : (OS_BASE_CACHED | 0x30C8);
+const void* __OSStringTable : (OS_BASE_CACHED | 0x30D0);
+
+#pragma dont_inline on
+__declspec(weak) void OSNotifyLink(OSModuleInfo* module) {}
+
+__declspec(weak) void OSNotifyUnlink(OSModuleInfo* module) {}
+
+#pragma dont_inline reset
+
+#define EnqueueTail(queue, moduleInfo, link) \
+ do { \
+ OSModuleInfo* __prev; \
+ \
+ __prev = (queue)->tail; \
+ if (__prev == NULL) \
+ (queue)->head = (moduleInfo); \
+ else \
+ __prev->link.next = (moduleInfo); \
+ (moduleInfo)->link.prev = __prev; \
+ (moduleInfo)->link.next = NULL; \
+ (queue)->tail = (moduleInfo); \
+ } while (0)
+
+#define DequeueItem(queue, moduleInfo, link) \
+ do { \
+ OSModuleInfo* __next; \
+ OSModuleInfo* __prev; \
+ \
+ __next = (moduleInfo)->link.next; \
+ __prev = (moduleInfo)->link.prev; \
+ \
+ if (__next == NULL) \
+ (queue)->tail = __prev; \
+ else \
+ __next->link.prev = __prev; \
+ \
+ if (__prev == NULL) \
+ (queue)->head = __next; \
+ else \
+ __prev->link.next = __next; \
+ } while (0)
+
+void OSSetStringTable(const void* stringTable) { __OSStringTable = stringTable; }
+
+static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) {
+ OSModuleID idNew;
+ OSImportInfo* imp;
+ OSRel* rel;
+ OSSectionInfo* si;
+ OSSectionInfo* siFlush;
+ u32* p;
+ u32 offset;
+ u32 x;
+
+ idNew = newModule ? newModule->info.id : 0;
+ for (imp = (OSImportInfo*)module->impOffset;
+ imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) {
+ if (imp->id == idNew) {
+ goto Found;
+ }
+ }
+ return FALSE;
+
+Found:
+ siFlush = 0;
+ for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) {
+ (u8*)p += rel->offset;
+ if (idNew) {
+ si = &OSGetSectionInfo(newModule)[rel->section];
+ offset = OS_SECTIONINFO_OFFSET(si->offset);
+ } else {
+ offset = 0;
+ }
+ switch (rel->type) {
+ case R_PPC_NONE:
+ break;
+ case R_PPC_ADDR32:
+ x = offset + rel->addend;
+ *p = x;
+ break;
+ case R_PPC_ADDR24:
+ x = offset + rel->addend;
+ *p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
+ break;
+ case R_PPC_ADDR16:
+ x = offset + rel->addend;
+ *(u16*)p = (u16)(x & 0xffff);
+ break;
+ case R_PPC_ADDR16_LO:
+ x = offset + rel->addend;
+ *(u16*)p = (u16)(x & 0xffff);
+ break;
+ case R_PPC_ADDR16_HI:
+ x = offset + rel->addend;
+ *(u16*)p = (u16)(((x >> 16) & 0xffff));
+ break;
+ case R_PPC_ADDR16_HA:
+ x = offset + rel->addend;
+ *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff);
+ break;
+ case R_PPC_ADDR14:
+ case R_PPC_ADDR14_BRTAKEN:
+ case R_PPC_ADDR14_BRNTAKEN:
+ x = offset + rel->addend;
+ *p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
+ break;
+ case R_PPC_REL24:
+ x = offset + rel->addend - (u32)p;
+ *p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
+ break;
+ case R_PPC_REL14:
+ case R_PPC_REL14_BRTAKEN:
+ case R_PPC_REL14_BRNTAKEN:
+ x = offset + rel->addend - (u32)p;
+ *p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
+ break;
+ case R_DOLPHIN_NOP:
+ break;
+ case R_DOLPHIN_SECTION:
+ si = &OSGetSectionInfo(module)[rel->section];
+ p = (u32*)OS_SECTIONINFO_OFFSET(si->offset);
+ if (siFlush) {
+ offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
+ DCFlushRange((void*)offset, siFlush->size);
+ ICInvalidateRange((void*)offset, siFlush->size);
+ }
+ siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0;
+ break;
+ default:
+ OSReport("OSLink: unknown relocation type %3d\n", rel->type);
+ break;
+ }
+ }
+
+ if (siFlush) {
+ offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
+ DCFlushRange((void*)offset, siFlush->size);
+ ICInvalidateRange((void*)offset, siFlush->size);
+ }
+
+ return TRUE;
+}
+
+#if OS_MODULE_VERSION >= 3
+static BOOL Link(OSModuleInfo* newModule, void* bss, BOOL fixed) {
+ u32 i;
+ OSSectionInfo* si;
+ OSModuleHeader* moduleHeader;
+ OSModuleInfo* moduleInfo;
+ OSImportInfo* imp;
+
+ moduleHeader = (OSModuleHeader*)newModule;
+ moduleHeader->bssSection = 0;
+
+ if (OS_MODULE_VERSION < newModule->version ||
+ 2 <= newModule->version &&
+ (moduleHeader->align && (u32)newModule % moduleHeader->align != 0 ||
+ moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) {
+ return FALSE;
+ }
+
+ EnqueueTail(&__OSModuleInfoList, newModule, link);
+ newModule->sectionInfoOffset += (u32)moduleHeader;
+ moduleHeader->relOffset += (u32)moduleHeader;
+ moduleHeader->impOffset += (u32)moduleHeader;
+ if (3 <= newModule->version) {
+ moduleHeader->fixSize += (u32)moduleHeader;
+ }
+ for (i = 1; i < newModule->numSections; i++) {
+ si = &OSGetSectionInfo(newModule)[i];
+ if (si->offset != 0) {
+ si->offset += (u32)moduleHeader;
+ } else if (si->size != 0) {
+ moduleHeader->bssSection = (u8)i;
+ si->offset = (u32)bss;
+ bss = (void*)((u32)bss + si->size);
+ }
+ }
+ for (imp = (OSImportInfo*)moduleHeader->impOffset;
+ imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) {
+ imp->offset += (u32)moduleHeader;
+ }
+ if (moduleHeader->prologSection != SHN_UNDEF) {
+ moduleHeader->prolog +=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->prologSection].offset);
+ }
+ if (moduleHeader->epilogSection != SHN_UNDEF) {
+ moduleHeader->epilog +=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->epilogSection].offset);
+ }
+ if (moduleHeader->unresolvedSection != SHN_UNDEF) {
+ moduleHeader->unresolved +=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->unresolvedSection].offset);
+ }
+ if (__OSStringTable) {
+ newModule->nameOffset += (u32)__OSStringTable;
+ }
+
+ Relocate(0, moduleHeader);
+
+ for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
+ Relocate(moduleHeader, (OSModuleHeader*)moduleInfo);
+ if (moduleInfo != newModule) {
+ Relocate((OSModuleHeader*)moduleInfo, moduleHeader);
+ }
+ }
+
+ if (fixed) {
+ for (imp = (OSImportInfo*)moduleHeader->impOffset;
+ imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) {
+ if (imp->id == 0 || imp->id == newModule->id) {
+ moduleHeader->impSize = (u32)((u8*)imp - (u8*)moduleHeader->impOffset);
+ break;
+ }
+ }
+ }
+
+ memset(bss, 0, moduleHeader->bssSize);
+
+ OSNotifyLink(newModule);
+
+ return TRUE;
+}
+
+BOOL OSLink(OSModuleInfo* newModule, void* bss) { return Link(newModule, bss, FALSE); }
+
+BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss) {
+ if (OS_MODULE_VERSION < newModule->version || newModule->version < 3) {
+ return FALSE;
+ }
+ return Link(newModule, bss, TRUE);
+}
+#else
+BOOL OSLink(OSModuleInfo* newModule, void* bss) {
+ u32 i;
+ OSSectionInfo* si;
+ OSModuleHeader* moduleHeader;
+ OSModuleInfo* moduleInfo;
+ OSImportInfo* imp;
+
+ moduleHeader = (OSModuleHeader*)newModule;
+ moduleHeader->bssSection = 0;
+
+ if (OS_MODULE_VERSION < newModule->version ||
+ 2 <= newModule->version &&
+ (moduleHeader->align && (u32)newModule % moduleHeader->align != 0 ||
+ moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) {
+ return FALSE;
+ }
+
+ EnqueueTail(&__OSModuleInfoList, newModule, link);
+ memset(bss, 0, moduleHeader->bssSize);
+ newModule->sectionInfoOffset += (u32)moduleHeader;
+ moduleHeader->relOffset += (u32)moduleHeader;
+ moduleHeader->impOffset += (u32)moduleHeader;
+
+ for (i = 1; i < newModule->numSections; i++) {
+ si = &OSGetSectionInfo(newModule)[i];
+ if (si->offset != 0) {
+ si->offset += (u32)moduleHeader;
+ } else if (si->size != 0) {
+ moduleHeader->bssSection = (u8)i;
+ si->offset = (u32)bss;
+ bss = (void*)((u32)bss + si->size);
+ }
+ }
+ for (imp = (OSImportInfo*)moduleHeader->impOffset;
+ imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) {
+ imp->offset += (u32)moduleHeader;
+ }
+ if (moduleHeader->prologSection != SHN_UNDEF) {
+ moduleHeader->prolog +=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->prologSection].offset);
+ }
+ if (moduleHeader->epilogSection != SHN_UNDEF) {
+ moduleHeader->epilog +=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->epilogSection].offset);
+ }
+ if (moduleHeader->unresolvedSection != SHN_UNDEF) {
+ moduleHeader->unresolved +=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->unresolvedSection].offset);
+ }
+ if (__OSStringTable) {
+ newModule->nameOffset += (u32)__OSStringTable;
+ }
+
+ Relocate(0, moduleHeader);
+
+ for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
+ Relocate(moduleHeader, (OSModuleHeader*)moduleInfo);
+ if (moduleInfo != newModule) {
+ Relocate((OSModuleHeader*)moduleInfo, moduleHeader);
+ }
+ }
+
+ OSNotifyLink(newModule);
+
+ return TRUE;
+}
+#endif
+
+static BOOL Undo(OSModuleHeader* newModule, OSModuleHeader* module) {
+ OSModuleID idNew;
+ OSImportInfo* imp;
+ OSRel* rel;
+ OSSectionInfo* si;
+ OSSectionInfo* siFlush;
+ u32* p;
+ u32 offset;
+ u32 x;
+
+ idNew = newModule->info.id;
+ for (imp = (OSImportInfo*)module->impOffset;
+ imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) {
+ if (imp->id == idNew) {
+ goto Found;
+ }
+ }
+ return FALSE;
+
+Found:
+ siFlush = 0;
+ for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) {
+ (u8*)p += rel->offset;
+ si = &OSGetSectionInfo(newModule)[rel->section];
+ offset = OS_SECTIONINFO_OFFSET(si->offset);
+ x = 0;
+ switch (rel->type) {
+ case R_PPC_NONE:
+ break;
+ case R_PPC_ADDR32:
+ *p = x;
+ break;
+ case R_PPC_ADDR24:
+ *p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
+ break;
+ case R_PPC_ADDR16:
+ *(u16*)p = (u16)(x & 0xffff);
+ break;
+ case R_PPC_ADDR16_LO:
+ *(u16*)p = (u16)(x & 0xffff);
+ break;
+ case R_PPC_ADDR16_HI:
+ *(u16*)p = (u16)(((x >> 16) & 0xffff));
+ break;
+ case R_PPC_ADDR16_HA:
+ *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff);
+ break;
+ case R_PPC_ADDR14:
+ case R_PPC_ADDR14_BRTAKEN:
+ case R_PPC_ADDR14_BRNTAKEN:
+ *p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
+ break;
+ case R_PPC_REL24:
+ if (module->unresolvedSection != SHN_UNDEF) {
+ x = (u32)module->unresolved - (u32)p;
+ }
+ *p = (*p & ~0x03fffffc) | (x & 0x03fffffc);
+ break;
+ case R_PPC_REL14:
+ case R_PPC_REL14_BRTAKEN:
+ case R_PPC_REL14_BRNTAKEN:
+ *p = (*p & ~0x0000fffc) | (x & 0x0000fffc);
+ break;
+ case R_DOLPHIN_NOP:
+ break;
+ case R_DOLPHIN_SECTION:
+ si = &OSGetSectionInfo(module)[rel->section];
+ p = (u32*)OS_SECTIONINFO_OFFSET(si->offset);
+ if (siFlush) {
+ offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
+ DCFlushRange((void*)offset, siFlush->size);
+ ICInvalidateRange((void*)offset, siFlush->size);
+ }
+ siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0;
+ break;
+ default:
+ OSReport("OSUnlink: unknown relocation type %3d\n", rel->type);
+ break;
+ }
+ }
+
+ if (siFlush) {
+ offset = OS_SECTIONINFO_OFFSET(siFlush->offset);
+ DCFlushRange((void*)offset, siFlush->size);
+ ICInvalidateRange((void*)offset, siFlush->size);
+ }
+
+ return TRUE;
+}
+
+BOOL OSUnlink(OSModuleInfo* oldModule) {
+ OSModuleHeader* moduleHeader;
+ OSModuleInfo* moduleInfo;
+ u32 i;
+ OSSectionInfo* si;
+ OSImportInfo* imp;
+
+ moduleHeader = (OSModuleHeader*)oldModule;
+
+ DequeueItem(&__OSModuleInfoList, oldModule, link);
+
+ for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
+ Undo(moduleHeader, (OSModuleHeader*)moduleInfo);
+ }
+
+ OSNotifyUnlink(oldModule);
+
+ if (__OSStringTable) {
+ oldModule->nameOffset -= (u32)__OSStringTable;
+ }
+ if (moduleHeader->prologSection != SHN_UNDEF) {
+ moduleHeader->prolog -=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->prologSection].offset);
+ }
+ if (moduleHeader->epilogSection != SHN_UNDEF) {
+ moduleHeader->epilog -=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->epilogSection].offset);
+ }
+ if (moduleHeader->unresolvedSection != SHN_UNDEF) {
+ moduleHeader->unresolved -=
+ OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->unresolvedSection].offset);
+ }
+ for (imp = (OSImportInfo*)moduleHeader->impOffset;
+ imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) {
+ imp->offset -= (u32)moduleHeader;
+ }
+ for (i = 1; i < oldModule->numSections; i++) {
+ si = &OSGetSectionInfo(oldModule)[i];
+ if (i == moduleHeader->bssSection) {
+ moduleHeader->bssSection = 0;
+ si->offset = 0;
+ } else if (si->offset != 0) {
+ si->offset -= (u32)moduleHeader;
+ }
+ }
+ moduleHeader->relOffset -= (u32)moduleHeader;
+ moduleHeader->impOffset -= (u32)moduleHeader;
+ oldModule->sectionInfoOffset -= (u32)moduleHeader;
+
+ return TRUE;
+}
+
+void __OSModuleInit(void) {
+ __OSModuleInfoList.head = __OSModuleInfoList.tail = 0;
+ __OSStringTable = 0;
+}
+
+OSModuleInfo* OSSearchModule(void* ptr, u32* section, u32* offset) {
+ OSModuleInfo* moduleInfo;
+ OSSectionInfo* sectionInfo;
+ u32 i;
+ u32 baseSection;
+
+ if (ptr == NULL) {
+ return NULL;
+ }
+
+ for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) {
+ sectionInfo = OSGetSectionInfo(moduleInfo);
+ for (i = 0; i < moduleInfo->numSections; ++i) {
+ if (sectionInfo->size) {
+ baseSection = OS_SECTIONINFO_OFFSET(sectionInfo->offset);
+ if (baseSection <= (u32)ptr && (u32)ptr < baseSection + sectionInfo->size) {
+ if (section) {
+ *section = i;
+ }
+ if (offset) {
+ *offset = (u32)ptr - baseSection;
+ }
+ return moduleInfo;
+ }
+ }
+ sectionInfo++;
+ }
+ }
+
+ return NULL;
+}