一个空的程序的GCC的汇编输出在x86,Win32的 [英] GCC's assembly output of an empty program on x86, win32

查看:309
本文介绍了一个空的程序的GCC的汇编输出在x86,Win32的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写空的程序惹恼了地狱的计算器codeRS,而不是。我只是探索的GNU工具链。

现在以下可能是太深的我,但到continuie我已经开始研究C编译器的输出,东东GNU作为消耗空的程序传奇。

  gcc版本4.4.0(TDM-1的mingw32)

test.c的:

  INT的main()
{
    返回0;
}

的gcc -S test.c的

  .filetest.c的
    .DEF ___main; .scl伪2; .TYPE 32; .endef伪
    。文本
.globl _main
    .DEF _main; .scl伪2; .TYPE 32; .endef伪
_主要:
    pushl%EBP
    MOVL%ESP,EBP%
    和L $ -16,ESP%
    调用___main
    MOVL $ 0,%EAX
    离开
    RET

您可以在这里说明一下会发生什么?这是我努力去理解它。我已经使用了手动和我最小的x86 ASM知识:


  • .filetest.c的是逻辑文件名的指令。

  • .DEF :根据文档的开始定义一个符号名调试信息的。什么是符号(函数名/变量?)什么样的调试信息?

  • .scl伪:文档说的存储类型可以表明符号是静态的还是外部的的。这是同一的静态的和的外部的我从C知道吗?什么是2?

  • .TYPE :存储参数的作为一个符号表项的类型属性的,我不知道

  • .endef伪:没问题

  • 的.text :现在,这是有问题的,这似乎是一种叫部分,我已阅读,其code的地方,但该文档没'不要告诉我太多。

  • .globl 使符号LD可见。的,该手册是对这个很清楚的。

  • _main:(?)这可能对我的主要功能是起始地址

  • pushl _ :长(32位)推,哪些地方在栈上EBP

  • MOVL :32位的举动。伪C: EBP = ESP;

  • 和L :逻辑和。伪C: ESP = -16安培; ESP ,我实在不明白这什么的地步。

  • 呼叫:推动IP堆栈(所以被调用过程可以找到它的归途),并继续在那里 __主是。 (什么__main?)

  • MOVL :这种零一定是恒定的我在code的最后返回。该MOV地方这种零到EAX。

  • 离开:一键指令后恢复堆栈(?)。为什么呢?

  • RET :回到被保存在栈上的指令地址

谢谢您的帮助!


解决方案

  

.filetest.c的


命令开始。是指令的汇编。这只是说,这是file.c中,这些信息可以导出为ex​​e文件的调试信息。


  

.DEF ___main; .scl伪2;
  .TYPE 32; .endef伪


.DEF指令定义了一个调试符号。 SCL 2指存储类2(外部存储类).TYPE 32说,这是sumbol功能。这些数字将被PE-COFF EXE格式来定义

___主要是一种叫做函数,它引导了GCC的需求(它会做的事情一样运行C ++静态初始化,需要其他管家)的照顾。


 的.text


开始一个文本部分 - code住在这里。


  

.globl _main


定义_main符号作为全球性的,这将使它的连接器和该公司在连接的其他模块可见。


  .DEF _main; .scl伪2; .TYPE 32; .endef伪


同样的事情_main,创建调试符号,说明_main是一个函数。这可以通过调试器使用。


  

_main:


开始一个新的标签(这将结束一个地址)。上述.globl指令,使这个地址设置为向其他实体。


  pushl%EBP


在堆栈中保存旧帧指针(EBP寄存器)(因此它可以在地方,当这个函数结束时被放回)


  MOVL%ESP,EBP%


移动堆栈指针EBP寄存器。 EBP通常被称为帧指针,它指向当前的框内的堆栈值的顶部(函数通常),(指通过EBP堆栈上的变量可以帮助调试器)


  

和L $ -16,%ESP


行逻辑与FFFFFFF0的栈用途不同其对齐16字节边界。访问对齐值在堆栈上比,如果他们未对齐的快得多。所有这些preceding说明pretty太大的标准功能序幕。

 通话___main

调用___main功能,它会做初始化的东西,GCC的需求。通话将推动堆栈上的当前指令指针,并跳转到主___的

地址

  MOVL $ 0,%EAX


0移动到EAX寄存器,(0回报0)。EAX寄存器用来保存函数返回值的stdcall调用


  

离开


leave指令是pretty多简写


  MOVL EBP,ESP
popl EBP


即。它复原次数的功能开始做的东西 - 恢复帧指针和堆栈到以前的状态。


  

RET


返回到调用此功能。它会弹出从堆栈(其中一个相应的调用指令将已摆在那里)指令指针和跳到那里。

I write empty programs to annoy the hell out of stackoverflow coders, NOT. I am just exploring the gnu toolchain.

Now the following might be too deep for me, but to continuie the empty program saga I have started to examine the output of the C compiler, the stuff GNU as consumes.

gcc version 4.4.0 (TDM-1 mingw32)

test.c:

int main()
{
    return 0;
}

gcc -S test.c

    .file	"test.c"
    .def	___main;	.scl	2;	.type	32;	.endef
    .text
.globl _main
    .def	_main;	.scl	2;	.type	32;	.endef
_main:
    pushl	%ebp
    movl	%esp, %ebp
    andl	$-16, %esp
    call	___main
    movl	$0, %eax
    leave
    ret

Can you explain what happens here? Here is my effort to understand it. I have used the as manual and my minimal x86 ASM knowledge:

  • .file "test.c" is the directive for the logical filename.
  • .def: according to the docs "Begin defining debugging information for a symbol name". What is a symbol (a function name/variable?) and what kind of debugging information?
  • .scl: docs say "Storage class may flag whether a symbol is static or external". Is this the same static and external I know from C? And what is that '2'?
  • .type: stores the parameter "as the type attribute of a symbol table entry", I have no clue.
  • .endef: no problem.
  • .text: Now this is problematic, it seems to be something called section and I have read that its the place for code, but the docs didn't tell me too much.
  • .globl "makes the symbol visible to ld.", the manual is quite clear on this.
  • _main: This might be the starting address (?) for my main function
  • pushl_: A long (32bit) push, which places EBP on the stack
  • movl: 32-bit move. Pseudo-C: EBP = ESP;
  • andl: Logical AND. Pseudo-C: ESP = -16 & ESP, I don't really see whats the point of this.
  • call: Pushes the IP to the stack (so the called procedure can find its way back) and continues where __main is. (what is __main?)
  • movl: this zero must be the constant I return at the end of my code. The MOV places this zero into EAX.
  • leave: restores stack after an ENTER instruction (?). Why?
  • ret: goes back to the instruction address that is saved on the stack

Thank you for your help!

解决方案

.file "test.c"

Commands starting with . are directives to the assembler. This just says this is "file.c", that information can be exported to the debugging information of the exe.

.def ___main; .scl 2; .type 32; .endef

.def directives defines a debugging symbol. scl 2 means storage class 2(external storage class) .type 32 says this sumbol is a function. These numbers will be defined by the pe-coff exe-format

___main is a function called that takes care of bootstrapping that gcc needs(it'll do things like run c++ static initializers and other housekeeping needed).

.text

Begins a text section - code lives here.

.globl _main

defines the _main symbol as global, which will make it visible to the linker and to other modules that's linked in.

.def        _main;  .scl    2;      .type   32;     .endef

Same thing as _main , creates debugging symbols stating that _main is a function. This can be used by debuggers.

_main:

Starts a new label(It'll end up an address). the .globl directive above makes this address visible to other entities.

pushl       %ebp

Saves the old frame pointer(ebp register) on the stack (so it can be put back in place when this function ends)

movl        %esp, %ebp

Moves the stack pointer to the ebp register. ebp is often called the frame pointer, it points at the top of the stack values within the current "frame"(function usually), (referring to variables on the stack via ebp can help debuggers)

andl $-16, %esp

Ands the stack with fffffff0 which effectivly aligns it on a 16 byte boundary. Access to aligned values on the stack are much faster than if they were unaligned. All these preceding instructions are pretty much a standard function prologue.

call        ___main

Calls the ___main function which will do initializing stuff that gcc needs. Call will push the current instruction pointer on the stack and jump to the address of ___main

movl        $0, %eax

move 0 to the eax register,(the 0 in return 0;) the eax register is used to hold function return values for the stdcall calling convention.

leave

The leave instruction is pretty much shorthand for

movl     ebp,esp
popl     ebp

i.e. it "undos" the stuff done at the start of the function - restoring the frame pointer and stack to its former state.

ret

Returns to whoever called this function. It'll pop the instruction pointer from the stack (which a corresponding call instruction will have placed there) and jump there.

这篇关于一个空的程序的GCC的汇编输出在x86,Win32的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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