1.简介
本文介绍在c代码中嵌入汇编语言的方法,所有的方法仅对gcc(Gnu C Compiler)有效。由于作者是在一台pc上进行的实验,所以例子中如果未加说明,所有的汇编代码均为x86汇编。本文的唯一参考资料就是gcc Manual,其中的5.36小节介绍了在c中嵌入汇编的办法。
2.如何在c中嵌入汇编代码
2.1.最简单的情形
在gcc里有一个asm表达式,用于实现嵌入汇编。就像这样
asm("xor %%eax, %%eax");
这个汇编指令的作用是吧eax寄存器清零,你也许注意到这些代码和我们常见的x86汇编代码有些不同,的确,gcc使用的汇编格式是AT&T格式而不是DOS下常见的Intel格式,它们之间主要区别有:AT&T格式的寄存器使用%标志开头,例如Intel格式中的EAX在这里写作%eax;AT&T格式的目的操作数是后一个而不像Intel格式那样是前一个,比如:
asm("movl %%eax, %%ebx");
是将eax寄存器的值移到ebx。另外还有一些区别,比如内存地址的表示方法等等,详情可以参考DJGPP FAQ里的Coverting between Intel ASM syntax and AT&T syntax。
另外还要注意%号在asm表达式里是特殊字符,所以%eax前面要再加一个%号进行转义,这样就成了"%%eax"这样的寄存器表示方法,如果你用的是Sparc之类的cpu,寄存器使用"r1""r5"之类的表达式,就不需要累赘的%号了。
为了比较易读,多行的汇编代码可以写成这样
asm("xor %%eax, %%eax
movl -20(%%ebp), %%ebx
sub %%ebx, %%eax");
不过在最新的gcc-3系列里一个字符串写了一行以上是会引发一个warning的,让人看了不舒服,这样写就不会了:
asm("xor %%eax, %%eax \n\t"
"movl -20(%%ebp), %%ebx \n\t"
"sub %%ebx, %%eax");
\n就是换行,\t是tab对齐,这下明白了吧 :)
2.2.使用c中定义的变量
先给出一个例子:
int foo;
asm("movl %%eax, %0"
: "=g" (foo));
在asm()中,在冒号分隔符后面声明你的变量,括号中是变量名(foo),"=g"表示这是一个作为输出的整型变量,如果变量是作为输入的话,就要放在第二个括号分隔符后面,象这样:
int foo1,foo2;
asm("movl %1, %%eax \n\t"
"movl %%eax, %0"
: "=g" (foo1)
: "g" (foo2));
程序是把foo2的内容赋给foo1。从这个例子可以看到,变量在汇编语言里被引用的时候表示符是该变量在asm()里被声明的位置,foo1在asm()里首先声明,所以是%0,foo2紧接着所以是%1。"g"表示是一个整型,前面有"="号说明这是一个作为输出的变量(也就是被写的),没有"="号就说明是作为输入的变量。别的被支持的类型还有"r"(寄存器变量),"m"(内存变量),"f"(浮点变量)等等,更多的表示可以参考gcc manual 20.7.1 。
2.3.避免寄存器冲突
如果你在汇编中显式的使用寄存器,编译器会注意不会在上下文中造成冲突,但是有一些指令是不会显式的使用寄存器的,例如cpuid这条指令,它运行以后会改变%eax,%ebx,%ecx,%edx的值,但是这些寄存器不会在代码里出现,因此编译器不会为你避开这个冲突,如果你直接调用这个指令,可能就会造成你的代码core dump!一个笨笨的办法是自己保护寄存器,调用cpuid之前先将四个寄存器push到栈里,运行了cpuid之后将值保存,再pop这四个寄存器。当然这样很影响代码的效率。其实解决的办法很简单,在asm()的第三个冒号后面声明那些需要保护的寄存器就可以了,像这样:
asm("cpuid"
:
:
:"%eax","%ebx","%ecx","%edx");
注意在这里一个"%"号就好了,这样编译器就会小心的避开这些寄存器的冲突
分享到:
相关推荐
基本输入输出系统(BIOS)是嵌入在计算机主板ROM中的程序,它在开机时执行POST(Power On Self Test)以检查硬件的完整性。POST完成后,BIOS会从预设的启动设备(如硬盘、光驱或软盘)读取启动扇区(通常是主引导...
1.赵炯博士已经将汇编程序中引用的C变量(包括嵌入汇编的C变量)的下划线去掉了,但MinGW的gcc可能是为了与其它Windows下的编译器保持兼容,并不能识别这些不带下划线的C变量,因而还得把原先已经在汇编程序中去掉下划线...
1.赵炯博士已经将汇编程序中引用的C变量(包括嵌入汇编的C变量)的下划线去掉了,但MinGW的gcc可能是为了与其它Windows下的编译器保持兼容,并不能识别这些不带下划线的C变量,因而还得把原先已经在汇编程序中去掉下划线...
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
wrf转mp4播放器1.1.1
内容概要:本文档详细介绍了如何在Simulink中设计一个满足特定规格的音频带ADC(模数转换器)。首先选择了三阶单环多位量化Σ-Δ调制器作为设计方案,因为这种结构能在音频带宽内提供高噪声整形效果,并且多位量化可以降低量化噪声。接着,文档展示了具体的Simulink建模步骤,包括创建模型、添加各个组件如积分器、量化器、DAC反馈以及连接它们。此外,还进行了参数设计与计算,特别是过采样率和信噪比的估算,并引入了动态元件匹配技术来减少DAC的非线性误差。性能验证部分则通过理想和非理想的仿真实验评估了系统的稳定性和各项指标,最终证明所设计的ADC能够达到预期的技术标准。 适用人群:电子工程专业学生、从事数据转换器研究或开发的技术人员。 使用场景及目标:适用于希望深入了解Σ-Δ调制器的工作原理及其在音频带ADC应用中的具体实现方法的人群。目标是掌握如何利用MATLAB/Simulink工具进行复杂电路的设计与仿真。 其他说明:文中提供了详细的Matlab代码片段用于指导读者完成整个设计流程,同时附带了一些辅助函数帮助分析仿真结果。
国网台区终端最新规范
《基于YOLOv8的智慧农业水肥一体化控制系统》(包含源码、可视化界面、完整数据集、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计
GSDML-V2.33-LEUZE-AMS3048i-20170622.xml
微信小程序项目课程设计,包含LW+ppt
微信小程序项目课程设计,包含LW+ppt
终端运行进度条脚本
幼儿园预防肺结核教育培训课件资料
python,python相关资源
《基于YOLOv8的智慧校园电动车充电桩状态监测系统》(包含源码、可视化界面、完整数据集、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计
deepseek 临床之理性软肋.pdf
SM2258XT量产工具(包含16种程序),固态硬盘量产工具使用
RecyclerView.zip
水务大脑让水务运营更智能(23页)
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。