Why does the following x64 assembly give me "Address boundary error"? It only happens when I add code after call _print_string
. I assume that some of the register have been modified but aren't they supposed to be reverted once the _print_string
function returns?
I am using Mac OS X
obj_size = 8
.data
hello_world: .asciz "hello world!"
.text
.globl _main
_main:
pushq %rbp
movq %rsp, %rbp
leaq hello_world(%rip), %rdi
callq _print_string
subq obj_size, %rsp
movq 1, %rax
movq %rax, obj_size(%rsp)
addq obj_size, %rsp
leave
ret
And the C program is:
void
print_string(char *str)
{
printf("%s\n", str);
}
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