GCC生成汇编文件解析

来源:互联网 发布:springboot 不打印sql 编辑:程序博客网 时间:2024/05/19 23:25
【示例代码1】
(1)C代码(test.c)
  1 #include <stdio.h>
  2
  3 void func()
  4 {
  5         return;
  6 }
  7
  8 int main(void)
  9 {
 10         return 0;
 11 }
 
(2)编译命令:gcc -S test.c

(3)汇编代码(test.s)
  1         .file   "test.c"
  2         .text

  3 .globl func
  4         .type   func, @function
  5 func:
  6         pushl   %ebp                       ;EBP寄存器压栈
  7         movl    %esp, %ebp             ;将ESP值赋给EBP
  8         popl    %ebp                       ;弹栈赋给EBP
  9         ret
 10         .size   func, .-func

 11 .globl main
 12         .type   main, @function
 13 main:
 14         leal    4(%esp), %ecx            ;ESP值加4赋给ECX
 15         andl    $-16, %esp               ;ESP末四位清零,目的是为了字节对齐
 16         pushl   -4(%ecx)                 ;将ECX-4值压栈(即ESP所指位置),这就是EIP
 17         pushl   %ebp                   ;EBP压栈,以便在函数退出时恢复EBP
 18         movl    %esp, %ebp             ;将ESP寄存器的值赋给EBP
 19         pushl   %ecx                   ;ECX值压栈,在函数退出时,通过此值恢复ESP
 20         movl    $0, %eax               ;函数返回值赋给EAX
 21         popl    %ecx                   ;ECX弹栈
 22         popl    %ebp                   ;EBP弹栈,恢复EBP
 23         leal    -4(%ecx), %esp         ;恢复ESP
 24         ret
 25         .size   main, .-main

 26         .ident  "GCC: (GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"
 27         .section        .note.GNU-stack,"",@progbits
 
(4)汇编代码详解
第1行,文件名称。
第2行,代码段标识符。
 
第3 - 4行,func函数标识。若该函数为static类型,则没有第三行声明。
第5行,func函数入口标识。
第6 - 9行,func函数主体。
第10行,func函数的代码段大小。
 
第11 - 12行,main函数标识。
第13行,main函数入口标识。
第14 - 24行,main函数主体部分。
第25行,main函数的代码段大小。
 
第26 - 27行,GCC编译器嵌入的标记。
 
 
【分析总结】
(1)一个代码段(函数)运行时使用的栈内存空间是连续的。EBP指向当前运行代码段的堆栈空间的第一个位置,也就是基地址;代码段在存取自身所使用的数据时使用EBP索引,在获取局部变量参数时使用ESP索引。
(2)ESP是栈顶指针,POP、PUSH会自动改变ESP的值;PUSH操作,先移动指针后向内存写数据;POP操作,先从读取内存数据后移动指针。
(3)堆栈是动态内存空间,在程序运行过程时,其中保持的主要内容有:局部变量(非静态变量),函数调用的现场保护数据(主要是相关寄存器的值)。
(4)在调用某函数时,必须先保存EBP寄存器的值,然后将EBP指向自己的真实地址;在退出函数执行时,必须恢复EBP的值,使调用者能够正常运行。
(5)函数的返回值,在默认的情况下,存放在EAX寄存器中。