【问题标题】:Difference between i386 and x86-64 memory stacki386 和 x86-64 内存栈的区别
【发布时间】:2017-01-17 14:35:39
【问题描述】:

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

【问题讨论】:

  • 调用约定不同,不是吗?
  • 也许使用调试器并找出故障发生在哪里?
  • 除非他们上周改变了整个语言规范,否则这不是 C,而是汇编语言。不要垃圾标签! (调用库函数不会改变这一点!)

标签: gcc assembly x86 nasm


【解决方案1】:

在 32 位模式下,大多数 调用约定(cdeclstdcall 等...)期望参数被压入堆栈,而不是寄存器中,这与 64 不同-bit 模式,另外,调用puts 后需要调整堆栈指针,因此需要执行以下操作:

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

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

【讨论】:

  • 原来是这个问题,谢谢!有一段时间没有真正使用 i386
  • 大多数调用约定需要什么并不重要。这是一个 C 标准库函数,因此它将使用 cdecl 调用约定,这意味着您的答案是正确的。 (如果是 stdcall,那么被调用者会清理堆栈,而不是调用者!)
  • @CodyGray 肯定同意,但我试图给出一个一般情况的答案 - 如果说,他正在调用一个使用 ms fastcall 而不是标准 C 函数的函数,那么它将是在 ECX 中有第一个参数是正确的
猜你喜欢
  • 2015-01-20
  • 2017-03-11
  • 1970-01-01
  • 2013-10-12
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2015-08-09
相关资源
最近更新 更多