ARM Architecture Debate: SL vs. THR Registers in Dart AOT true/false
The Debate:
A lively discussion took place in a Telegram group called TDOHex Discussion in April 2024, where two individuals debated which register is used for handling true/false
in ARM architecture within Dart Ahead-of-Time (AOT) compilation. While it was an insightful exchange, it’s unfortunate that in a group of over 1,000 members, only these two showed interest in the topic. Now, almost half a year later in September 2024, the discussion remains unresolved, with no further contributions from others. Here’s a breakdown of what went down:
NOTE: This article covers only arm
architecture i.e. arm32
as solution for the debate and also you all are already familiar with the 64-bit architecture example:
- Assembly for return true in ARM64:
add x0, x22, 0x20 // x22 is the NULL register in dart
- Assembly for return false in ARM64:
add x0, x22, 0x30 // x22 is the NULL register in dart
Side 1:
They claimed that the THR (Thread) register is used to handle true/false
. Their analysis, done back in 2021, mentioned this code snippet:
ldr r2, [thr, 0x70]
Side 2:
The other person argued that the SL (Stack Limit) register is responsible for handling true/false
. Their analysis from 2024 provided this code:
ldr r0, [sl, 0x38]
Surprisingly, both were right! 😲 But technically, one of them was more right.
The Surprising Truth: Both Are Correct! 🎉
Yes, both sides were correct, but with a twist. Technically, Side 1’s answer is more accurate. However, Side 2 would’ve been right if not for an issue with Radare2’s disassembly tool, which led to some confusion.
Breaking Down the Registers:
- THR Register:
Side 1’s analysis refers to the THR (Thread) register, which is used for holding a pointer to the current running thread. According to the ARM Developer’s website, the r10 register (also called
v7
orsl
) serves as the Stack Limit pointer in stack-checked variants:Register Synonym Special Role in the procedure call standard r10
v7
sl
ARM-state variable register 7. Stack limit pointer in stack-checked variants. - SL Register:
Side 2’s analysis mentioned the SL register. However, the confusion arises because Dart’s SDK uses the r10 register (which can be referred to as
sl
) for THR.
Diving into the Dart SDK 📂
Let’s look at the Dart SDK to clarify things further:
Dart SDK Register Constants
In the constants_arm.h file of the Dart SDK, you’ll see that r10 is defined as THR:
R10 = 10, // THR
Offsets for Objects
In the runtime_offsets_extracted.h, you’ll find offsets used to determine object values for thread:
~ For Stack Limit:
static constexpr dart::compiler::target::word AOT_Thread_stack_limit_offset = 0x38;
So, for Stack Limit, it would be called by [r10 + 0x38]
.
~ For NULL
:
static constexpr dart::compiler::target::word AOT_Thread_object_null_offset = 0x68;
Note: Dart recently updated this offset to 0x70
in its latest commit, but not all developers are using this yet.
**True/False in Dart **
In some Dart SDK versions like 3.4.0, the true/false
values are handled with these offsets:
static constexpr dart::compiler::target::word Thread_bool_false_offset = 0x3c;
static constexpr dart::compiler::target::word Thread_bool_true_offset = 0x38;
So, the assembly code would look like this:
- For
false
:ldr r0, [THR, 0x3c]
- For
true
:ldr r0, [THR, 0x38]
- Here too, recently Dart made changes to these registers which you’ll encounter in future
The Radare2 Confusion 🤔
Radare2, a popular disassembly tool, mistakenly showed the code using the sl
register, which led Side 2 to conclude that SL was responsible for handling true/false
. But in reality, it’s THR (which uses r10
as well).
Check out the screenshots that clarify this misunderstanding:
- Radare2 Output (Mistaken):
- To Confirm:
The Final Verdict 🏆
~ Side 1’s Analysis (2021) was based on the older offset, which was based on that time dart version.
~ Side 2’s Analysis (2024) was confused by Radare2’s incorrect disassembly, leading them to the wrong conclusion.
But with the Dart SDK’s updates and some careful analysis, it’s clear that the THR register (r10
) is indeed the correct register to look at for true/false
values in Dart AOT, not SL.
Hope this clears up the confusion! 😁 Happy Reversing! 🔧💻