【问题标题】:Assembly: function template meditation汇编:函数模板冥想
【发布时间】:2015-01-20 15:19:15
【问题描述】:

我现在正在学习汇编,但我对(大概)标准函数模板一无所知。

因此,基于this really nice book“函数要记住的形式如下:”

function_label:
    pushl   %ebp
    movl    %esp, %ebp
    < normal function code goes here>
    movl    %ebp, %esp
    popl    %ebp
    ret

好的,我很好,但是有一件小事我不明白。在“正常功能代码”之后,我们恢复esp 的初始(调用前)值,该值之前存储在ebp 中。

现在,我清楚地理解了为什么我们要将 esp 值原封不动地返回给调用上下文。我不明白的是在什么条件下esp 值可以在函数执行期间完全改变。

此模板中是否包含某种针对我们自己的保护(以防我们以某种方式破坏了代码中某处的堆栈)?或者也许改变函数内部的堆栈值是一种正常的做法? 或者即使我们不做任何事情,初始的esp 值也可能在执行过程中最终改变? (事实上​​,我无法弄清楚这是怎么回事。)

想到这个我觉得很傻,并在这个简单的代码中用gdb检查了esp的值:

.section .data
message:
    .asciz "> Hello from function #%d\n"

.section .text
.globl main

main:
    nop
    call    overhere
    pushl   $0
    call    exit
overhere:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   $1
    pushl   $message
    call    printf
    add     $8, %esp
    movl    %ebp, %esp
    popl    %ebp
    ret 

esp(正如我实际预期的那样)没有受到影响,因此将ebp 移动到esp 实际上并没有改变任何东西。

现在,我希望我想知道什么很清楚:

  • esp 的值最终会自行改变吗? (我敢打赌它不能。)
  • 如果不能,那么上面的这个模板显然假定程序员可能会在函数内部以某种方式更改它。但我不明白为什么在地球上可能需要这样做,所以 - 更改 esp 值是一个错误吗?

提前谢谢你,原谅我的无知。

【问题讨论】:

    标签: function assembly x86 stack gnu-assembler


    【解决方案1】:

    我很困惑你怎么错过了明确改变esp:add $8, %esp的指令。所以答案显然是肯定的,它可能会在函数期间发生变化并且不是错误。注意pushcall也改了,其实add是为了补偿两条push指令(printf末尾的ret会平衡call)。更改esp 的其他典型原因是局部变量的分配。这已从您显示的函数模板中省略,它通常在 movl %esp, %ebp 之后看起来像 sub $size_of_locals, %esp

    也就是说,您不需要使用ebp 来记住堆栈指针,只要您确保它在函数退出时与进入时具有相同的值。最新版本的 gcc 在启用优化时不要使用ebp,否则您可以使用-fomit-frame-pointer 这样做。

    【讨论】:

      猜你喜欢
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-27
      • 2011-04-20
      • 1970-01-01
      相关资源
      最近更新 更多