【问题标题】:Why doesn't this assembly code print the top of the stack?为什么这个汇编代码不打印堆栈的顶部?
【发布时间】:2019-03-10 18:41:46
【问题描述】:

成功发出“Hello, World!”之后x86-64 中的程序,我想要 制作一个可以窥视堆栈顶部的程序(不弹出它,并使用esp 寄存器,这样我就可以了解它是如何工作的)。这是 NASM 中的程序:

extern GetStdHandle, WriteConsoleA, ExitProcess
section .bss
    dummy resd 1
section .text
%macro print 3
    mov rcx, %1
    mov rdx, %2
    mov r8, %3
    mov r9, dummy
    push NULL
    call WriteConsoleA
%endmacro
_start:
    mov rcx, STD_OUTPUT_HANDLE
    call GetStdHandle

    push 65
    print rax, [x], 1

    mov rcx, 0
    call ExitProcess

NULL equ 0
STD_OUTPUT_HANDLE equ -11

print rax, [x], 1 行,x 被替换为某些东西。我尝试了各种方法,例如rspesprsiesirsp+1rsp+4 等,但都没有奏效。他们要么不编译,要么不打印任何东西。

正确的做法是什么? (注意:这仅用于实验目的。我知道在这种情况下我可以使用push/pop,但我想学习如何这样做。)

【问题讨论】:

  • print rax, rsp, 1 应该可以工作。发生了什么?请注意,您没有遵循标准调用约定,尤其是阴影空间和堆栈对齐要求。
  • @Jester 是的,我是组装新手,所以我不确定如何正确地做事。

标签: windows assembly x86-64


【解决方案1】:

mov rdx, [rsp] 会将 65 加载到 rdx。但是 WriteConsole 需要打印字符串的 address。所以你想要mov rdx, rsp

还有一点需要解决:调用前堆栈应该对齐到 16 个字节,堆栈顶部应该有 32 个字节的空白空间。推送后,输入sub rsp, 40。然后使用rsp+40作为打印地址。

【讨论】:

  • 啊,我怎么错过了!使用mov rdx, rsp 它仍然无法正常工作。当我运行它时它挂起
  • 对不起,我对组装很陌生,你能解释一下对齐方式吗?
  • 对于大多数函数调用,堆栈在调用之前是对齐的,并且调用本身会压入返回地址(8 个字节),所以每个函数都应该减去 odd 的倍数8 从堆栈指针(由 push 65 完成)。但是,由于这是_start,不是普通函数,我怀疑堆栈在入口时已经对齐到16,所以你需要额外减去8个字节。
  • 这个问题的答案或许能更好地解释它:stackoverflow.com/questions/40344385
  • 为什么我们需要在_start处“减去额外的8个字节”?为什么sub rsp, 40 在推送之后而不是之前?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
相关资源
最近更新 更多