【问题标题】:Save variable to stack (X86-64 assembly)将变量保存到堆栈(X86-64 程序集)
【发布时间】:2013-12-31 02:25:55
【问题描述】:

我用 x86-64 汇编 (AT&T) 语法编写了一个小程序,它汇编得很好,但我没有得到我期望的结果。 我在寄存器%rdi 中有一个变量,我需要在子程序中对其进行修改,并且我需要保留原始值以供以后使用。我要做的是将push的原始值放入堆栈,然后在子例程完成时再次检索它,例如,如果变量位于%rdi

    pushq %rdi
    call subroutine
    movq (%rsp), %rdi

现在,我不确定这是否是正确的做法?我在某处读过子程序将返回值推送到堆栈上,但这是否意味着我在尝试检索变量时必须包含偏移量?

我也知道我必须保持堆栈指针对齐 16 个字节,我不太确定我是否这样做。如果我不这样做,汇编器会不会给我一个错误,或者这可能是我的程序失败的原因吗?

顺便说一下,这个程序是作业的一部分,所以我不能和你分享代码,但我希望我的描述足够好。

【问题讨论】:

  • 无法想象你的作业有什么秘密以至于你不能分享代码。
  • 这不是秘密,但如果将整个程序发布在网站上并要求其他人纠正所有错误,那么我就处于作弊的边缘。

标签: assembly stack x86-64 calling-convention


【解决方案1】:

代码片段很可疑,因为它未能在调用序列中保持堆栈指针平衡,这可能不是预期的行为。通常,您要么匹配pushpop 操作,多次匹配push,然后匹配addq $k, %rsp(其中k 是每个先前push 的组合大小),或者在整个执行过程中保持帧大小不变函数并使用显式访问。

鉴于您需要保持堆栈指针 16 字节对齐,保持恒定大小的帧可能是最直接的方法。它可能看起来像

# in the function prologue
subq $K, %rsp
...
mov %rdi, SLOT(%rsp)
call subroutine
mov SLOT(%rsp), %rdi
...
# in the epilogue
addq $K, %rsp

其中K 是所有本地堆栈状态的足够空间加上最大的输出参数集的足够空间,四舍五入到 16,SLOT 是堆栈上为 %rdi 的值保留的位置.

整数类型的返回值通常放在rax中,而不是在栈上。其他类型的返回方式不同(例如通过隐藏指针) - 检查您正在与之交互的编译器的调用约定。

【讨论】:

  • 好的,所以根据我从你的回答中可以理解,下面的代码可以做到吗? subq $16, %rsp movq %rdi, 8(%rsp) 调用子程序 movq 8(%rsp), %rdi addq $16, %rsp
  • 这对我来说看起来不错,尽管您通常会为整个函数使用一对subq/addq,而不是为每个子例程调用使用一对。
  • 好的,非常感谢。我的程序仍然没有达到预期的效果,但结果发生了变化。我可能只需要花更多时间查看代码。
【解决方案2】:

使用 popq %rdi 代替 movq (%rsp),%rdi。第一个不会更新RSP 堆栈指针,因此在返回调用您的函数时可能会遇到问题。

当然,如果subroutine 不为自己调整堆栈。它subroutine 正在使用standard (Pascal) calling convention,参数将由函数本身而不是调用者删除,您将无法访问保存的%rdi 值。

【讨论】:

    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 2014-08-07
    相关资源
    最近更新 更多