question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

THUMB "half-bl" instruction not supported

See original GitHub issue

I am hoping to use Ghidra as a hobbyist to reverse engineer parts of GBA games for modding. Unfortunately, they make extensive use of what is technically unpredictable behaviour: using the second half of a “bl” instruction pair in THUMB code to perform an absolute jump to the address in the link register.

It would be really useful for THUMB disassembly to recognise and support this, maybe as an optional feature as there is no guarantee it works on other processors. The processor in question is the ARM7TDMI, with architecture ARMv4T, little-endian.

Sample of affected code:

0d 4b      ldr r3, =procAddr
9e 46      mov lr, r3
00 f8      bl #0

Details of this instruction pair are found on page A7-26 of the ARM Architecture Reference Manual.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
adituvcommented, Mar 7, 2019

Thank you so much for that patch. I’ve managed to tweak it to create a new processor variant so that the changes don’t escape outside the GBA version. I don’t know how to suitably create a patch for this so I’ll list the steps I used in detail in case it helps anyone else: Update: patch now included.

diff --git a/Ghidra/Processors/ARM/data/languages/ARM.ldefs b/Ghidra/Processors/ARM/data/languages/ARM.ldefs
index f98077e..1440716 100644
--- a/Ghidra/Processors/ARM/data/languages/ARM.ldefs
+++ b/Ghidra/Processors/ARM/data/languages/ARM.ldefs
@@ -243,6 +243,22 @@
     <external_name tool="IDA-PRO" name="arm"/>
     <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
   </language>
+
+  <language processor="ARM"
+            endian="little"
+            size="32"
+            variant="v4t_gba"
+            version="1.101"
+            slafile="ARM4t_gba.sla"
+            processorspec="ARMt_v45.pspec"
+            manualindexfile="../manuals/ARM.idx"
+            id="ARM:LE:32:v4t"> 
+    <description>ARM/Thumb v4 little endian (GBA variant)</description>
+    <compiler name="default" spec="ARM_v45.cspec" id="default"/>
+    <external_name tool="gnu" name="armv4t"/>
+    <external_name tool="IDA-PRO" name="arm"/>
+    <external_name tool="DWARF.register.mapping.file" name="ARM.dwarf"/>
+  </language>
 
   <language processor="ARM"
             endian="big"
diff --git a/Ghidra/Processors/ARM/data/languages/ARM4t_gba.slaspec b/Ghidra/Processors/ARM/data/languages/ARM4t_gba.slaspec
new file mode 100644
index 0000000..d316c85
--- /dev/null
+++ b/Ghidra/Processors/ARM/data/languages/ARM4t_gba.slaspec
@@ -0,0 +1,7 @@
+
+@define ENDIAN "little"
+@define T_VARIANT ""
+@define GBA_VARIANT ""
+
+@include "ARM.sinc"
+
diff --git a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
index ea89edd..84d9563 100644
--- a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
+++ b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
@@ -100,6 +100,7 @@ define token instrThumb (16)
   soffset8=(0,7) signed
   offset10=(0,9)
   offset10S=(10,10)
+  offset11=(0,10)
   soffset11=(0,10) signed
   offset12=(0,11)
 
@@ -1383,6 +1384,19 @@ with : ARMcondCk=1 {
 
 @endif # VERSION_5
 
+@if defined(GBA_VARIANT)
+ThHalfBlOffset11: reloc is offset11 [ reloc = offset11 << 1; ] { export reloc; }
+
+:bl^ItCond  lr",#"ThHalfBlOffset11   is TMode=1 & ItCond & op11=0x1f & ThHalfBlOffset11 & lr
+{
+  build ItCond;
+  local tmp = lr + ThHalfBlOffset11;
+  lr = inst_next|1;
+  SetThumbMode(1);
+  call [tmp];
+}
+@endif # GBA_VARIANT
+
 :bl^ItCond 	ThAddr24 			is TMode=1 & ItCond & (op11=0x1e; part2c1415=3 & part2c1212=1) & ThAddr24
 {
   build ItCond;

I’m leaving this issue open in case this is a desired modification when Ghidra becomes open source.

2reactions
nneonneocommented, Mar 7, 2019

This turns out to be a nice exercise in SLEIGH programming, so here we go:

diff --git a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
index ea89edd..fb9f9a1 100644
--- a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
+++ b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc
@@ -100,6 +100,7 @@ define token instrThumb (16)
   soffset8=(0,7) signed
   offset10=(0,9)
   offset10S=(10,10)
+  offset11=(0,10)
   soffset11=(0,10) signed
   offset12=(0,11)
 
@@ -1383,6 +1384,19 @@ with : ARMcondCk=1 {
 
 @endif # VERSION_5
 
+# half-bl, used in GBA games, technically unpredictable behaviour
+ThHalfBlOffset11: "" is offset11=0 { export 0:4; }
+ThHalfBlOffset11: "+"reloc is offset11 [ reloc = offset11 << 1; ] { export reloc; }
+
+:bl^ItCond  "lr" ThHalfBlOffset11           is TMode=1 & ItCond & (op11=0x1f & ThHalfBlOffset11)
+{
+  build ItCond;
+  local tmp = lr + ThHalfBlOffset11;
+  lr = inst_next|1;
+  SetThumbMode(1);
+  call [tmp];
+}
+
 :bl^ItCond  ThAddr24            is TMode=1 & ItCond & (op11=0x1e; part2c1415=3 & part2c1212=1) & ThAddr24
 {
   build ItCond;

If you apply the patch and restart Ghidra, it should automatically recompile the SLEIGH specification.

I confirmed this disassembled the half-br instruction properly on a test binary, and the decompiler picked it up as a call instruction as expected. (I’m not 100% sure I got the non-zero case right - but hopefully you don’t run into any of those?)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Error: Thumb does not support conditional execution
I'm using arm-gcc to and it throws two errors. Error: Thumb does not support conditional execution. Error: instruction not allowed in IT block ......
Read more >
ARM Architecture Reference Manual Thumb-2 Supplement
THE ARM ARCHITECTURE REFERENCE MANUAL IS PROVIDED "AS IS" WITH NO WARRANTIES. EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO ANY ...
Read more >
ARM® and Thumb®-2 Instruction Set Quick Reference Card
<sh> range is 1-32 in the ARM instruction. C2. The optional 2 is available from ARMv5. It provides an alternative operation. Condition codes...
Read more >
ARM and Thumb Assembler Instructions
Word-aligned loads are supported for LDRD. A non-word-aligned LDRD generates an alignment fault data abort. If A= 0 and U= 0, then LDR...
Read more >
Thumb® Instruction Set Quick Reference Card
All Thumb registers are Lo (R0-R7) except where specified. ... Move NOT. MVN Rd, Rm. N Z. Rd := NOT Rm. Test bits....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found