2017-04-10 92 views
1

爲什麼下面的x64程序集會給我「地址邊界錯誤」?只有當我在call _print_string之後添加代碼時纔會發生。我假設一些寄存器已被修改,但不是在_print_string函數返回時它們應該被還原嗎?x64:爲什麼這段代碼給我「地址邊界錯誤」

我使用的是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 

與C程序的是:

void 
print_string(char *str) 
{ 
    printf("%s\n", str); 
} 
+1

哪些操作系統?一些寄存器不被保留,並且保存哪些不同於OS到OS。 –

+0

@RudyVelthuis我使用的是Mac OS X –

回答

3

問題與此代碼非常簡單。在GNU彙編程序中使用AT & T語法 - 用作立即數操作數的立即數常量需要以$(美元符號)作爲前綴,否則常量將被視爲內存操作數。因爲你要使用的常量obj_size1作爲一個值(立即數),而不是內存引用

subq obj_size, %rsp 
movq 1, %rax 
[snip] 
addq obj_size, %rsp 

在這些情況下:

這些線路都有這個問題。上述說明應該是:

subq $obj_size, %rsp 
movq $1, %rax 
[snip] 
addq $obj_size, %rsp 

subq obj_size, %rsp試圖減去RSP在從值存儲器地址0x8中的64位值。 movq 1, %rax試圖將內存地址0x1處的64位值移動到RAX。由於OS/X上的這些內存位置無法讀取,因此您的程序發生故障。

關於AT & T語法和Intel語法之間差異的好文章可以在IBM's website上找到。特別是他們有以下差異:

在AT & T語法中,立即數操作數前面加$;在英特爾語法中,立即操作數不是。例如:英特爾:push 4,AT & T:pushl $4


要縮小這樣的往往是有益使用調試器的問題。在OS/X上,如果您不使用Xcode,則可以使用命令行中的調試器LLDB。 A tutorial on using LLDB可能會有用。在這種情況下,您可以運行LLDB作爲lldb ./nameofprogram,然後使用run命令允許它繼續,直到失敗。然後調試器會向您顯示崩潰發生時的彙編指令。


如果你想知道64位OS/X代碼Apple defines it this way使用的調用約定:

OS X的x86-64的函數調用約定是相同的調用約定的函數描述System V應用程序二進制接口AMD64體系結構處理器補充。

您可以找到系統V應用程序二進制接口AMD64架構處理器補充here。主叫方和被叫方的列表保存的寄存器可以圖3.4中找到:註冊使用