📄 loader.c
字号:
ulong blocksize;
LPDWORD FixupAddress;
#ifndef x86
LPWORD FixupAddressHi;
BOOL MatchedReflo=FALSE;
#endif
DWORD FixupValue;
LPWORD currptr;
DWORD offset;
#if defined(x86)
#define RELOC_LIMIT 8192
#else
#define RELOC_LIMIT 4096
#endif
DWORD reloc_limit = RELOC_LIMIT;
#ifdef MIPS
if (IsMIPS16Supported)
reloc_limit = 8192;
#endif
LeaveCriticalSection(&PagerCS);
if (!(blocksize = eptr->e32_unit[FIX].size)) { // No relocations
EnterCriticalSection(&PagerCS);
return TRUE;
}
blockstart = blockptr = (struct info *)(ZeroPtr(BasePtr)+BaseAdj+eptr->e32_unit[FIX].rva);
if (BaseAdj != ProcArray[0].dwVMBase)
BaseAdj = 0; // for processes
DEBUGMSG(ZONE_LOADER1,(TEXT("Relocations: BasePtr = %8.8lx, BaseAdj = %8.8lx, VBase = %8.8lx, pMem = %8.8lx, pData = %8.8lx\r\n"),
BasePtr,BaseAdj, eptr->e32_vbase, pMem, pData));
if (!(offset = BasePtr - BaseAdj - eptr->e32_vbase)) {
EnterCriticalSection(&PagerCS);
DEBUGMSG(ZONE_LOADER1,(TEXT("Relocations: No Relocation Required\r\n")));
return TRUE; // no adjustment needed
}
DEBUGMSG(ZONE_LOADER1,(TEXT("RelocatePage: Offset is %8.8lx\r\n"),offset));
if ((ZeroPtr(pMem) >= ZeroPtr(BasePtr+eptr->e32_unit[FIX].rva)) &&
(ZeroPtr(pMem) < ZeroPtr(BasePtr+eptr->e32_unit[FIX].rva+eptr->e32_unit[FIX].size))) {
EnterCriticalSection(&PagerCS);
return TRUE;
}
while (((ulong)blockptr < (ulong)blockstart + blocksize) && blockptr->size) {
currptr = (LPWORD)(((ulong)blockptr)+sizeof(struct info));
if ((ulong)currptr >= ((ulong)blockptr+blockptr->size)) {
blockptr = (struct info *)(((ulong)blockptr)+blockptr->size);
continue;
}
if ((ZeroPtr(BasePtr+blockptr->rva) > ZeroPtr(pMem)) || (ZeroPtr(BasePtr+blockptr->rva)+reloc_limit <= ZeroPtr(pMem))) {
blockptr = (struct info *)(((ulong)blockptr)+blockptr->size);
continue;
}
goto fixuppage;
}
EnterCriticalSection(&PagerCS);
return TRUE;
fixuppage:
DEBUGMSG(ZONE_LOADER1,(L"Fixing up %8.8lx %8.8lx, %8.8lx\r\n",blockptr->rva,optr->o32_rva,optr->o32_realaddr));
while ((ulong)currptr < ((ulong)blockptr+blockptr->size)) {
#ifdef x86
Comp1 = ZeroPtr(pMem);
Comp2 = ZeroPtr(BasePtr + blockptr->rva);
Comp1 = (Comp2 + 0x1000 == Comp1) ? 1 : 0;
#else
Comp1 = ZeroPtr(pMem) - ZeroPtr(BasePtr + blockptr->rva);
Comp2 = (DWORD)(*currptr&0xfff);
#if defined(MIPS)
// Comp1 is relative start of page being relocated
// Comp2 is relative address of fixup
// For MIPS16 jump, deal with fixups on this page or the preceding page
// For all other fixups, deal with this page only
if (IsMIPS16Supported && (*currptr>>12 == IMAGE_REL_BASED_MIPS_JMPADDR16)) {
if ((Comp1 > Comp2 + PAGE_SIZE) || (Comp1 + PAGE_SIZE <= Comp2)) {
currptr++;
continue;
}
// PrevPage: is fixup located on the page preceding the one being relocated?
PrevPage = (Comp1 > Comp2);
// Comp1: is fixup located in the block preceding the one that contains the current page?
Comp1 = PrevPage && ((Comp1 & 0xfff) == 0);
} else {
#endif
if ((Comp1 > Comp2) || (Comp1 + PAGE_SIZE <= Comp2)) {
if (*currptr>>12 == IMAGE_REL_BASED_HIGHADJ)
currptr++;
currptr++;
continue;
}
#if defined(MIPS)
// Comp1: is fixup located in the block preceding the one that contains the current page? (No.)
if (IsMIPS16Supported)
Comp1 = 0;
}
#endif
#endif
#if defined(x86)
FixupAddress = (LPDWORD)(((pData&0xfffff000) + (*currptr&0xfff)) - 4096*Comp1);
#else
FixupAddress = (LPDWORD)((pData&0xfffff000) + (*currptr&0xfff));
#ifdef MIPS
if (IsMIPS16Supported)
FixupAddress = (LPDWORD) (FixupAddress - 4096*Comp1);
#endif
#endif
DEBUGMSG(ZONE_LOADER2,(TEXT("type %d, low %8.8lx, page %8.8lx, addr %8.8lx\r\n"),
(*currptr>>12)&0xf, (*currptr)&0x0fff,blockptr->rva,FixupAddress));
switch (*currptr>>12) {
case IMAGE_REL_BASED_ABSOLUTE: // Absolute - no fixup required.
break;
#ifdef x86
case IMAGE_REL_BASED_HIGHLOW: // Word - (32-bits) relocate the entire address.
if (Comp1 && (((DWORD)FixupAddress & 0xfff) > 0xffc)) {
switch ((DWORD)FixupAddress & 0x3) {
case 1:
FixupValue = (prevdw>>8) + (*((LPBYTE)FixupAddress+3) <<24 ) + offset;
*((LPBYTE)FixupAddress+3) = (BYTE)(FixupValue >> 24);
break;
case 2:
FixupValue = (prevdw>>16) + (*((LPWORD)FixupAddress+1) << 16) + offset;
*((LPWORD)FixupAddress+1) = (WORD)(FixupValue >> 16);
break;
case 3:
FixupValue = (prevdw>>24) + ((*(LPDWORD)((LPBYTE)FixupAddress+1)) << 8) + offset;
*(LPWORD)((LPBYTE)FixupAddress+1) = (WORD)(FixupValue >> 8);
*((LPBYTE)FixupAddress+3) = (BYTE)(FixupValue >> 24);
break;
}
} else if (!Comp1) {
if (((DWORD)FixupAddress & 0xfff) > 0xffc) {
switch ((DWORD)FixupAddress & 0x3) {
case 1:
FixupValue = *(LPWORD)FixupAddress + (((DWORD)*((LPBYTE)FixupAddress+2))<<16) + offset;
*(LPWORD)FixupAddress = (WORD)FixupValue;
*((LPBYTE)FixupAddress+2) = (BYTE)(FixupValue>>16);
break;
case 2:
*(LPWORD)FixupAddress += (WORD)offset;
break;
case 3:
*(LPBYTE)FixupAddress += (BYTE)offset;
break;
}
} else
*FixupAddress += offset;
}
break;
#else
case IMAGE_REL_BASED_HIGH: // Save the address and go to get REF_LO paired with this one
FixupAddressHi = (LPWORD)FixupAddress;
MatchedReflo = TRUE;
break;
case IMAGE_REL_BASED_LOW: // Low - (16-bit) relocate high part too.
if (MatchedReflo) {
FixupValue = (DWORD)(long)((*FixupAddressHi) << 16) +
*(LPWORD)FixupAddress + offset;
*FixupAddressHi = (short)((FixupValue + 0x8000) >> 16);
MatchedReflo = FALSE;
} else
FixupValue = *(short *)FixupAddress + offset;
*(LPWORD)FixupAddress = (WORD)(FixupValue & 0xffff);
break;
case IMAGE_REL_BASED_HIGHLOW: // Word - (32-bits) relocate the entire address.
if ((DWORD)FixupAddress & 0x3)
*(UNALIGNED DWORD *)FixupAddress += (DWORD)offset;
else
*FixupAddress += (DWORD)offset;
break;
case IMAGE_REL_BASED_HIGHADJ: // 32 bit relocation of 16 bit high word, sign extended
DEBUGMSG(ZONE_LOADER2,(TEXT("Grabbing extra data %8.8lx\r\n"),*(currptr+1)));
*(LPWORD)FixupAddress += (WORD)((*(short *)(++currptr)+offset+0x8000)>>16);
break;
case IMAGE_REL_BASED_MIPS_JMPADDR: // jump to 26 bit target (shifted left 2)
FixupValue = ((*FixupAddress)&0x03ffffff) + (offset>>2);
*FixupAddress = (*FixupAddress & 0xfc000000) | (FixupValue & 0x03ffffff);
break;
#if defined(MIPS)
case IMAGE_REL_BASED_MIPS_JMPADDR16: // MIPS16 jal/jalx to 26 bit target (shifted left 2)
if (IsMIPS16Supported) {
if (PrevPage && (((DWORD)FixupAddress & (PAGE_SIZE-1)) == PAGE_SIZE-2)) {
// Relocation is on previous page, crossing into the current one
// Do this page's portion == last 2 bytes of jal/jalx == least-signif 16 bits of address
*((LPWORD)FixupAddress+1) += (WORD)(offset >> 2);
break;
} else if (!PrevPage) {
// Relocation is on this page. Put the most-signif bits in FixupValue
FixupValue = (*(LPWORD)FixupAddress) & 0x03ff;
FixupValue = ((FixupValue >> 5) | ((FixupValue & 0x1f) << 5)) << 16;
if (((DWORD)FixupAddress & (PAGE_SIZE-1)) == PAGE_SIZE-2) {
// We're at the end of the page. prevdw has the 2 bytes we peeked at on the next page,
// so use them instead of loading them from FixupAddress+1
FixupValue |= (WORD)prevdw;
FixupValue += offset >> 2;
} else {
// All 32 bits are on this page. Go ahead and fixup last 2 bytes
FixupValue |= *((LPWORD)FixupAddress+1);
FixupValue += offset >> 2;
*((LPWORD)FixupAddress+1) = (WORD)(FixupValue & 0xffff);
}
// In either case, we now have the right bits for the upper part of the address
// Rescramble them and put them in the first 2 bytes of the fixup
FixupValue = (FixupValue >> 16) & 0x3ff;
*(LPWORD)FixupAddress = (WORD)((*(LPWORD)FixupAddress & 0xfc00) | (FixupValue >> 5) | ((FixupValue & 0x1f) << 5));
}
}
break;
#endif
#endif
default :
DEBUGMSG(ZONE_LOADER1,(TEXT("Not doing fixup type %d\r\n"),*currptr>>12));
DEBUGCHK(0);
break;
}
//DEBUGMSG(ZONE_LOADER2,(TEXT("reloc complete, new op %8.8lx\r\n"),*FixupAddress));
currptr++;
}
#ifdef MIPS
if (IsMIPS16Supported) {
#endif
#if defined(x86) || defined(MIPS)
if (Comp1) {
blockptr = (struct info *)(((ulong)blockptr)+blockptr->size);
if (((ulong)blockptr < (ulong)blockstart + blocksize) && blockptr->size) {
currptr = (LPWORD)(((ulong)blockptr)+sizeof(struct info));
if ((ulong)currptr < ((ulong)blockptr+blockptr->size))
if ((ZeroPtr(BasePtr+blockptr->rva) <= ZeroPtr(pMem)) && (ZeroPtr(BasePtr+blockptr->rva)+4096 > ZeroPtr(pMem)))
goto fixuppage;
}
}
#endif
#ifdef MIPS
}
#endif
EnterCriticalSection(&PagerCS);
return TRUE;
}
//------------------------------------------------------------------------------
// Relocate a DLL or EXE
//------------------------------------------------------------------------------
#pragma prefast(disable: 11, "if dataptr is NULL, we'll except anyway")
BOOL
Relocate(
e32_lite *eptr,
o32_lite *oarry,
ulong BasePtr,
ulong BaseAdj
)
{
o32_lite *dataptr;
struct info *blockptr, *blockstart;
ulong blocksize;
LPDWORD FixupAddress;
LPWORD FixupAddressHi, currptr;
WORD curroff;
DWORD FixupValue, offset;
BOOL MatchedReflo=FALSE;
int loop;
BOOL fRet = TRUE;
DEBUGMSG(ZONE_LOADER1,(TEXT("Relocations: BasePtr = %8.8lx, BaseAdj = %8.8lx, VBase = %8.8lx\r\n"),
BasePtr,BaseAdj, eptr->e32_vbase));
__try {
if ((blocksize = eptr->e32_unit[FIX].size) // has relocations, and
&& (offset = BasePtr - BaseAdj - eptr->e32_vbase)) { // adjustment needed
DEBUGMSG(ZONE_LOADER1,(TEXT("Relocate: Offset is %8.8lx\r\n"),offset));
blockstart = blockptr = (struct info *)(BasePtr+eptr->e32_unit[FIX].rva);
while (((ulong)blockptr < (ulong)blockstart + blocksize) && blockptr->size) {
currptr = (LPWORD)(((ulong)blockptr)+sizeof(struct info));
if ((ulong)currptr >= ((ulong)blockptr+blockptr->size)) {
blockptr = (struct info *)(((ulong)blockptr)+blockptr->size);
continue;
}
dataptr = 0;
while ((ulong)currptr < ((ulong)blockptr+blockptr->size)) {
curroff = *currptr&0xfff;
if (!curroff && !blockptr->rva) {
currptr++;
continue;
}
if (!dataptr || (dataptr->o32_rva > blockptr->rva + curroff) ||
(dataptr->o32_rva + dataptr->o32_vsize <= blockptr->rva + curroff)) {
for (loop = 0; loop < eptr->e32_objcnt; loop++) {
dataptr = &oarry[loop];
if ((dataptr->o32_rva <= blockptr->rva + curroff) &&
(dataptr->o32_rva+dataptr->o32_vsize > blockptr->rva + curroff))
break;
}
}
DEBUGCHK(loop != eptr->e32_objcnt);
FixupAddress = (LPDWORD)(blockptr->rva - dataptr->o32_rva + curroff + dataptr->o32_realaddr);
DEBUGMSG(ZONE_LOADER2,(TEXT("type %d, low %8.8lx, page %8.8lx, addr %8.8lx, op %8.8lx\r\n"),
(*currptr>>12)&0xf, (*currptr)&0x0fff,blockptr->rva,FixupAddress,*FixupAddress));
switch (*currptr>>12) {
case IMAGE_REL_BASED_ABSOLUTE: // Absolute - no fixup required.
break;
case IMAGE_REL_BASED_HIGH: // Save the address and go to get REF_LO paired with this one
FixupAddressHi = (LPWORD)FixupAddress;
MatchedReflo = TRUE;
break;
case IMAGE_REL_BASED_LOW: // Low - (16-bit) relocate high part too.
if (MatchedReflo) {
FixupValue = (DWORD)(long)((*FixupAddressHi) << 16) +
*(LPWORD)FixupAddress + offset;
*FixupAddressHi = (short)((FixupValue + 0x8000) >> 16);
MatchedReflo = FALSE;
} else
FixupValue = *(short *)FixupAddress + offset;
*(LPWORD)FixupAddress = (WORD)(FixupValue & 0xffff);
break;
case IMAGE_REL_BASED_HIGHLOW: // Word - (32-bits) relocate the entire address.
if ((DWORD)FixupAddress & 0x3)
*(UNALIGNED DWORD *)FixupAddress += (DWORD)offset;
else
*FixupAddress += (DWORD)offset;
break;
case IMAGE_REL_BASED_HIGHADJ: // 32 bit relocation of 16 bit high word, sign extended
DEBUGMSG(ZONE_LOADER2,(TEXT("Grabbing extra data %8.8lx\r\n"),*(currptr+1)));
*(LPWORD)FixupAddress += (WORD)((*(short *)(++currptr)+offset+0x8000)>>16);
break;
case IMAGE_REL_BASED_MIPS_JMPADDR: // jump to 26 bit target (shifted left 2)
FixupValue = ((*FixupAddress)&0x03ffffff) + (offset>>2);
*FixupAddress = (*FixupAddress & 0xfc000000) | (FixupValue & 0x03ffffff);
break;
#if defined(MIPS)
case IMAGE_REL_BASED_MIPS_JMPADDR16: // MIPS16 jal/jalx to 26 bit target (shifted left 2)
if (IsMIPS16Supported) {
FixupValue = (*(LPWORD)FixupAddress) & 0x03ff;
FixupValue = (((FixupValue >> 5) | ((FixupValue & 0x1f) << 5)) << 16) | *((LPWORD)FixupAddress+1);
FixupValue += offset >> 2;
*((LPWORD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -