分享

一步步编写操作系统 70 汇编语言和c语言共同协作2

 山峰云绕 2019-07-13

本节是对前文的代码说明,代码再贴过来,C_with_S_c.c如下:

1 extern void asm_print(char*,int); 2 void c_print(char* str) { 3 int len=0; 4 while(str[len++]); 5 asm_print(str, len); 6 }

代码C_with_S_c.c的第1行是声明外部函数asm_print,通知编译器这个函数并不在当前文件中定义。我们知道它定义在文件C_with_S_S.S中,但编译器是不知道的,所以只能在链接阶段将此函数重新定位,编排地址。

第2~6行是c_print的实现,在它的内部,它又调用了汇编代码C_with_S_S.S中的函数asm_print,经过第1行的声明,我们要给它提供两个参数:字符串的起始地址及长度。

特别强调一下,由于这里并不打算把c标准库也链接进来,所以在求字符串长度时,我们不能用string.h中的strlen函数。也就是说即使include <string.h>将其strlen的声明加进来,没有strlen实现本身所在的.o文件也是不行的。函数声明的作用是:一方面是告诉编译器该函数的参数所需要的栈空间大小及返回值,这样编译器能为其准备好执行环境,另一方面是如果该函数是在外部文件中定义的,一定要在链接阶段时将其对应的目标文件一块链接进来。所以这里第3~4行通过while循环求字符串的长度。字符串结尾必须是空字符’\0’才行,否则while就是死循环了。这个字符串是代码C_with_S_S.S提供的,我们转过去看看。

 1 section .data 2 str: db 'asm_print says hello world!', 0xa, 0 3 ;0xa是换行符,0是手工加上的字符串结束符的ascii码。 4 str_len equ $-str 5 6 section .text 7 extern c_print 8 global _start 9 _start: 10 ;;;;;;;;;;;; 调用c代码中的函数c_print ;;;;;;;;;;; 11 push str ;传入参数 12 call c_print ;调用c函数 13 add esp,4 ;回收栈空间 14 15 ;;;;;;;;;;;;;;;;;;; 退出程序 ;;;;;;;;;;;;;;;;;;;; 16 mov eax,1 ;第1号子功能是exit系统调用 17 int 0x80 ;发起中断,通知linux完成请求的功能。 18 19 global asm_print ;相当于asm_print(str,size) 20 asm_print: 21 push ebp ;备份ebp 22 mov ebp,esp 23 mov eax,4 ;第4号子功能是write系统调用 24 mov ebx, 1 ;此项固定为文件描述符1,标准输出(stdout)指向屏幕 25 mov ecx, [ebp+8] ;第1个参数 26 mov edx, [ebp+12] ;第2个参数 27 int 0x80 ;发起中断,通知linux完成请求的功能。 28 pop ebp ;恢复ebp 29 ret

在代码C_with_S_S.S的第2行,定义待打印的字符串时,在结尾人为的加了个0,它就是空字符’\0’的ascii码。

第8~9行是将_start导出为全局符号,为的是给链接器用的,之前解释过了。

为了在汇编文件中引用外部的函数(未必是c代码中的),需要用extern来声明所需要的函数名。

由于我们用到了外部的函数c_print,所以在第7行用extern c_print来声明c_print函数是外部的。第11~13行是为外部函数c_print压栈传参,调用它后清理栈空间。

第16~17行是调用exit系统调用告诉linux我要正常退出。

在汇编语言中导出符号名是用global关键字,这在之前说_start时大伙已有所耳闻,global是将符号导出为全局属性,对程序中的所有文件可见,这样其它外部文件中也可以引用被global导出的符号啦,无论该符号是函数还是变量。

由于在c代码文件C_with_S_c.c中也调用了这里的asm_print函数,所以为了让外部代码可以引用asm_print。我们在第19行用global asm_print将其导出。

第20行之后是asm_print的实现,相信大家已经非常明白了,不解释。

好啦,通过这两个例子我相信大伙儿已经掌握c和汇编混合编程的方法啦,确切说是方法之一。对于这种汇编代码和C代码单独编译的方式还是较容易的,以后咱们会讲C内联汇编的方式难为难为大家的,玩笑玩笑,只要用心没有学不会的(听上去似乎觉得更难了^_^,没事没事)。

有关混合编程的部分就说完了,总结一下:

  • 在汇编代码中导出符号供外部引用是用关键字global,引用外部文件的符号是用关键字extern。

  • 在C代码中只要将符号定义为全局便可以被外部引用(一般情况下无须用额外关键字修饰,具体请参考c语言手册),引用外部符号时用extern声明即可。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多