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 位模式下,大多数 调用约定(cdecl
、stdcall
等...)期望将参数推送到堆栈,不在寄存器中,与 64 位模式不同,而且,您需要在调用 puts
后调整堆栈指针,因此您需要执行以下操作:
lea edx, @message
push edx
call puts
add esp, 4
让程序在 32 位模式下产生相同的输出。我可能没有正确的 NASM 语法,因为我通常在 MASM 和 GAS 中编写汇编代码。
在我的 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 位模式下,大多数 调用约定(cdecl
、stdcall
等...)期望将参数推送到堆栈,不在寄存器中,与 64 位模式不同,而且,您需要在调用 puts
后调整堆栈指针,因此您需要执行以下操作:
lea edx, @message
push edx
call puts
add esp, 4
让程序在 32 位模式下产生相同的输出。我可能没有正确的 NASM 语法,因为我通常在 MASM 和 GAS 中编写汇编代码。