summaryrefslogtreecommitdiffstats
path: root/courgette/disassembler_elf_32_arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'courgette/disassembler_elf_32_arm.cc')
-rw-r--r--courgette/disassembler_elf_32_arm.cc39
1 files changed, 39 insertions, 0 deletions
diff --git a/courgette/disassembler_elf_32_arm.cc b/courgette/disassembler_elf_32_arm.cc
index f271020..6270c64 100644
--- a/courgette/disassembler_elf_32_arm.cc
+++ b/courgette/disassembler_elf_32_arm.cc
@@ -17,6 +17,45 @@
namespace courgette {
+CheckBool DisassemblerElf32ARM::TypedRVAARM::ComputeRelativeTarget(
+ const uint8* op_pointer) {
+ uint32 temp = 0;
+
+ switch (type_) {
+ case ARM_OFF24:
+ // The offset is given by the lower 24-bits of the op, shifted
+ // left 2 bits, and sign extended.
+ temp = Read32LittleEndian(op_pointer);
+ temp = (temp & 0x00FFFFFF) << 2;
+ if (temp & 0x02000000)
+ temp |= 0xFC000000;
+ temp += 8;
+ break;
+ case ARM_OFF8:
+ // The offset is given by lower 8 bits of the op. It is a 9-bit
+ // offset, shifted right one bit and signed extended.
+ temp = (Read16LittleEndian(op_pointer) & 0x00FF) << 1;
+ if (temp & 0x0100)
+ temp |= 0xFFFFFE00;
+ temp += 4; // Offset from _next_ PC.
+ break;
+ case ARM_OFF11:
+ // The offset is given by lower 11 bits of the op, and is a
+ // 12-bit offset, shifted right one bit and sign extended.
+ temp = (Read16LittleEndian(op_pointer) & 0x07FF) << 1;
+ if (temp & 0x00000800)
+ temp |= 0xFFFFF000;
+ temp += 4; // Offset from _next_ PC.
+ break;
+ default:
+ return false;
+ }
+
+ set_relative_target(temp);
+
+ return true;
+}
+
DisassemblerElf32ARM::DisassemblerElf32ARM(const void* start, size_t length)
: DisassemblerElf32(start, length) {
}