2017-01-17 33 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中有第一个参数是正确的 –