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:
Mow
2026-02-01 05:51:57 -05:00
committed by GitHub
parent 28bfb3b423
commit a648d4c4a9
5 changed files with 81 additions and 49 deletions

63
common/ArmHelper.h Normal file
View 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]);
}
};