对组装说明感到困惑

时间:2014-06-25 23:32:09

标签: assembly byte intel att

我正在阅读这篇关于汇编的教程:http://orangejuiceliberationfront.com/intel-assembler-on-mac-os-x/,我遇到了这个基本的汇编代码:

    .text
.globl _main
_main:
    pushl %ebp
    movl %esp, %ebp
    subl $8, %esp
    movl $0, %eax
    leave
    ret

我对此大部分了解,但我不知道为什么subl $8, %esp被召唤。我知道它从esp中减去了8个字节,但我不知道为什么这是必要的或者为什么要这样做。该教程说它将堆栈平衡到一个16字节的边界,但我不知道"平衡"堆栈意味着为什么使用数字8形成一个16字节的边界。

本教程后面将展示如何定义一个函数,并将其调用如下:

    .text
.globl _doSomething
_doSomething:
    pushl %ebp
    movl %esp, %ebp
    subl $8, %esp
    nop
    leave
    ret

.globl _main
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $3, (%esp)
    call    _doSomething
    movl    $0, %eax
    leave
    ret

教程中有" 8对齐,16为我们的4字节参数和填充"在这一行:subl $24, %esp

但如果有一个4字节的参数和填充,为什么我们使用数字16?还有什么参数?

我使用的是Intel Core mac,运行OS X 10.9.3,使用gcc -S -m32进行编译。

我对装配很新,所以请尽可能简单地回答你的问题。谢谢!

3 个答案:

答案 0 :(得分:2)

让我们看一系列指令:

1. nop   #call-stack is aligned to 16 bytes (sp is multiple of 16) to start.
2. call function #pushes return address (4 bytes) onto stack.

---(called function)
3. push %ebp #pushes base-pointer (4 bytes) onto stack, which is now 8-byte aligned
---cannot call function that expects to find 16-byte aligned stack---
4. sub $8, %esp #aligns stack to 16 bytes
5. call other_function

答案 1 :(得分:1)

如何在机器语言级别调用函数是由称为调用约定的东西强制执行的,该调用约定通常是体系结构和特定于操作系统的。它的设计使您可以以可互操作的方式调用其他功能。在这种情况下,调用约定指定被调用函数可以预期,当调用函数时,堆栈指针在16字节边界上对齐。

这意味着堆栈指针(esp)是16个字节的倍数。

这样做是因为某些指令仅适用于存储在16的倍数的内存位置的数据,主要是出于性能原因。其他指令甚至可以在未对齐的数据上工作,但效率却低得多。

答案 2 :(得分:1)

如果你想问“为什么程序看起来不像这样?”:

_main:
    mov $0, %eax   ; sub %eax, %eax would be more efficient
    ret

你是对的。以下四条说明:

pushl %ebp
movl %esp, %ebp
subl $8, %esp
leave

在示例中完全没用。

如果您手动编写此汇编程序函数(或对C编译器输出进行后优化),则不会编写(或删除)这四条指令。

然而,大多数C编译器都针对“正常情况”进行了优化:除了返回常量值之外什么都不做的C函数(这种情况就是这种情况)并不经常出现。

在大多数C函数(包含变量和实际代码)中,上面显示的四条指令都有意义!这就是为什么大多数C编译器总是插入这四个指令,即使在特殊情况下不需要它们。

我想汇编教程只是插入四条指令,因为在下一步中会有更多指令添加到函数中......