我试图通过示例学习汇编语言,或者使用-S选项,英特尔语法和CFI调用禁用GCC编译简单的C文件(每隔一个免费方式都非常混乱
我的C文件实际上只是int main() {return 0;}
,但是GCC吐出了这个:
.file "simpleCTest.c"
.intel_syntax noprefix
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
push ebp
mov ebp, esp
and esp, -16
call ___main
mov eax, 0
leave
ret
.ident "GCC: (GNU) 5.3.0"
我真正的问题是为什么main函数有任何处理器指令(push edp
,mov edp, esp
等)?这些甚至是必要的(我想这将是一种准备/关闭程序的数据管理方式,但我不确定)?为什么它只是在主函数之后发出ret
语句?另外为什么有两个主要功能(_main& ___ main)?
总结一下,为什么不是这样呢?
.def _main
_main:
mov eax, 0 ;(for return integer)
ret
答案 0 :(得分:0)
海湾合作委员会吐出这个
如果您确实让主函数做了一些事情,奇怪的是,包括调用另一个函数,这可能会更清楚一些。
您编译的代码正在设置一个框架,通过该框架可以使用第一个操作码mov ebp,esp来引用其堆栈变量。例如,如果你有可以用ebp引用的变量和常量,那么就可以使用它。然后,它使用AND指令将堆栈对齐到16个字节的倍数 - 也就是说,它表示它不会使用所提供堆栈的0到15个字节,这样[esp]对齐到16的倍数字节。由于使用的调用约定,这很重要。
结束操作码将备份的基指针复制到堆栈指针的当前状态,然后用pop恢复原始基本指针。
我真正的问题是为什么main函数有任何处理器指令
它为你不做的事情设置了东西(但那些重要的程序会这样做),并没有做出最优化的"返回0"程序,它可以。通过使一个基本指针主要是原始堆栈指针的备份,程序可以自由地将局部变量称为偏移量加上基本指针(包括你不使用的隐含的东西,如参数计数,指针指向参数列表的指针和指向环境的指针,并且通过具有16的倍数的堆栈指针,程序可以根据其调用标准自由地调用函数。