Chinaunix首页 | 论坛 | 博客
  • 博客访问: 656665
  • 博文数量: 171
  • 博客积分: 2246
  • 博客等级: 大尉
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-31 11:45
文章分类

全部博文(171)

文章存档

2018年(3)

2017年(4)

2015年(1)

2014年(20)

2013年(57)

2012年(86)

分类: LINUX

2012-07-18 20:29:31


刚接触到C和汇编函数互相调用的例子,觉得很是神奇,灰常强大……感动得(谁叫咱是菜鸟)
C和汇编是两种编程语言,在语法上我觉得是差别很大的。个人认为,把它们联系起来的纽带是“C Calling Conversion”——C调用约定。下面是从书上看到的例子。
 
"foo.asm"文件代码:

点击(此处)折叠或打开

  1. extern choose ; int choose(int a, int b);
  2. [section .data] ;
  3. num1st dd 3
  4. num2nd dd 4
  5. [section .text] ;
  6. global _start
  7. global myprint
  8. _start:
  9. push dword [num2nd] ; `.
  10. push dword [num1st] ;  |
  11. call choose         ;  | choose(num1st, num2nd);
  12. add esp, 8          ; /
  13. mov ebx, 0
  14. mov eax, 1 ; sys_exit
  15. int 0x80 ;
  16. ; void myprint(char* msg, int len)
  17. myprint:
  18. mov edx, [esp + 8] ; len
  19. mov ecx, [esp + 4] ; msg
  20. mov ebx, 1
  21. mov eax, 4 ; sys_write
  22. int 0x80 ;
  23. ret

 
"bar.c" 文件内容:

点击(此处)折叠或打开

  1. void myprint(char* msg, int len);
  2. int choose(int a, int b)
  3. {
  4. if(a >= b){
  5. myprint("the 1st one\n", 13);
  6. }
  7. else{
  8. myprint("the 2nd one\n", 13);
  9. }
  10. return 0;
  11. }

 
由上可知:
1.由于在bar.c中用到函数myprint(),所以要在foo.asm中用关键字global将其导出。并且要一个地方(bar.c能引用到的地方)“声明”void myprint(char *msg, int len)这个函数,就像我们平时使用纯C一样,在主函数main()之外,我们可以自定义函数,方法也可以是先给出一个子函数的声明,例如
void func(int a,int b);接着在主函数后面写出它的具体实现,如:
void func()
{
   //something
}
    在C里面,一切我们都觉得很自然,因为子函数有了,调用起来也简单,func()需要什么参数,我们调用的时候直接“填”就行了,调用完程序继续执行,完全不用考虑堆栈之类的东西(系统自动配栈),所以的事情都符合逻辑。
    但是如果子函数或者说调用的函数是用汇编写的,情况就复杂了。函数符号要怎样识别,这里用了一个关键字“global”导出函数,这个还好理解,函数名我们可以认为是一个指针,一个地址,所以在哪里问题不大。我觉得最难理解的是“参数”。汇编里面是通过在call之前push 参数实现的,进入子程序后利用esp从堆栈中取得,在汇编程序调用中,堆栈非常重要,起传递参数的作用(当然,返回时也用到)。问题来了,在C中,我没有“push”,虽然我知道函数名,但是我怎样把参数传递给函数呢?正当我无限困惑时,上例的应用让我无比震惊,心理想,就这么简单,就这么随意就行了?!bar.c中“void myprint(char *msg, int len);”绝对是强大的。返回类型,参数类型,参数个数清清楚楚地给出了,咋一看,这不是C的子函数吗?堆栈,还是堆栈。虽然C里面不能push参数,但是根据C的调用约定,系统配栈时,会先后将 'len' 'msg'的地址入栈,效果和在汇编中的一样,这样一来在,C里面调用汇编里面的函数就没问题了。反过来,在汇编中调用C里面的函数也是一样的。要利用extern关键字导入,这个属于语法问题。个人认为,理解时要抓住三点:
     1.不管是在C还是汇编里,调用函数本质上是 call 一个地址,光这个操作和参数毫无关系;
     2.它们都遵循C调用约定(C Calling Conversion),后面的参数先入栈,并由调用者(caller)清理堆栈。
     3.参数是通过堆栈传递的,汇编里参数由编程者入栈,C里参数由系统配栈,编程者只需将参数放到函数参数表中。而当函数返回时,汇编里通过add esp+X 来清理堆栈,而在C里面,由于是系统配栈,当然系统也会自动清栈,对编程者来说,清理堆栈这一步就省了。
     好,继续学习…………
阅读(698) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~