了解空 main() 转换为程序集 [英] Understanding empty main()'s translation into assembly

查看:15
本文介绍了了解空 main() 转换为程序集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

谁能解释一下 GCC 对这段代码做了什么?它在初始化什么?原代码为:

Could somebody please explain what GCC is doing for this piece of code? What is it initializing? The original code is:

#include <stdio.h>
int main()
{

}

它被翻译成:

    .file   "test1.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .text
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    call    __alloca
    call    ___main
    leave
    ret

如果编译器/汇编专家让我开始解释堆栈、寄存器和部分初始化,我将不胜感激.我无法从代码中脱颖而出.

I would be grateful if a compiler/assembly guru got me started by explaining the stack, register and the section initializations. I cant make head or tail out of the code.

我正在使用 gcc 3.4.5.命令行参数是 gcc -S test1.c

I am using gcc 3.4.5. and the command line argument is gcc -S test1.c

谢谢你,昆贾恩.

推荐答案

我应该在所有评论的开头说,我还在学习汇编.

I should preface all my comments by saying, I am still learning assembly.

我将忽略部分初始化.部分初始化的解释以及我所涵盖的基本上所有其他内容都可以在这里找到:http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax

I will ignore the section initialization. A explanation for the section initialization and basically everything else I cover can be found here: http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax

ebp 注册堆栈帧 基指针,因此是 BP.它存储一个指向当前堆栈开头的指针.

The ebp register is the stack frame base pointer, hence the BP. It stores a pointer to the beginning of the current stack.

esp 寄存器是堆栈指针.它保存堆栈顶部的内存位置.每次我们将某些东西压入堆栈时,esp 都会更新,以便它始终指向堆栈顶部的地址.

The esp register is the stack pointer. It holds the memory location of the top of the stack. Each time we push something on the stack esp is updated so that it always points to an address the top of the stack.

所以 ebp 指向底部,而 esp 指向顶部.所以堆栈看起来像:

So ebp points to the base and esp points to the top. So the stack looks like:

esp -----> 000a3   fa
           000a4   21
           000a5   66
           000a6   23
ebp -----> 000a7   54

如果您将 e4 压入堆栈,会发生以下情况:

If you push e4 on the stack this is what happens:

esp -----> 000a2   e4
           000a3   fa
           000a4   21
           000a5   66
           000a6   23
ebp -----> 000a7   54

注意堆栈向低地址增长,这一事实在下面很重要.

Notice that the stack grows towards lower addresses, this fact will be important below.

前两个步骤称为过程序言或更常见的函数序言.他们准备堆栈以供局部变量使用(参见底部的过程序言引用).

The first two steps are known as the procedure prolog or more commonly as the function prolog. They prepare the stack for use by local variables (See procedure prolog quote at the bottom).

在第 1 步中,我们通过调用将指向旧堆栈帧的指针保存在堆栈上推送 %ebp.由于 main 是第一个调用的函数,我也不知道 %ebp 的先前值是什么.

In step 1 we save the pointer to the old stack frame on the stack by calling pushl %ebp. Since main is the first function called, I have no idea what the previous value of %ebp points too.

第 2 步,我们正在输入一个新的堆栈帧,因为我们正在输入一个新函数(main).因此,我们必须设置一个新的堆栈帧基指针.我们使用 esp 中的值作为堆栈帧的开始.

Step 2, We are entering a new stack frame because we are entering a new function (main). Therefore, we must set a new stack frame base pointer. We use the value in esp to be the beginning of our stack frame.

步骤 3. 在堆栈上分配 8 个字节的空间.正如我们上面提到的,堆栈向低地址增长,因此,减去 8,将堆栈顶部移动 8 个字节.

Step 3. Allocates 8 bytes of space on the stack. As we mentioned above, the stack grows toward lower addresses thus, subtracting by 8, moves the top of the stack by 8 bytes.

第 4 步;对齐堆栈,我对此有不同的看法.我不太确定这是做什么的.我怀疑这样做是为了允许在堆栈上分配大指令 (SIMD),

Step 4; Aligns the stack, I've found different opinions on this. I'm not really sure exactly what this is done. I suspect it is done to allow large instructions (SIMD) to be allocated on the stack,

http://gcc.gnu.org/ml/gcc/2008-01/msg00282.html

此代码与 0xFFFF0000 的 ESP 相和",将堆栈与下一个对齐最低 16 字节边界.一个Mingw的源代码检查表明这可能适用于 SIMD_main"中出现的说明例程,仅在对齐时运行地址.因为我们的例程没有包含 SIMD 指令,这一行是不必要的.

This code "and"s ESP with 0xFFFF0000, aligning the stack with the next lowest 16-byte boundary. An examination of Mingw's source code reveals that this may be for SIMD instructions appearing in the "_main" routine, which operate only on aligned addresses. Since our routine doesn't contain SIMD instructions, this line is unnecessary.

http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax

步骤 5 到 11 对我来说似乎没有意义.我在谷歌上找不到任何解释.真正了解这些东西的人能否提供更深入的理解.我听说这东西是用于 C 的异常处理的.

Steps 5 through 11 seem to have no purpose to me. I couldn't find any explanation on google. Could someone who really knows this stuff provide a deeper understanding. I've heard rumors that this stuff is used for C's exception handling.

第五步,将main 0的返回值存储在eax中.

Step 5, stores the return value of main 0, in eax.

第 6 步和第 7 步我们将十六进制的 15 添加到 eax 中,原因不明.eax = 01111 + 01111 = 11110

Step 6 and 7 we add 15 in hex to eax for unknown reason. eax = 01111 + 01111 = 11110

第 8 步我们将 eax 的位向右移动 4 位.eax = 00001 因为最后一位从末尾移出 00001 |111.

Step 8 we shift the bits of eax 4 bits to the right. eax = 00001 because the last bits are shift off the end 00001 | 111.

第 9 步我们将 eax 的位向左移动 4 位,eax = 10000.

Step 9 we shift the bits of eax 4 bits to the left, eax = 10000.

步骤 10 和 11 将堆栈上分配的前 4 个字节中的值移入 eax,然后将其从 eax 移回.

Steps 10 and 11 moves the value in the first 4 allocated bytes on the stack into eax and then moves it from eax back.

步骤 12 和 13 设置 c 库.

Steps 12 and 13 setup the c library.

我们已经到了函数尾声.也就是说,函数中将堆栈指针 esp 和 ebp 返回到调用此函数之前的状态的部分.

We have reached the function epilogue. That is, the part of the function which returns the stack pointers, esp and ebp to the state they were in before this function was called.

第 14 步,leave 将 esp 设置为 ebp 的值,将栈顶移动到调用 main 之前的地址.然后它设置 ebp 指向我们在步骤 1 中保存在栈顶的地址.

Step 14, leave sets esp to the value of ebp, moving the top of stack to the address it was before main was called. Then it sets ebp to point to the address we saved on the top of the stack during step 1.

离开可以只用以下指令代替:

Leave can just be replaced with the following instructions:

mov  %ebp, %esp
pop  %ebp

第15步,返回并退出函数.

Step 15, returns and exits the function.

1.    pushl       %ebp
2.    movl        %esp, %ebp
3.    subl        $8, %esp
4.    andl        $-16, %esp
5.    movl        $0, %eax
6.    addl        $15, %eax
7.    addl        $15, %eax
8.    shrl        $4, %eax
9.    sall        $4, %eax
10.   movl        %eax, -4(%ebp)
11.   movl        -4(%ebp), %eax
12.   call        __alloca
13.   call        ___main
14.   leave
15.   ret

程序序言:

函数必须做的第一件事称为过程序言.它首先保存当前基指针(ebp) 使用指令 pushl %ebp(记住 ebp 是用于访问函数参数和局部变量).现在它复制堆栈指针(esp)到基址带有指令的指针 (ebp)movl %esp, %ebp.这使您可以访问函数参数为来自基指针的索引.当地的变量总是减法来自 ebp,例如 -4(%ebp) 或(%ebp)-4 表示第一个局部变量,返回值始终为 4(%ebp)或 (%ebp)+4,每个参数或参数在 N*4+4(%ebp) 例如第一个参数为 8(%ebp) 而旧的 ebp 位于 (%ebp).

The first thing a function has to do is called the procedure prolog. It first saves the current base pointer (ebp) with the instruction pushl %ebp (remember ebp is the register used for accessing function parameters and local variables). Now it copies the stack pointer (esp) to the base pointer (ebp) with the instruction movl %esp, %ebp. This allows you to access the function parameters as indexes from the base pointer. Local variables are always a subtraction from ebp, such as -4(%ebp) or (%ebp)-4 for the first local variable, the return value is always at 4(%ebp) or (%ebp)+4, each parameter or argument is at N*4+4(%ebp) such as 8(%ebp) for the first argument while the old ebp is at (%ebp).

http://www.milw0rm.com/papers/52

存在一个非常棒的堆栈溢出线程,它回答了这个问题的大部分.为什么我的 gcc 输出中有额外的指令?

A really great stack overflow thread exists which answers much of this question. Why are there extra instructions in my gcc output?

可以在此处找到有关 x86 机器代码指令的良好参考:http://programminggroundup.blogspot.com/2007/01/appendix-b-common-x86-instructions.html

A good reference on x86 machine code instructions can be found here: http://programminggroundup.blogspot.com/2007/01/appendix-b-common-x86-instructions.html

本次讲座包含以下使用的一些想法:http://csc.colstate.edu/bosworth/cpsc5155/Y2006_TheFall/MySlides/CPSC5155_L23.htm

This a lecture which contains some of the ideas used below: http://csc.colstate.edu/bosworth/cpsc5155/Y2006_TheFall/MySlides/CPSC5155_L23.htm

以下是回答您问题的另一种看法:http://www.phiral.net/linuxasmone.htm

Here is another take on answering your question: http://www.phiral.net/linuxasmone.htm

这些资料都不能解释一切.

None of these sources explain everything.

这篇关于了解空 main() 转换为程序集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆