由于有了上一节的铺垫,本节的内容相对较少,这里给大家准备了两个小文件来实例演示汇编语言和c语言相互调用。

会两种不同语言的人,只是掌握了同一件事物的两种表达方式。人在学习一种新语言时,潜意识里是建立了语言符号与事物形象的映射关系,比如我们在学习grape这个单词时,我们之所以认为它就是我们所认知的葡萄,是因为我们知道这两个名词都是在描述同一种圆圆的、黑紫色、甜酸的这一水果的形象,如果脑子中不存在这个形象的话,不光是学不会grape这个英文单词,就连中文的葡萄也不知道是何意。总之,对于具体的事物,一定是先有其形象,再有其描述,这样才能理解该事物,了解了事物的本质形象后,无论该事物的名字怎样变化,我们都能将它们相互转换。

也许有同学会问,以上这些所说的目的是什么?各位观众稍安勿燥,马上就要入戏啦^_^。

“汇编语言和C语言可以互相调用”,这句话并不是如表面陈述的那样,似乎是两种语言能直接交流,其实并不是这样。c语言和汇编语言完全是不同的东西,它们怎么能认识对方呢。这就像跟不懂汉语的人说汉语,那人听了肯定会晕头转向的,除非身边有个翻译帮忙转述,这个翻译所做的工作实质上是在脑子中找到这种语言所描述的事物形象,然后给出这种事物形象的另一种语言表达,这个事物形象才是翻译的核心。这有些类似上面提到的葡萄的例子,在同一种指令集上的各种计算机程序语言,最终也要编译为那些相同的机器码,这些机器码便是高级语言的本质形象。对于上面提到的翻译,在计算机世界里,就是编译器,只不过这个翻译是有多个,例如本书所说的c语言编译器gcc和汇编语言编译器nasm,它们能在一起配合,是因为它们都懂机器语言。举个例子,就像小明只会汉语和英语,小红只会汉语和法语,若他们之间在交流时,小明说英语,小红说法语,他俩相互都听不懂,所以,当说英文的小明想跟说法语的小红借作业时,他必须用汉语告诉小红。

编译器知道高级语言所描述的事物形象是机器码,所以各种编译在高级语言方面的交流,本质上都是将它们都变成统一的机器码后实现的。

吼吼,一不小心又说多了,不知道我表达清楚了没有,反正话题就此结束啦,小弟这里给各位看官准备了两个小文件:C_with_S_c.c和C_with_S_S.S。大家不用细看,快速浏览一下即可,在代码后面我还有话说呢

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_S.S

 1 section .data2 str: db "asm_print says hello world!", 0xa, 03 ;0xa是换行符,0是手工加上的字符串结束符\0的ascii码。4 str_len equ $-str56 section .text7 extern c_print8 global _start9 _start:10 ;;;;;;;;;;;; 调用c代码中的函数c_print ;;;;;;;;;;;11 push str ;传入参数12 call c_print ;调用c函数13 add esp,4 ;回收栈空间1415 ;;;;;;;;;;;;;;;;;;; 退出程序 ;;;;;;;;;;;;;;;;;;;;16 mov eax,1 ;第1号子功能是exit系统调用17 int 0x80 ;发起中断,通知linux完成请求的功能。1819 global asm_print ;相当于asm_print(str,size)20 asm_print:21 push ebp ;备份ebp22 mov ebp,esp23 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 ;恢复ebp29 ret

代码C_with_S_c.c中的函数c_print是被汇编代码C_with_S_S.S调用的,在c_print的实现中,它又调用汇编代码中的asm_print。它们的关系如图

下节再解释代码,先去吃饭了。

接上节,前文请见“一步步编写操作系统 69 汇编语言和c语言共同协作”,

本节是对前文的代码说明,代码再贴过来,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 .data2 str: db "asm_print says hello world!", 0xa, 03 ;0xa是换行符,0是手工加上的字符串结束符的ascii码。4 str_len equ $-str56 section .text7 extern c_print8 global _start9 _start:10 ;;;;;;;;;;;; 调用c代码中的函数c_print ;;;;;;;;;;;11 push str ;传入参数12 call c_print ;调用c函数13 add esp,4 ;回收栈空间1415 ;;;;;;;;;;;;;;;;;;; 退出程序 ;;;;;;;;;;;;;;;;;;;;16 mov eax,1 ;第1号子功能是exit系统调用17 int 0x80 ;发起中断,通知linux完成请求的功能。1819 global asm_print ;相当于asm_print(str,size)20 asm_print:21 push ebp ;备份ebp22 mov ebp,esp23 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 ;恢复ebp29 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声明即可。

好了,大爷再来玩哦。

一步步编写操作系统 69 汇编语言和c语言共同协作 70相关推荐

  1. 一步步编写操作系统 43 汇编语言和c语言的理解

    也许有的同学喜欢用汇编语言来实现操作系统,觉得用汇编来写程序似乎更简单直接,可控性比较强,有种"一切尽在掌握"的赶脚.而用c语言实现操作系统这件事,虽然轻松很多,但似乎隐约感觉到有 ...

  2. 软件工程:汇编语言和C语言在软件工程的应用,计算机学生必看!

    随着科学技术不断发展,软件工程在社会发展中取得了进一步发展,软件工程专业,也在各大学生根发芽,许多大学的专业教学上也取得了良好的进展.汇编语言与C语言作为两种计算机基础语言,在推动软件工程发展等方面具 ...

  3. 汇编语言属于C语言吧,汇编语言和c语言的区别是什么

    区别:汇编语言的效率高,对硬件的可操控性更强,体积小,不易维护,可移植性很差:c语言的效率比较低,硬件可操控性比较差,目标代码体积大,容易维护,可移植性很好. 汇编语言(Assembly Langua ...

  4. 汇编语言和C语言编写程序各有什么优缺点,C语言和汇编语言在单片机开发中,各有什么优缺点?...

    您好,下面这个是我从论坛里面找出来的精华帖.你可以参考参考. C与汇编: C:经编译后,成汇编. 汇编:是自己"完成"了C的工作. C:是从通用化出发的,考虑了单片机的特点,极大地 ...

  5. 一步步编写操作系统 66 浅析c库函数与系统调用1

    本来说好的接下来的工作是要去"丰满"我们的内核,可咱们这种一步一回头的学习方式还得继续啊.其实我了解大家急切写内核的心情,但本书<操作系统真象还原>(请大家支持正版)的 ...

  6. 一步步编写操作系统 71 直接操作显卡,编写自己的打印函数71-74

    一直以来,我们在往屏幕上输出文本时,要么利用bios中断,要么利用系统调用,这些都是依赖别人的方法.咱们还用过一个稍微有点独立的方法,就是直接写显存,但这貌似又没什么含量.如今我们要写一个打印函数了, ...

  7. 一步步编写操作系统 62 函数调用约定

    由于我们要将c语言和汇编语言结合编程啦,所以一定会存在汇编代码和c代码相互调用的问题,有些事情还是要提前交待给大家的,本节就是要给大家说下函数调用规约中的那些事儿. 函数调用约定是什么? 调用约定,c ...

  8. 一步步编写操作系统 2 部署工作环境 2

    1.22汇编语言编译器新贵,NASM "新"是相对于旧来说的,老的汇编器MASM和TASM已经过时了,从名称上可以看出字母n是在m之后,其功能必然有所超越才会被大家接受. 请用一句 ...

  9. c++和java哪个好学_【技术科普】C语言和java语言有些什么区别?

    C语言和java语言有些什么区别? 可以打个比方吧: C语言就像一个初创公司的老板,由于人少经费少,从技术.财务.市场等都需要自己管,经常把自己累的跟狗一样: Java语言就像一个上市大公司的老板,人 ...

最新文章

  1. Paint滤镜效果实现
  2. ​基于BCI的现代神经反馈有助于认知增强
  3. 动态CSS - LESS学习总结
  4. c2000 pro 固件更新_一加7Pro系统更新新增屏幕侧滑返回手势
  5. 【AtCoder】ARC095 E - Symmetric Grid 模拟
  6. 创建自己的Java批注
  7. MyBatis #{ } ${ }
  8. 计算机一直黑屏,电脑开不了机 一直黑屏 电源灯亮着 在线等
  9. SteamVR简介(Yanlz+Steam+VR+Unity+AR+MR+XR+立钻哥哥+==)
  10. UopenCryptionKit4Java:一个好用的轻量开源加解密器工具包
  11. 二进制转十六进制(参考XYJ)
  12. flac转换mp3格式使用什么软件好
  13. SpringBoot笔记系列:(十)数据持久化Spring Data JPA
  14. python简易爬虫获取A股上证所有股票历史数据
  15. python:shape和reshape()函数
  16. 如何选择适合你的兴趣爱好(五十一),喝茶
  17. 乔布斯对于flash的看法
  18. centos下sqlite3安装
  19. 护理方面关于人工智能的构想_谷歌秘密的atap实验室正在构想智能设备的未来...
  20. 【报错记录】Un-Routed Net Constraint

热门文章

  1. hadoop中map和reduce的数量设置问题
  2. Memory及其controller芯片整体测试方案(上篇)
  3. Mybatis基于XML配置SQL映射器(一)
  4. spring depends-on 不起作用
  5. 产品专家Marty Cagan:不做仅仅会编码的人
  6. Webx框架:Pipeline基本介绍
  7. Android学习(二十)Notification通知栏
  8. oracle 的进程
  9. 在.net 2.0 中执行分布式事务:隐式事务篇(SQL Server 与 Oracle)
  10. leetcode之回溯backtracing专题2