The issue with this code is pretty simple. In GNU Assembler using AT&T syntax -
literal constants that are used as an immediate operand need to be prefixed with a $
(dollar sign) otherwise the constant is treated as a memory operand.
These lines all have this issue:
subq obj_size, %rsp
movq 1, %rax
[snip]
addq obj_size, %rsp
In these cases since you want to use the constants obj_size
and 1
as a value (immediate operand) and not a memory reference. The instructions above should have been:
subq $obj_size, %rsp
movq $1, %rax
[snip]
addq $obj_size, %rsp
subq obj_size, %rsp
attempted to subtract the 64-bit value at memory address 0x8 from the value in RSP. movq 1, %rax
attempted to move the 64-bit value at memory address 0x1 into RAX. Your program faulted since those memory locations on OS/X can't be read from.
A good article on the difference between AT&T syntax and Intel syntax can be found on IBM's website. In particular they have this difference listed:
In AT&T syntax, immediate operands are preceded by $; in Intel syntax, immediate operands are not. For example: Intel: push 4
, AT&T: pushl $4
To narrow down problems like these it is often beneficial to use a debugger. On OS/X if you are not using Xcode you can use the debugger LLDB from the command line. A tutorial on using LLDB may be useful. In this case you could have run LLDB as lldb ./nameofprogram
and then used the run
command to allow it to continue until it failed. The debugger would have then shown you what assembly instruction the crash occurred at.
If you want to know the calling convention used by 64-bit OS/X code Apple defines it this way:
The OS X x86-64 function calling conventions are the same as the function calling conventions described in System V Application Binary Interface AMD64 Architecture Processor Supplement.
You can find the System V Application Binary Interface AMD64 Architecture Processor Supplement here. The list of caller and callee saved registers can be found in Figure 3.4: Register Usage