helos1/execformat/pe/reloc.c

109 lines
3.0 KiB
C
Raw Permalink Normal View History

2021-10-10 14:39:17 +08:00
#include "reloc.h"
#include "../../runtime/panic_assert.h"
#include <string.h>
static inline int __local_strncmp(const char *s1, const char *s2, size_t n) {
while (n && *s1 && (*s1 == *s2)) {
++s1;
++s2;
--n;
}
if (n == 0) {
return 0;
} else {
return (*(unsigned char *)s1 - *(unsigned char *)s2);
}
}
static const char *caseFlags(uint16_t type) {
#define CASE(expr) \
case EXECFORMAT_PE_BASERELOC_##expr: \
return #expr;
switch (type) {
CASE(ABSOLUTE)
CASE(HIGH)
CASE(LOW)
CASE(HIGHLOW)
CASE(HIGHADJ)
CASE(DIR64)
default:
return "(Unknown)";
}
#undef CASE
}
void execformat_pe_BaseRelocate(execformat_pe_PortableExecutable *pe, void *relocBase, void *relocEnd, uint64_t currentBase, uint64_t targetBase) {
if (pe->begin == 0)
return;
if (currentBase == 0) {
if (pe->isPE32P)
currentBase = ((execformat_pe_OptionalHeader_PE32P *)pe->optional)->win.imageBase;
else
currentBase = ((execformat_pe_OptionalHeader_PE32 *)pe->optional)->win.imageBase;
}
void *reloc = 0, *reloc_end;
if (relocBase != 0 && relocEnd != 0) {
reloc = relocBase;
reloc_end = relocEnd;
} else {
// find the .reloc section
for (int i = 0; i < pe->numSections; i++)
if (__local_strncmp(pe->sections[i].name, ".reloc", 6) == 0) {
reloc = pe->begin + pe->sections[i].virtualAddr;
reloc_end = reloc + pe->sections[i].virtualSize;
break;
}
if (reloc == 0)
return; // no .reloc section
}
uint64_t diff = targetBase - currentBase;
while (reloc < reloc_end) {
execformat_pe_BaseRelocBlock *block = reloc;
int entries = (block->blockSize - 8) / 2;
assert((block->blockSize - 8) % 2 == 0);
printf("BaseReloc Block RVA=0x%08x, entries=%d\n", block->pageOffset, entries);
for (int i = 0; i < entries; i++) {
void *target = pe->begin + block->pageOffset + (block->entries[i] & EXECFORMAT_PE_BASERELOC_OFFSET_MASK);
//uint64_t cur = 0, new = 0;
switch (block->entries[i] & EXECFORMAT_PE_BASERELOC_FLAG_MASK) {
case EXECFORMAT_PE_BASERELOC_HIGH:
//cur = *((uint16_t *)target);
*((uint16_t *)target) += (uint16_t)(diff >> 16);
//new = *((uint16_t *)target);
break;
case EXECFORMAT_PE_BASERELOC_LOW:
//cur = *((uint16_t *)target);
*((uint16_t *)target) += (uint16_t)(diff);
//new = *((uint16_t *)target);
break;
case EXECFORMAT_PE_BASERELOC_HIGHLOW:
//cur = *((uint32_t *)target);
*((uint32_t *)target) += (uint32_t)(diff);
//new = *((uint32_t *)target);
break;
case EXECFORMAT_PE_BASERELOC_DIR64:
//cur = *((uint64_t *)target);
*((uint64_t *)target) += (diff);
//new = *((uint64_t *)target);
break;
case EXECFORMAT_PE_BASERELOC_HIGHADJ:
i++;
break;
}
//printf(" Reloc Off0x%08llx CUR=0x%08llx(Off0x%08llx), NEW=0x%llx, Type=%s\n", target - pe->begin, cur, cur - currentBase, new, caseFlags(block->entries[i] & EXECFORMAT_PE_BASERELOC_FLAG_MASK));
}
reloc += block->blockSize;
}
}