Gcc i386和x86-64内存堆栈之间的差异

Gcc i386和x86-64内存堆栈之间的差异,gcc,assembly,x86,nasm,Gcc,Assembly,X86,Nasm,当我试图在我的Ubuntu机器上用NASM和GCC制作一个非常小的程序时,我注意到了一些奇怪的事情 以下代码在64位NASM和GCC下编译良好: 但是,当试图在32位NASM和GCC下编译相同的代码(仅在寄存器更改的情况下)时,可能会导致分段错误和/或随机字符。为什么会这样?x64体系结构在将内存存储到堆栈中的方式是否与i386不同?如果是这样,如何防止这种行为呢?在32位模式下,大多数调用约定(cdecl,stdcall,等等)都希望参数被推送到堆栈上,而不是寄存器中,这与64位模式不同,而

当我试图在我的Ubuntu机器上用NASM和GCC制作一个非常小的程序时,我注意到了一些奇怪的事情

以下代码在64位NASM和GCC下编译良好:

但是,当试图在32位NASM和GCC下编译相同的代码(仅在寄存器更改的情况下)时,可能会导致分段错误和/或随机字符。为什么会这样?x64体系结构在将内存存储到堆栈中的方式是否与i386不同?如果是这样,如何防止这种行为呢?

在32位模式下,大多数调用约定(
cdecl
stdcall
,等等)都希望参数被推送到堆栈上,而不是寄存器中,这与64位模式不同,而且,在调用
puts
之后,还需要调整堆栈指针,因此,您需要执行以下操作:

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

使程序在32位模式下产生相同的输出。我可能没有正确的NASM语法,因为我通常用MASM和GAS编写汇编代码。

调用约定不同,不是吗?也许可以使用调试器找出故障发生的地方?除非他们上周更改了整个语言规范,否则这不是C,而是汇编语言。不要垃圾邮件标签!(调用库函数不会改变这一点!)所以这就是问题所在,谢谢!我已经有一段时间没有真正使用i386了。大多数调用约定需要什么并不重要。这是一个C标准库函数,因此它将使用cdecl调用约定,这意味着您的答案是正确的。(如果是stdcall,那么被调用方将清理堆栈,而不是调用方!)@CodyGray肯定同意,但我试图给出一个一般情况的答案——比如说,如果他调用的是使用ms fastcall而不是标准C函数的函数,那么在ECX中使用第一个参数是正确的
lea edx, @message
push edx
call puts
add esp, 4