i386 和 x86-64 内存栈的区别

Difference between i386 and x86-64 memory stack

在我的 Ubuntu 机器上尝试使用 NASM 和 GCC 制作一个非常小的程序时,我发现了一些奇怪的东西。

以下代码在 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 下编译相同的代码(仅更改寄存器)时,它会导致分段错误 and/or 随机字符。为什么会这样? x64 架构将内存存储到堆栈的方式是否与 i386 不同?如果是这样,如何防止这种行为?

在 32 位模式下,大多数 调用约定(cdeclstdcall 等...)期望将参数推送到堆栈,不在寄存器中,与 64 位模式不同,而且,您需要在调用 puts 后调整堆栈指针,因此您需要执行以下操作:

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

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