×
嵌入式 > 技术百科 > 详情

汇编技术内幕(1)

发布时间:2020-06-13 发布时间:
|
最简单C代码分析
为简化问题,来分析一下最简的c代码生成的汇编代码:

    # vi test1.c
     int main()
    {
        return 0;
    
   
    编译该程序,产生二进制文件:
    # gcc test1.c -o test1
    # file test1 
    test1: ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not stripped
    test1是一个ELF格式32位小端(Little Endian)的可执行文件,动态链接并且符号表没有去除。
    这正是Unix/Linux平台典型的可执行文件格式。

    用mdb反汇编可以观察生成的汇编代码:
    # mdb test1
    Loading modules: [ libc.so.1 ]
    > main::dis       ; 反汇编main函数,mdb的命令一般格式为  ::dis
main:          pushl   %ebp;ebp寄存器内容压栈,即保存main函数的上级调用函数的栈基地址
main+1:        movl    %esp,%ebp  ; esp值赋给ebp,设置main函数的栈基址main+3:        subl    $8,%esp
main+6:        andl    $0xf0,%esp
main+9:        movl    $0,%eax
main+0xe:      subl    %eax,%esp
main+0x10:     movl    $0,%eax    ; 设置函数返回值0
main+0x15: leave; 将ebp值赋给esp,pop先前栈内的上级函数栈的基地址给ebp,恢复原栈基址
main+0x16:     ret                ; main函数返回,回到上级调用
    
    注:这里得到的汇编语言语法格式与Intel的手册有很大不同,Unix/Linux采用AT&T汇编格式作为汇编语言的语法格式

   问题:谁调用了 main函数?
   在C语言的层面来看,main函数是一个程序的起始入口点,而实际上,ELF可执行文件的入口点并不是main而是_start。
   mdb也可以反汇编_start:
    > _start::dis                       ;从_start 的地址开始反汇编
    _start:              pushl   $0
    _start+2:            pushl   $0
    _start+4:            movl    %esp,%ebp
    _start+6:            pushl   %edx
    _start+7:            movl    $0x80504b0,%eax
    _start+0xc:          testl   %eax,%eax
    _start+0xe:          je      +0xf            <_start>
    _start+0x10:         pushl   $0x80504b0
    _start+0x15:         call    -0x75          
    _start+0x1a:         addl    $4,%esp
    _start+0x1d:         movl    $0x8060710,%eax
    _start+0x22:         testl   %eax,%eax
    _start+0x24:         je      +7              <_start>
    _start+0x26:         call    -0x86          
    _start+0x2b:         pushl   $0x80506cd
    _start+0x30:         call    -0x90          
    _start+0x35:         movl    +8(%ebp),%eax
    _start+0x38:         leal    +0x10(%ebp,%eax,4),%edx
    _start+0x3c:         movl    %edx,0x8060804
    _start+0x42:         andl    $0xf0,%esp
    _start+0x45:         subl    $4,%esp
    _start+0x48:         pushl   %edx
    _start+0x49:         leal    +0xc(%ebp),%edx
    _start+0x4c:         pushl   %edx
    _start+0x4d:         pushl   %eax
    _start+0x4e:         call    +0x152          <_init>
    _start+0x53:         call    -0xa3           <__fpstart>
    _start+0x58:         call    +0xfb       
              ;在这里调用了main函数
    _start+0x5d:         addl    $0xc,%esp
    _start+0x60:         pushl   %eax
    _start+0x61:         call    -0xa1          
    _start+0x66:         pushl   $0
    _start+0x68:         movl    $1,%eax
    _start+0x6d:         lcall   $7,$0
    _start+0x74:         hlt
 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
中国国产第三代核电实现并网发电