2017-01-17 32 views
-2

在我的Ubuntu機器上嘗試使用NASM和GCC製作一個非常小的程序時,我注意到了一些奇怪的東西。i386和x86-64內存棧之間的區別

下面的代碼在64位NASM和GCC編譯罰款:

global main 
    extern puts 

section .text 
    main: 
    push rax 
    mov rdi, message 
    call puts 
    jmp exit 
    exit: 
    ;return stack memory 
    pop rax 
    ret 
    message: 
    db "Hello from NASM!", 0 

但是試圖編譯相同的代碼(僅與寄存器改變)根據32位NASM和GCC時,它要麼結果分段錯誤和/或隨機字符。這是爲什麼發生? x64體系結構在將內存存儲到堆棧上的方式與i386不同嗎?如果是這樣,這種行爲如何被阻止?

+3

調用約定是不同的,不是嗎? –

+0

也許使用調試器並找出故障發生的位置? –

+0

上週除非他們改變了整個語言規範,否則這不是C,而是彙編語言。不要垃圾標籤! (調用庫函數不會改變這個!) – Olaf

回答

3

當在32位模式下,調用約定(cdeclstdcall,等...)預計參數堆棧在64位模式推,而不是在寄存器中,不同的是,和也,你需要調用puts後調整堆棧指針,所以你需要做的是這樣:

lea edx, @message 
push edx 
call puts 
add esp, 4 

對於程序產生32位模式相同的輸出。我可能沒有NASM語法,因爲我通常在MASM和GAS中編寫彙編代碼。

+1

所以這就是問題,謝謝!有一段時間沒有真正使用i386 – Tatu

+1

大多數調用約定所需要的並不重要。這是一個C標準庫函數,因此它將使用cdecl調用約定,這意味着您的答案是正確的。 (如果是stdcall,那麼被調用者會清理堆棧,而不是調用者!) –

+0

@CodyGray同意,但我試圖給出一般情況下的答案 - 如果他說的是,他正在調用一個使用ms的函數fastcall而不是標準的C函數,那麼在ECX中有第一個參數是正確的 –