AMD System V ABI Reference
An ABI reference for quick lookup. If you crash or just want to step through disassembly, check the contents of the registers to see where parameters are being passed.
Arg | Register | Notes |
---|---|---|
1 | RDI |
Usually self or address to hold return value |
2 | RSI |
Usually _cmd but may contain self |
3 | RDX |
Contains _cmd if RSI contains self |
4 | RCX |
|
5 | R8 |
|
6 | R9 |
|
Floating point | XMM0 -XMM7 |
Only if floating-point used |
Return value | RAX |
Value or address to hold value |
Return value | RDX |
Only if return value is 9-16 bytes |
void abc(int64_t x, int64_t y, int64_t z) {
// RDI=x, RSI=y, RDX=z
}
@implementation ClassABC
- (void)abcWithX:(int64_t)x y:(int64_t)y z:(int64_t)z
{
// RDI=self, RSI=_cmd, RDX=x, RCX=y, R8=z
}
@end
If there are more arguments or arguments that cannot be passed on registers they are pushed on the stack from right to left.
// RDI=t, RSI=u, RDX=v, RCX=w, R8=x, R9=y (z pushed to stack)
void abc(int64_t t, int64_t u, int64_t v,
int64_t w, int64_t x, int64_t y,
int64_t z) { }
If the return value is too large to fit in RAX
then RDX
is also used.
If it is too large to fit in two registers then the caller allocates space and stores the address in RDI
. This same address is returned in RAX
. This effectively shifts all the arguments over and is why the objc_msgsend_stret
functions exist.
For variadic functions RAX
is used as a secret argument to pass the number of XMM
vector registers used.
Note: This is an abbreviated explanation. Read the ABI document for the full details.
Swift
Swift does not commit to using the platform default calling convention except when calling foreign functions. You can read about the Swift Calling Conventions.
Assembly Notes
Symbol | Notes |
---|---|
[instruction] [source], [dest] | Unix syntax is source, dest. Intel syntax is a spiteful and hateful thing. We shall never speak of it again. |
$ | Constant Value |
% | Register Name |
() | Load from memory (pointer dereference) |
b suffix | 8-bit byte form of instruction |
w suffix | 16-bit word form of instruction |
l suffix | 32-bit long form of instruction |
q suffix | 64-bit quadword form of instruction |
The full form of an address can include displacement(base register, offset register, multiplier).
Example
You're crashing with EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
. You can see disassembly something like this:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
subq $0xa8, %rsp
movq %rdi, %r9
leaq 0xdbb4(%rip), %r8 ; "XPC API Misuse: %s"
leaq -0xb0(%rip), %rbx
movl $0xa0, %esi
movl $0x0, %edx
movl $0xa0, %ecx
xorl %eax, %eax
movq %rbx, %rdi
callq 0x10aabbccd ; symbol stub for __snprintf_chk
movq %rbx, 0x1b0cd(%rip)
leaq 0xdb99(%rip), %rax ; "API Misuse"
movq %rax, 0x1b0c7(%rip)
ud2 ; <-- Stopped here
The ud2
instruction is exactly what the mnemonic seems like: undefined. It's a deliberate crash. The first few lines are standard function prolog stuff. Then we see the address of a string is loaded along with some other parameter setup. Then we see it is calling __snprintf_chk
which we can guess is going to print a string into a string buffer, most likely the crash message. Given what we know about the ABI, RAX
would have held the printed string but alas the movq
instruction has blasted it.
However if we unwind the execution mentally and use what we know about the ABI we can still find it. The first parameter is probably the buffer to write to. Right before the call RBX
was copied to RDI
which lines up.
lea
is load effective address with theq
quad-word suffix. It usesRIP
as a base, indexes0xB0
bytes backwards. Then instead of reading from that address likeMOV
would it stores the address itself.
Modern processors have address calculation units solea
instructions can often happen in parallel to normal integer instructions. Take any instruction that would dereference a pointer then substitutelea
to get the pointer instead.
We see that RBX
was found by subtracting 0xB0
from RIP
then using that as a pointer to load from. Nothing has overwritten RBX
since then so let's see what it holds:
(lldb) x -c 70 $rbx
0x7ffeea3d7f70: 58 50 43 20 41 50 49 20 4d 69 73 75 73 65 3a 20 XPC API Misuse:
0x7ffeea3d7f80: 41 63 74 69 76 61 74 69 6f 6e 20 6f 66 20 61 20 Activation of a
0x7ffeea3d7f90: 63 6f 6e 6e 65 63 74 69 6f 6e 20 77 69 74 68 6f connection witho
0x7ffeea3d7fa0: 75 74 20 61 6e 20 65 76 65 6e 74 20 68 61 6e 64 ut an event hand
0x7ffeea3d7fb0: 6c 65 72 2e 00 00 ler...
There it is!
This blog represents my own personal opinion and is not endorsed by my employer.