Merged scanning code paths for Large and Small OOVPA
Although this adds a small amount of overhead (since reading each entry must check the Type again, instead of once every scan), it halves the amount of code. But more importantly, the Large path contained a bug, since it tried to scan XRefs as regular values. With this merge of both code paths into one, that can't happen anymore
This commit is contained in:
parent
d65769a849
commit
8d64c13a2d
|
@ -333,6 +333,8 @@ enum XRefDataBaseOffset
|
||||||
// Also, if XREF_COUNT > sizeof(byte), enlarge struct OOVPA.XRefSaveIndex (and Value somehow)
|
// Also, if XREF_COUNT > sizeof(byte), enlarge struct OOVPA.XRefSaveIndex (and Value somehow)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define XREF_UNKNOWN -1
|
||||||
|
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
// * XRefDataBase
|
// * XRefDataBase
|
||||||
// ******************************************************************
|
// ******************************************************************
|
||||||
|
|
|
@ -176,7 +176,7 @@ void EmuHLEIntercept(Xbe::LibraryVersion *pLibraryVersion, Xbe::Header *pXbeHead
|
||||||
|
|
||||||
bXRefFirstPass = true; // Set to false for search speed optimization
|
bXRefFirstPass = true; // Set to false for search speed optimization
|
||||||
|
|
||||||
memset((void*)XRefDataBase, -1, sizeof(XRefDataBase));
|
memset((void*)XRefDataBase, XREF_UNKNOWN, sizeof(XRefDataBase));
|
||||||
|
|
||||||
|
|
||||||
for(int p=0;UnResolvedXRefs < LastUnResolvedXRefs;p++)
|
for(int p=0;UnResolvedXRefs < LastUnResolvedXRefs;p++)
|
||||||
|
@ -606,153 +606,104 @@ static inline void EmuInstallWrapper(void *FunctionAddr, void *WrapperAddr)
|
||||||
*(uint32*)&FuncBytes[1] = (uint32)WrapperAddr - (uint32)FunctionAddr - 5;
|
*(uint32*)&FuncBytes[1] = (uint32)WrapperAddr - (uint32)FunctionAddr - 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void GetOovpaEntry(OOVPA *oovpa, int index, OUT uint32 &offset, OUT uint08 &value)
|
||||||
|
{
|
||||||
|
if (oovpa->Type == Large) {
|
||||||
|
offset = (uint32) ((LOOVPA<1>*)oovpa)->Lovp[index].Offset;
|
||||||
|
value = ((LOOVPA<1>*)oovpa)->Lovp[index].Value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
offset = (uint32) ((SOOVPA<1>*)oovpa)->Sovp[index].Offset;
|
||||||
|
value = ((SOOVPA<1>*)oovpa)->Sovp[index].Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// locate the given function, searching within lower and upper bounds
|
// locate the given function, searching within lower and upper bounds
|
||||||
static void *EmuLocateFunction(OOVPA *Oovpa, uint32 lower, uint32 upper)
|
static void *EmuLocateFunction(OOVPA *Oovpa, uint32 lower, uint32 upper)
|
||||||
{
|
{
|
||||||
uint32 count = Oovpa->Count;
|
uint32 xref_count = Oovpa->XRefCount;
|
||||||
|
// skip out if this is an unnecessary search
|
||||||
// Skip out if this is an unnecessary search
|
if(!bXRefFirstPass && xref_count == XRefZero && Oovpa->XRefSaveIndex == XRefNoSaveIndex)
|
||||||
if(!bXRefFirstPass && Oovpa->XRefCount == XRefZero && Oovpa->XRefSaveIndex == XRefNoSaveIndex)
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// large
|
// correct upper bound with highest Oovpa offset
|
||||||
if(Oovpa->Type == Large)
|
uint32 count = Oovpa->Count;
|
||||||
{
|
{
|
||||||
LOOVPA<1> *Loovpa = (LOOVPA<1>*)Oovpa;
|
uint32 Offset;
|
||||||
|
uint08 Value; // ignored
|
||||||
|
|
||||||
upper -= Loovpa->Lovp[count-1].Offset;
|
GetOovpaEntry(Oovpa, count - 1, Offset, Value);
|
||||||
|
upper -= Offset;
|
||||||
|
}
|
||||||
|
|
||||||
// search all of the image memory
|
// search all of the image memory
|
||||||
for(uint32 cur=lower;cur<upper;cur++)
|
for (uint32 cur = lower; cur < upper; cur++)
|
||||||
{
|
{
|
||||||
uint32 v;
|
uint32 v; // verification counter
|
||||||
|
|
||||||
// check all cross references
|
// check all cross references
|
||||||
for(v=0;v<Oovpa->XRefCount;v++)
|
for (v = 0; v < xref_count; v++)
|
||||||
{
|
{
|
||||||
uint32 Offset = Loovpa->Lovp[v].Offset;
|
uint32 Offset;
|
||||||
uint32 Value = Loovpa->Lovp[v].Value;
|
uint08 Value;
|
||||||
|
|
||||||
uint32 RealValue = *(uint32*)(cur + Offset);
|
// get XRef offset + value pair and currently registered (un)known address
|
||||||
|
GetOovpaEntry(Oovpa, v, Offset, Value);
|
||||||
|
uint32 XRefValue = XRefDataBase[Value];
|
||||||
|
|
||||||
if(XRefDataBase[Value] == -1)
|
// unknown XRef cannot be checked yet
|
||||||
goto skipout_L; // Unsatisfied XRef is not acceptable
|
if (XRefValue == XREF_UNKNOWN)
|
||||||
|
break;
|
||||||
|
|
||||||
if((RealValue + cur + Offset+4 != XRefDataBase[Value]) && (RealValue != XRefDataBase[Value]))
|
uint32 RealValue = *(uint32*)(cur + Offset);
|
||||||
break;
|
// check if PC-relative or direct reference matches XRef
|
||||||
}
|
if ((RealValue + cur + Offset + 4 != XRefValue) && (RealValue != XRefValue))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO : Should we do the following (to could prevent false positives), like the small case does?
|
// did all xrefs match?
|
||||||
// TODO : Even better would be to merge both paths into one, as this is the only difference...
|
if (v == xref_count)
|
||||||
// check OV pairs if all xrefs matched
|
{
|
||||||
// if (v == Oovpa->XRefCount)
|
// check all OV pairs, moving on if any do not match
|
||||||
|
for (; v < count; v++)
|
||||||
{
|
{
|
||||||
// check all pairs, moving on if any do not match
|
uint32 Offset;
|
||||||
for (v = 0; v < count; v++)
|
uint08 Value;
|
||||||
{
|
|
||||||
uint32 Offset = Loovpa->Lovp[v].Offset;
|
|
||||||
uint32 Value = Loovpa->Lovp[v].Value;
|
|
||||||
|
|
||||||
uint08 RealValue = *(uint08*)(cur + Offset);
|
GetOovpaEntry(Oovpa, v, Offset, Value);
|
||||||
|
uint08 RealValue = *(uint08*)(cur + Offset);
|
||||||
if (RealValue != Value)
|
if (RealValue != Value)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// success if we found all pairs
|
// success if we found all pairs
|
||||||
if(v == count)
|
if (v == count)
|
||||||
{
|
{
|
||||||
if(Oovpa->XRefSaveIndex != XRefNoSaveIndex)
|
// do we need to save the found address?
|
||||||
{
|
if (Oovpa->XRefSaveIndex != XRefNoSaveIndex)
|
||||||
if(XRefDataBase[Oovpa->XRefSaveIndex] == -1)
|
{
|
||||||
{
|
// is the XRef not saved yet?
|
||||||
UnResolvedXRefs--;
|
if (XRefDataBase[Oovpa->XRefSaveIndex] == XREF_UNKNOWN)
|
||||||
XRefDataBase[Oovpa->XRefSaveIndex] = cur;
|
{
|
||||||
|
// save and count the found address
|
||||||
|
UnResolvedXRefs--;
|
||||||
|
XRefDataBase[Oovpa->XRefSaveIndex] = cur;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO : Check identical result?
|
||||||
|
// already found, no bother patching again
|
||||||
|
return (void*)XRefDataBase[Oovpa->XRefSaveIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (void*)cur;
|
// return found address
|
||||||
}
|
return (void*)cur;
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
return (void*)XRefDataBase[Oovpa->XRefSaveIndex]; // already Found, no bother patching again
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (void*)cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
skipout_L:;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// small
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SOOVPA<1> *Soovpa = (SOOVPA<1>*)Oovpa;
|
|
||||||
|
|
||||||
upper -= Soovpa->Sovp[count-1].Offset;
|
|
||||||
|
|
||||||
// search all of the image memory
|
|
||||||
for(uint32 cur=lower;cur<upper;cur++)
|
|
||||||
{
|
|
||||||
uint32 v;
|
|
||||||
|
|
||||||
// check all cross references
|
|
||||||
for(v=0;v<Oovpa->XRefCount;v++)
|
|
||||||
{
|
|
||||||
uint32 Offset = Soovpa->Sovp[v].Offset;
|
|
||||||
uint32 Value = Soovpa->Sovp[v].Value;
|
|
||||||
|
|
||||||
uint32 RealValue = *(uint32*)(cur + Offset);
|
|
||||||
|
|
||||||
if(XRefDataBase[Value] == -1)
|
|
||||||
goto skipout_S; // Unsatisfied XRef is not acceptable
|
|
||||||
|
|
||||||
if( (RealValue + cur + Offset + 4 != XRefDataBase[Value]) && (RealValue != XRefDataBase[Value]))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check OV pairs if all xrefs matched
|
|
||||||
if(v == Oovpa->XRefCount)
|
|
||||||
{
|
|
||||||
// check all pairs, moving on if any do not match
|
|
||||||
// TODO : Why does this loop use v=Oovpa->XRefCount instead of starting with v=0 (like in large)?
|
|
||||||
for(;v<count;v++)
|
|
||||||
{
|
|
||||||
uint32 Offset = Soovpa->Sovp[v].Offset;
|
|
||||||
uint32 Value = Soovpa->Sovp[v].Value;
|
|
||||||
|
|
||||||
uint08 RealValue = *(uint08*)(cur + Offset);
|
|
||||||
|
|
||||||
if(RealValue != Value)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// success if we found all pairs
|
|
||||||
if(v == count)
|
|
||||||
{
|
|
||||||
if(Oovpa->XRefSaveIndex != XRefNoSaveIndex)
|
|
||||||
{
|
|
||||||
if(XRefDataBase[Oovpa->XRefSaveIndex] == -1)
|
|
||||||
{
|
|
||||||
UnResolvedXRefs--;
|
|
||||||
XRefDataBase[Oovpa->XRefSaveIndex] = cur;
|
|
||||||
|
|
||||||
return (void*)cur;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (void*)XRefDataBase[Oovpa->XRefSaveIndex]; // already Found, no bother patching again
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (void*)cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
skipout_S:;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// found nothing
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,4 +759,3 @@ static void EmuXRefFailure()
|
||||||
CxbxKrnlCleanup("XRef-only function body reached. Fatal Error.");
|
CxbxKrnlCleanup("XRef-only function body reached. Fatal Error.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue