Chris,
I ported your C callback contexts (closures) to ARM. The key bit of
assembly is 12 bytes:
static unsigned char thunk[4][12] = {
/* 0 arguments:
ldr r0, [PC, #-16]
ldr r12, [PC, #-16]
bx r12
*/
{
0x10, 0x00, 0x1f, 0xe5,
0x10, 0xc0, 0x1f, 0xe5,
0x1c, 0xff, 0x2f, 0xe1
}, {
There are a few differences between x86-64 and ARM. The PC is always
8 bytes ahead in ARM mode so I had to adjust accordingly for the PC
relative loads of the user data and callback. In order to branch to
the callback, I first have to load it into a register, hence the need
for an additional instruction. The register I chose is r12 as its
purpose is for implementing thunks or veneers. The toolchain uses r12
in the implementation of PLT entries for calling externally defined
functions. The AArch64 port is very similar with the difference being
that more arguments are passed directly in registers as compared to
ARM which only supports up to 4 in the Sys V calling convention.
The code's here (it's your code with the small modification):
https://github.com/dillstead/scratch/tree/main/cb_ctxs
I had to implement symbol obfuscation before for ARM and AArch64.
Basically if the caller asked for a symbol to call, I had to handback
a thunk which would obscure the actual address of the function being
called by using a level of indirection.
Neat gdb tricks in your latest blog post especially adding a label to
the code which pins down a breakpoint in the face of changing code. I
can see that being a nice time saver for me.
It's too bad ARM doesn't have an equivalent of int3. Did you test the
BKPT opcode?
As always, interesting stuff.
Steadman
Interesting, and thanks for the port, Steadman!
> Did you test the BKPT opcode?
I had tried BRK but not BKPT, but it appears to be the same story. The
instruction pointer is left on the break instruction, and so GDB (and
LLDB) get stuck in a loop on the instruction. It seems they'd need special
handling for it. I don't currently have access to a Windows Aarch64 system
to see how it works as debugbreak under Visual Studio, but my cursory
reading suggests they've got it figured out.