代码之家  ›  专栏  ›  技术社区  ›  zneak

i386汇编问题:为什么我需要处理堆栈指针?

  •  6
  • zneak  · 技术社区  · 15 年前

    我决定是的 乐趣 gcc -S 我可以给我。最后我得到了这个:

    HELLO:
        .ascii "Hello, world!\12\0"
        .text
    
    .globl _main
    _main:
        pushl   %ebp        # 1. puts the base stack address on the stack
        movl    %esp, %ebp  # 2. puts the base stack address in the stack address register
        subl    $20, %esp   # 3. ???
        pushl   $HELLO      # 4. push HELLO's address on the stack
        call    _puts       # 5. call puts
        xorl    %eax, %eax  # 6. zero %eax, probably not necessary since we didn't do anything with it
        leave               # 7. clean up
        ret                 # 8. return
                            # PROFIT!
    

    它编译 甚至还能工作 ! 我想我明白了

    但是,魔术发生在第3步。如果我删除这行,我的程序将在调用 puts 以及 xor 从未对齐的堆栈错误。我会改变吗 $20 very 很重要。

    有人能解释一下吗(我使用的是Mac OS,这有什么关系吗。)

    3 回复  |  直到 15 年前
        1
  •  3
  •   academicRobot    15 年前

    在x86 OSX上,函数调用的堆栈需要16字节对齐,请参见ABI文档 here . 所以,解释是

    push stack pointer (#1)         -4
    strange increment (#3)         -20
    push argument (#4)              -4
    call pushes return address (#5) -4
    total                          -32
    

    此外,伊格纳西奥·巴斯克斯·艾布拉姆斯指出,#6不是可选的。寄存器包含以前计算的剩余部分,因此必须显式地归零。

    this 非常有助于64位组装。

        2
  •  3
  •   Ignacio Vazquez-Abrams    15 年前

    注释的一般形式应该是“为局部变量分配空间”。为什么? 改变 我不确定它会不会崩溃。我只能看到它崩溃,如果你减少它。6的正确注释是“准备从这个函数返回0”。

        3
  •  1
  •   Josh Haberman    15 年前

    请注意,如果使用-fomit frame指针编译 %ebp 指针样板将消失。基指针有助于调试,但在x86上实际上并不需要。

    另外,我强烈建议使用所有GCC/binutils支持的Intel语法。我曾经认为AT&和;T和Intel语法只是一个品味的问题,但是有一天我遇到了 this example AT&记忆法和英特尔的完全不同。由于所有的x86官方文档都使用英特尔语法,所以这似乎是一个更好的方法。

    推荐文章