Dart shifts to standard calling convention

@cryptax
2 min readJul 19, 2024

--

Up until Dart SDK v3.4.0, Dart was using an uncommon calling convention where all arguments for a function were passed on the stack [see my previous article] and [here].

Today, as I was peering into the disassembly of an app, I noticed this has changed! Dart now uses a standard calling convention, where the first few arguments are passed in specific registers and only if there are more they are pushed on the stack.

On Arm 64, registers r1 to r7 are used, with the exception of r4.

struct DartCallingConvention {
static constexpr Register kCpuRegistersForArgs[] = {R1, R2, R3, R5, R6, R7};
static constexpr FpuRegister kFpuRegistersForArgs[] = {V0, V1, V2,
V3, V4, V5};
};

In the assembly below, Radare2 shows the assembly to call a method named nextGame(), with the following source code:

class ColorMemoryState extends State<ColorMemoryStateful>{
...
void nextGame(String buttonText, String msg) {
...
}
}

As nextGame is applied an object, as usual, a reference to the current object this is provided as first argument in x1.

x1 contains a pointer to “this” object, x2 contains the buttonText and x3 msg.

x1 is computed through the first 2 instructions (ldur and add), which actually achieve what is called as pointer decompression. To keep smaller pointers, Dart often uses compressed pointers where only the lower 32 bits of a pointer are kept in memory. To be used, the pointer must be decompressed. Here, the address of x0+0x0fcontains the compressed address. The upper bits are added in the second instruction (add) through x28 << 32 (x28, lsl 32).

x2 contains the address of x27+0x7b40. On Arm64, Dart uses x27 as a special register to access the Object Pool. The Object Pool contains frequently used objects, constants and immediates. In this case, it will get a string for a button.

Similarly, x3 contains the address of another string, loaded from x27+0x7b48. It is the msg argument.

So what?

Disassemblers were often confused by this initial unknown convention. This change is likely to make it easier for them.

Binary Ninja used to be confused by the calling convention. This will probably help.
Ouch! JEB 5.14.0 used to understand better Dart than other disassemblers, but now it is lost by the new convention!

References:

Thanks to @Julemand101 and @KayZ for their helpful input on Dart community Discord server.

— Cryptax

--

--

@cryptax

Mobile and IoT malware researcher. The postings on this account are solely my own opinion and do not represent my employer.