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

由于有了上一节的铺垫,本节的内容相对较少,这里给大家准备了两个小文件来实例演示汇编语言和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声明即可。

好了,大爷再来玩哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439536.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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

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

【CodeForces - 208C 】Police Station(单源最短路条数,起点终点建图,枚举顶点)

题干&#xff1a; The Berland road network consists of n cities and of m bidirectional roads. The cities are numbered from 1 to n, where the main capital city has number n, and the culture capital — number 1. The road network is set up so that it is possi…

【Chrome浏览器】常用快捷键整理

标签页和窗口快捷键 1. Ctrl n 打开新窗口 2. Ctrl t 打开新的标签页&#xff0c;并跳转到该标签页 3. Ctrl Shift t 重新打开最后关闭的标签页&#xff0c;并跳转到该标签页 4. Ctrl Tab 跳转到下一个打开的标签页 5. Ctrl Shift Tab 跳转到上一个打开的标签页 6.…

【人工智能课程实验】 - 利用贝叶斯分类器实现手写数字 的识别

读入数据与预处理 因为老师给的文件无法直接读取&#xff0c;故从官网导入数据&#xff1a; 官网链接&#xff1a;http://www.cs.nyu.edu/~roweis/data.html 导入数据之后要对MATLAB文件进行读入&#xff1a; datasio.loadmat(trainfile) 对文件type一下&#xff1a; ty…

一步步编写操作系统 77 内联汇编与ATT语法简介

内联汇编 之前和大家介绍过了一种汇编方法&#xff0c;就是C代码和汇编代码分别编译&#xff0c;最后通过链接的方式结合在一起形成可执行文件。 另一种方式就是在C代码中直接嵌入汇编语言&#xff0c;强大的GCC无所不能&#xff0c;咱们本节要学习的就是这一种&#xff0c;它…

【Python学习】内置函数(不断更新)

关于常用在for循环中的range函数 python range() 函数可创建一个整数列表&#xff0c;一般用在 for 循环中。 函数语法 range(start, stop[, step]) 参数说明&#xff1a; start: 计数从 start 开始。默认是从 0 开始。例如range&#xff08;5&#xff09;等价于range&#…

【Python学习】 简单语法与常见错误(持续更新)

关于单引号和双引号 当输出的字符串内部没有单引号的时候&#xff0c;外面可以用单引号&#xff0c; 但是如果内部有了单引号&#xff0c;那么外部只能用双引号。 dict {Name: Zara, Age: 7, Class: First} print(dict) print (dict[Name]: , dict[Name]) print ("dic…

一步步编写操作系统 78 intel汇编与ATT汇编语法区别

本节咱们介绍下intel汇编语法和at&t汇编语法的区别。 以上表中未列出这两种语法在内存寻址方面的差异&#xff0c;个人觉得区别还是很大的&#xff0c;下面单独说说。 在Intel语法中&#xff0c;立即数就是普通的数字&#xff0c;如果让立即数成为内存地址&#xff0c;需要…

重读经典:《Masked Autoencoders Are Scalable Vision Learners》

MAE 论文逐段精读【论文精读】这一次李沐博士给大家精读的论文是 MAE&#xff0c;这是一篇比较新的文章&#xff0c;2021年11月11日才上传到 arXiv。这篇文章在知乎上的讨论贴已经超过了一百万个 view&#xff0c;但是在英文社区&#xff0c;大家反应比较平淡一点&#xff0c;R…

【Python学习日志】 - Numpy包

NumPy是什么&#xff1f; 使用Python进行科学计算的基础包&#xff0c;在数据分析的时候比较常用到矩阵计算。这时太多的Np属性不记得&#xff0c;所以方便自己使用把一些常用的Np属性汇总记录一下使用的时候方便查找。 ndarray.ndim 阵列的轴数&#xff08;尺寸&#xff09;…

详解协同感知数据集OPV2V: An Open Benchmark Dataset and Fusion Pipeline for Perception with V2V Communication

在《详解自动驾驶仿真框架OpenCDA: An Open Cooperative Driving Automation Framework Integrated with Co-Simulation》 一文中介绍了自动驾驶仿真框架 OpenCDA。本文将介绍论文作者另一篇最新工作 OPV2V&#xff0c;论文收录于 ICRA2022。 OPV2V 数据集主要 feature 有&…

【Python学习】 - 如何在Spyder中弹出plot绘图窗口而不是在Console中绘图

依次选择这几项&#xff1a; 点击ok确认。 注意&#xff1a;点击ok之后不会立即生效&#xff0c;重启Spyder之后才会生效

mysql系列:加深对脏读、脏写、可重复读、幻读的理解

关于相关术语的专业解释&#xff0c;请自行百度了解&#xff0c;本文皆本人自己结合参考书和自己的理解所做的阐述&#xff0c;如有不严谨之处&#xff0c;还请多多指教。 **不可重复读的重点是修改: **同一事务&#xff0c;两次读取到的数据不一样。 幻读的重点在于新增或者…

重读经典(点云深度学习开山之作):《Deep learning on point clouds for 3D scene understanding》(持续更新中)

本文介绍的是 PointNet 作者的博士论文&#xff1a;3D场景理解中的点云深度学习。从上图可以看到&#xff0c;整个博士论文主要贡献有两块&#xff1a;一是点云深度学习的网络架构&#xff08;PointNet 和 PointNet&#xff09;&#xff1b;二是在3D场景理解中的应用&#xff0…

Coursera自动驾驶课程第17讲:An Autonomous Vehicle State Estimator

在第16讲《Coursera自动驾驶课程第16讲&#xff1a;LIDAR Sensing》我们学习了自动驾驶目前常用的3D 传感器&#xff0c;激光雷达&#xff0c;了解了激光雷达的工作原理&#xff0c;掌握了对点云数据的操作以及如何使用点云配准方法来进行汽车定位。 回顾一下&#xff0c;在本…

!何为脏读、不可重复读、幻读

2.0、前言 事务的隔离性是指多个事务并发执行的时候相互之间不受到彼此的干扰的特性&#xff0c;隔离性是事务ACID特性中的I&#xff0c;根据隔离程度从低到高分为Read Uncommitted&#xff08;读未提交&#xff09;&#xff0c;Read Committed&#xff08;读已提交&#xff0…

【转】JPA、Hibernate和Mybatis区别和总结

很多人都用过java的数据库连接池C3P0&#xff0c;但官方没有说明名称的由来。 据传闻&#xff1a;连接池作者是《星球大战》迷&#xff0c;C3P0就是其中的一个机器人&#xff0c;并且这个名称中包涵connection 和pool的单词字母。因此叫这个名字&#xff08;根据网友提醒&…

详解3D物体检测模型: Voxel Transformer for 3D Object Detection

本文介绍一个新的的3D物体检测模型&#xff1a;VoTr&#xff0c;论文已收录于ICCV 2021。 这是第一篇使用 voxel-based Transformer 做3D 主干网络&#xff0c;用于点云数据3D物体检测。由于有限的感受野&#xff0c;传统的 3D 卷积网络检测器&#xff08;voxel-based&#xff…

一步步编写操作系统 65 标准调用约定stdcall 汇编实战

因为c语言遵循的调用约定是cdecl&#xff0c;咱们也自然要遵守cdecl约定了。不过为了起到对比的作用&#xff0c;除了介绍cdecl外&#xff0c;也会介绍下stdcall。 既然咱们用的是调用约定是cdecl&#xff0c;那对它的介绍最好让它离下一节的内容近一些&#xff0c;所以先说一…

Coursera自动驾驶课程第18讲:The Planning Problem

在第17讲《Coursera自动驾驶课程第17讲&#xff1a;An Autonomous Vehicle State Estimator》 我们学习了如何使用多传感器融合进行自车定位&#xff0c;以及传感器的内外参标定和时间同步&#xff0c;我们还讨论了在实际应用中常遇到的问题。 从本讲开始我们将学习一个新的模…