mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 09:16:49 +02:00
Add helper class for ARM/Thumb assembly functions (#127)
Replaces static helper functions in
Sdk5DsiSdCardRedirectPatch.cpp
LastWindowCrcPatch.h
CardiTryReadCardDmaPatch.cpp
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "ArmHelper.h"
|
||||||
#include "sharedMemory.h"
|
#include "sharedMemory.h"
|
||||||
#include "ndsHeader.h"
|
#include "ndsHeader.h"
|
||||||
#include "moduleParams.h"
|
#include "moduleParams.h"
|
||||||
@@ -12,11 +13,6 @@ static const u32 sAttachFunctionPatternThumb[] = { 0xB0FFB518u, 0xB0DFB0FFu, 0x4
|
|||||||
#define BL_TO_GET_DRIVE_STRUCT_OFFSET (-0x20)
|
#define BL_TO_GET_DRIVE_STRUCT_OFFSET (-0x20)
|
||||||
#define BL_TO_GET_DRIVE_STRUCT_OFFSET_ALT 0x88
|
#define BL_TO_GET_DRIVE_STRUCT_OFFSET_ALT 0x88
|
||||||
|
|
||||||
static bool isArmUnconditionalBl(u32 armInstruction)
|
|
||||||
{
|
|
||||||
return (armInstruction >> 24) == 0xEB;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext)
|
bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext)
|
||||||
{
|
{
|
||||||
_attachFunction = patchContext.FindPattern32Twl(sAttachFunctionPattern, sizeof(sAttachFunctionPattern));
|
_attachFunction = patchContext.FindPattern32Twl(sAttachFunctionPattern, sizeof(sAttachFunctionPattern));
|
||||||
@@ -32,10 +28,10 @@ bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
LOG_DEBUG("Found FATFSi_sdmcRtfsAttach at %p\n", _attachFunction);
|
LOG_DEBUG("Found FATFSi_sdmcRtfsAttach at %p\n", _attachFunction);
|
||||||
_blToGetDriveStructOffset = BL_TO_GET_DRIVE_STRUCT_OFFSET;
|
_blToGetDriveStructOffset = BL_TO_GET_DRIVE_STRUCT_OFFSET;
|
||||||
if (!_thumb && !isArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)))
|
if (!_thumb && !ArmHelper::IsArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)))
|
||||||
{
|
{
|
||||||
_blToGetDriveStructOffset = BL_TO_GET_DRIVE_STRUCT_OFFSET_ALT;
|
_blToGetDriveStructOffset = BL_TO_GET_DRIVE_STRUCT_OFFSET_ALT;
|
||||||
if (!isArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)))
|
if (!ArmHelper::IsArmUnconditionalBl(*(u32*)((u8*)_attachFunction + _blToGetDriveStructOffset)))
|
||||||
{
|
{
|
||||||
LOG_WARNING("Unsupported arm7 version for SD redirection patches\n");
|
LOG_WARNING("Unsupported arm7 version for SD redirection patches\n");
|
||||||
_attachFunction = nullptr;
|
_attachFunction = nullptr;
|
||||||
@@ -50,19 +46,6 @@ bool Sdk5DsiSdCardRedirectPatch::FindPatchTarget(PatchContext& patchContext)
|
|||||||
return _attachFunction != nullptr;
|
return _attachFunction != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 getArmBlAddress(const u32* instructionPointer)
|
|
||||||
{
|
|
||||||
u32 blInstruction = *instructionPointer;
|
|
||||||
return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 getThumbBlAddress(const u32* instructionPointer)
|
|
||||||
{
|
|
||||||
u32 blInstruction1 = ((u16*)instructionPointer)[0];
|
|
||||||
u32 blInstruction2 = ((u16*)instructionPointer)[1];
|
|
||||||
return (u32)instructionPointer + 5 + ((int)((((blInstruction1 & 0x7FF) << 11) | (blInstruction2 & 0x7FF)) << 10) >> 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext)
|
void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext)
|
||||||
{
|
{
|
||||||
if (!_attachFunction)
|
if (!_attachFunction)
|
||||||
@@ -71,11 +54,11 @@ void Sdk5DsiSdCardRedirectPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
u32 getDriveStructAddress;
|
u32 getDriveStructAddress;
|
||||||
if (_thumb)
|
if (_thumb)
|
||||||
{
|
{
|
||||||
getDriveStructAddress = getThumbBlAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset));
|
getDriveStructAddress = ArmHelper::GetThumbCallAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
getDriveStructAddress = getArmBlAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset));
|
getDriveStructAddress = ArmHelper::GetArmCallAddress((u32*)((u8*)_attachFunction + _blToGetDriveStructOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto arm7iAutoload = patchContext.GetAutoloadAdjusterTwl();
|
auto arm7iAutoload = patchContext.GetAutoloadAdjusterTwl();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "ArmHelper.h"
|
||||||
#include "patches/PatchContext.h"
|
#include "patches/PatchContext.h"
|
||||||
#include "LastWindowCrcPatchCode.h"
|
#include "LastWindowCrcPatchCode.h"
|
||||||
#include "LastWindowCrcPatch.h"
|
#include "LastWindowCrcPatch.h"
|
||||||
@@ -13,6 +14,6 @@ void LastWindowCrcPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<LastWindowCrcPatchCode>(patchContext.GetPatchHeap());
|
auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<LastWindowCrcPatchCode>(patchContext.GetPatchHeap());
|
||||||
u32 patchAddr = (u32)patchCode->GetLastWindowCrcFunction();
|
u32 patchAddr = (u32)patchCode->GetLastWindowCrcFunction();
|
||||||
*_getCrc16 = MakeBlxCall(patchAddr);
|
*_getCrc16 = ArmHelper::MakeArmCall((u32)_getCrc16, patchAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,4 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
u32* _getCrc16 = nullptr;
|
u32* _getCrc16 = nullptr;
|
||||||
|
|
||||||
u32 MakeBlxCall(u32 patchAddr) const
|
|
||||||
{
|
|
||||||
return 0xFA000000 | (((patchAddr - (u32)_getCrc16 - 8) >> 2) & 0xFFFFFF);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "ArmHelper.h"
|
||||||
#include "patches/PatchContext.h"
|
#include "patches/PatchContext.h"
|
||||||
#include "thumbInstructions.h"
|
#include "thumbInstructions.h"
|
||||||
#include "CardiSetCardDmaPatchCode.h"
|
#include "CardiSetCardDmaPatchCode.h"
|
||||||
@@ -169,17 +170,6 @@ bool CardiTryReadCardDmaPatch::FindPatchTarget(PatchContext& patchContext)
|
|||||||
return true; //_cardiTryReadCardDma != nullptr;
|
return true; //_cardiTryReadCardDma != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s32 getArmBlOffset(u32 blInstruction)
|
|
||||||
{
|
|
||||||
return 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 getArmBlAddress(const u32* instructionPointer)
|
|
||||||
{
|
|
||||||
u32 blInstruction = *instructionPointer;
|
|
||||||
return (u32)instructionPointer + 8 + ((int)((blInstruction & 0xFFFFFF) << 8) >> 6) + ((blInstruction >> 24) == 0xFA ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
||||||
{
|
{
|
||||||
if (!_cardiTryReadCardDma)
|
if (!_cardiTryReadCardDma)
|
||||||
@@ -204,7 +194,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x134);
|
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x134);
|
||||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x144);
|
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x144);
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x124));
|
||||||
if (*(u32*)cardiOnReadCard == 0xE92D40F0u)
|
if (*(u32*)cardiOnReadCard == 0xE92D40F0u)
|
||||||
{
|
{
|
||||||
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
||||||
@@ -222,7 +212,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140);
|
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x140);
|
||||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150);
|
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x150);
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x130));
|
||||||
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
||||||
cardiOnReadCardOffset = 0x40;
|
cardiOnReadCardOffset = 0x40;
|
||||||
}
|
}
|
||||||
@@ -230,7 +220,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148) + 4;
|
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x148) + 4;
|
||||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158);
|
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x158);
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x138));
|
||||||
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
||||||
cardiOnReadCardOffset = 0x40;
|
cardiOnReadCardOffset = 0x40;
|
||||||
}
|
}
|
||||||
@@ -240,11 +230,11 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C);
|
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x16C);
|
||||||
if (*(u32*)((u8*)_cardiTryReadCardDma + 0x158) == 0xE12FFF1E)
|
if (*(u32*)((u8*)_cardiTryReadCardDma + 0x158) == 0xE12FFF1E)
|
||||||
{
|
{
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x148));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
|
||||||
}
|
}
|
||||||
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
||||||
cardiOnReadCardOffset = 0x40;
|
cardiOnReadCardOffset = 0x40;
|
||||||
@@ -253,7 +243,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x160) + 4;
|
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x160) + 4;
|
||||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x170);
|
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x170);
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x14C));
|
||||||
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
cardiSetCardDmaDmaCopyCallOffset = 0x18;
|
||||||
cardiOnReadCardOffset = 0x40;
|
cardiOnReadCardOffset = 0x40;
|
||||||
}
|
}
|
||||||
@@ -261,7 +251,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x178) + 4;
|
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x178) + 4;
|
||||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x188);
|
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x188);
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x16C));
|
||||||
cardiSetCardDmaDmaCopyCallOffset = 0x1C;
|
cardiSetCardDmaDmaCopyCallOffset = 0x1C;
|
||||||
cardiOnReadCardOffset = 0x48;
|
cardiOnReadCardOffset = 0x48;
|
||||||
}
|
}
|
||||||
@@ -269,7 +259,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
{
|
{
|
||||||
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x180) + 4;
|
cardiCommon = *(u32*)((u8*)_cardiTryReadCardDma + 0x180) + 4;
|
||||||
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x190);
|
cardiOnReadCard = *(u32*)((u8*)_cardiTryReadCardDma + 0x190);
|
||||||
cardiSetCardDma = getArmBlAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174));
|
cardiSetCardDma = ArmHelper::GetArmCallAddress((u32*)((u8*)_cardiTryReadCardDma + 0x174));
|
||||||
cardiSetCardDmaDmaCopyCallOffset = 0x1C;
|
cardiSetCardDmaDmaCopyCallOffset = 0x1C;
|
||||||
cardiOnReadCardOffset = 0x48;
|
cardiOnReadCardOffset = 0x48;
|
||||||
}
|
}
|
||||||
@@ -291,7 +281,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
|
|
||||||
// MIi_CardDmaCopy32 is relative, but we need its final location to call it later
|
// MIi_CardDmaCopy32 is relative, but we need its final location to call it later
|
||||||
u32 miiCardDmaCopy32CallLocation = cardiSetCardDma + cardiSetCardDmaDmaCopyCallOffset;
|
u32 miiCardDmaCopy32CallLocation = cardiSetCardDma + cardiSetCardDmaDmaCopyCallOffset;
|
||||||
s32 miiCardDmaCopy32CallOffset = getArmBlOffset(*(u32*)miiCardDmaCopy32CallLocation);
|
s32 miiCardDmaCopy32CallOffset = ArmHelper::GetArmCallOffset(*(u32*)miiCardDmaCopy32CallLocation);
|
||||||
if (autoloadAdjuster)
|
if (autoloadAdjuster)
|
||||||
{
|
{
|
||||||
miiCardDmaCopy32CallLocation = autoloadAdjuster->AdjustInitialToFinal(miiCardDmaCopy32CallLocation);
|
miiCardDmaCopy32CallLocation = autoloadAdjuster->AdjustInitialToFinal(miiCardDmaCopy32CallLocation);
|
||||||
@@ -300,7 +290,7 @@ void CardiTryReadCardDmaPatch::ApplyPatch(PatchContext& patchContext)
|
|||||||
|
|
||||||
// same as above with OS_DisableIrqMask
|
// same as above with OS_DisableIrqMask
|
||||||
u32 osDisableIrqMaskCallLocation = cardiOnReadCard + cardiOnReadCardOffset + 4;
|
u32 osDisableIrqMaskCallLocation = cardiOnReadCard + cardiOnReadCardOffset + 4;
|
||||||
s32 osDisableIrqMaskCallOffset = getArmBlOffset(*(u32*)osDisableIrqMaskCallLocation);
|
s32 osDisableIrqMaskCallOffset = ArmHelper::GetArmCallOffset(*(u32*)osDisableIrqMaskCallLocation);
|
||||||
if (autoloadAdjuster)
|
if (autoloadAdjuster)
|
||||||
{
|
{
|
||||||
osDisableIrqMaskCallLocation = autoloadAdjuster->AdjustInitialToFinal(osDisableIrqMaskCallLocation);
|
osDisableIrqMaskCallLocation = autoloadAdjuster->AdjustInitialToFinal(osDisableIrqMaskCallLocation);
|
||||||
|
|||||||
63
common/ArmHelper.h
Normal file
63
common/ArmHelper.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @brief Class containing helper functions for manipulating ARM or Thumb assembly.
|
||||||
|
class ArmHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArmHelper() = delete;
|
||||||
|
|
||||||
|
/// @brief Check if an ARM instruction is an unconditional bl call.
|
||||||
|
/// @param instruction The ARM instruction to check.
|
||||||
|
/// @return True if the instruction is an unconditional bl call, false otherwise.
|
||||||
|
static bool IsArmUnconditionalBl(u32 instruction)
|
||||||
|
{
|
||||||
|
return (instruction >> 24) == 0xEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get the offset of an ARM call (bl or blx).
|
||||||
|
/// @param callInstruction The ARM call instruction.
|
||||||
|
/// @return The offset to the destination function. +1 if Thumb.
|
||||||
|
static s32 GetArmCallOffset(u32 callInstruction)
|
||||||
|
{
|
||||||
|
return 8 + ((int)((callInstruction & 0xFFFFFF) << 8) >> 6)
|
||||||
|
+ ((callInstruction >> 24) == 0xFA ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get the address of the callee in an ARM call (bl or blx).
|
||||||
|
/// @param instructionPointer Pointer to the ARM call instruction.
|
||||||
|
/// @return The address of the function being called. +1 if Thumb.
|
||||||
|
static u32 GetArmCallAddress(const void* instructionPointer)
|
||||||
|
{
|
||||||
|
auto pc = (const u32*)((u32)instructionPointer & ~3);
|
||||||
|
return (u32)pc + GetArmCallOffset(*pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Create an ARM call instruction (bl or blx).
|
||||||
|
/// @param instructionAddress The address where the instruction is to be placed.
|
||||||
|
/// @param targetAddress The address of the function to call. +1 if Thumb.
|
||||||
|
/// @return The ARM call instruction to call the target.
|
||||||
|
static u32 MakeArmCall(u32 instructionAddress, u32 targetAddress)
|
||||||
|
{
|
||||||
|
u32 offset = targetAddress - instructionAddress - 8;
|
||||||
|
return ((targetAddress & 1) ? 0xFA000000 : 0xEB000000) | ((offset >> 2) & 0xFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get the offset of a Thumb call (bl or blx).
|
||||||
|
/// @param callInstruction1 The first Thumb call instruction.
|
||||||
|
/// @param callInstruction2 The second Thumb call instruction.
|
||||||
|
/// @return The offset to the destination function. +1 if Thumb.
|
||||||
|
static s32 GetThumbCallOffset(u16 callInstruction1, u16 callInstruction2)
|
||||||
|
{
|
||||||
|
return 4 + ((int)((((callInstruction1 & 0x7FF) << 11) | (callInstruction2 & 0x7FF)) << 10) >> 9)
|
||||||
|
+ ((callInstruction2 >> 11) == 0x1F ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get the address of the callee in an Thumb call (bl or blx).
|
||||||
|
/// @param instructionPointer Pointer to the first Thumb call instruction.
|
||||||
|
/// @return The offset to the destination function. +1 if Thumb.
|
||||||
|
static u32 GetThumbCallAddress(const void* instructionPointer)
|
||||||
|
{
|
||||||
|
auto pc = (const u16*)((u32)instructionPointer & ~1);
|
||||||
|
return (u32)pc + GetThumbCallOffset(pc[0], pc[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user