Chinaunix首页 | 论坛 | 博客
  • 博客访问: 196430
  • 博文数量: 26
  • 博客积分: 1121
  • 博客等级: 少尉
  • 技术积分: 499
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-12 14:24
文章分类
文章存档

2011年(3)

2010年(10)

2009年(13)

我的朋友

分类: C/C++

2010-09-29 13:54:49


【示例代码1】
(1)C代码(test.c)
  1 #include
  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寄存器中。
 
阅读(6895) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~