09. C语言内嵌汇编代码

news2024/11/17 17:34:24


C语言函数内可以自定义一段汇编代码,在GCC编译器中使用 asm 或 __asm__ 关键词定义一段汇编代码,并可选添加volatile关键字,表示不要让编译器优化这段汇编代码。

内嵌汇编代码格式如下:

__asm__
(
    "汇编代码"
    :输出描述
    :输入描述
    :修改描述
);


汇编代码部分

汇编代码部分是一个字符串,嵌入的汇编代码使用此字符串存储,多条汇编代码之间使用;符号隔开,字符串可以换行存储,换行存储方式如下:

__asm__
(
    "mov eax,ecx; \
    add eax,ebx;"
);

或者:

__asm__
(
    "mov eax,ecx;"
    "add eax,ebx;"
);

注:
1.汇编代码中16进制数据只能使用0x前缀,不能使用h后缀。
2.指定内存数据长度时,使用 word prt 关键词,不能省略 prt。
3.内嵌汇编代码默认使用AT&T语法,若使用inter语法则需要在编译时添加如下参数:-masm=intel,本文使用inter汇编语法。


输出描述部分

若汇编代码执行完毕后需要将寄存器、内存单元中的数据保存在C语言代码定义的局部变量中,则需要在输出描述部分定义寄存器或内存单元与局部变量的绑定关系,绑定代码格式如下:

#include <stdio.h>
int main()
{
    int i;

    __asm__
    (
        "mov eax,1; \
        mov ebx,2; \
        add eax,ebx;"
        
        :"=a"(i)          //输出描述部分,"=a"表示输出eax寄存器,(i)表示使用变量i接收输出数据
    );
    
    printf("%d\n", i);
    return 0;
}


输出描述部分使用简写代码表示要输出的寄存器或内存单元,常用代码如下:
a,表示ax系寄存器
b,表示bx系寄存器
c,表示cx系寄存器
d,表示dx系寄存器
S,表示si系寄存器
D,表示di系寄存器
r,表示自动分配的寄存器
m,表示自动分配的内存单元
g,表示自动分配的寄存器或内存单元


绑定的局部变量可以使用指针指定。

#include <stdio.h>
int main()
{
    int i;
    int *p1 = &i;
    
    __asm__
    (
        "mov eax,1; \
        mov ebx,2; \
        add eax,ebx;"
        
        :"=a"(*p1)
    );
    
    printf("%d\n", i);
    return 0;
}


输入描述部分

输入描述用于将局部变量与指定的寄存器或内存单元绑定,绑定的变量会首先复制到对应的寄存器或内存单元,然后再执行汇编代码。

#include <stdio.h>
int main()
{
    int i1, i2, i3;
    
    printf("输入两个整数\n");
    scanf("%d%d", &i1, &i2);
    
    __asm__
    (
        "add eax,ebx;"
        
        :"=a"(i3)            //输出描述部分,eax写入i3
        
        :"a"(i1), "b"(i2)    //输入描述部分,i1写入eax,i2写入ebx
    );
    
    printf("两数相加结果为:%d\n", i3);
    return 0;
}


修改描述部分

修改描述用于告知编译器哪些寄存器、内存单元被汇编代码修改过,让编译器在编译代码时对这些寄存器或内存单元进行保护,当然我们也可以手动进行保护,在使用寄存器之前首先将其入栈存储,在汇编代码末尾处还原寄存器。

修改描述注意事项:
1.若被修改的寄存器在输出描述、输入描述中记录过,则无需在修改描述中重复指定,编译器会自动处理。
2.若修改了内存单元,则应该在此部分定义"memory"。
3.若修改了标志寄存器,则应该在此部分定义"c"。

#include <stdio.h>
int main()
{
	int i1, i2, i3;
	
	printf("输入两个整数\n");
	scanf("%d%d", &i1, &i2);
	
	__asm__
	(
		"add eax,ebx; \
		mov edx,3; \
		imul ecx,edx"        //ecx与edx相乘仅做示例,没有实际作用
		
		:"=a"(i3)            //输出描述部分,eax写入i3
		
		:"a"(i1), "b"(i2)    //输入描述部分,i1写入eax,i2写入ebx
		
		:"ecx", "edx"        //修改描述部分,告知编译器ecx、edx被修改过,并且没有在输入输出描述中记录
	);
	
	printf("两数相加结果为:%d\n", i3);
	return 0;
}


编译器自动分配寄存器、内存单元

在汇编代码中存储数据时可以让编译器自动分配寄存器或内存,汇编代码使用“%数字”的方式调用编译器自动分配的寄存器或内存,比如:%0、%1、%2,这些名称称为占位符,占位符可以不按顺序定义。

占位符可以与输入输出描述中的局部变量绑定,绑定顺序为局部变量在输入输出描述中出现的顺序,%0绑定第一个变量、%1第二个、%2第三个。

#include <stdio.h>
int main()
{
    int i1, i2, i3;
    
    printf("输入两个整数\n");
    scanf("%d%d", &i1, &i2);
    
    __asm__
    (
        "add %1,%2; \
        mov %0,%1"
        
        :"=m"(i3)            //输出描述部分,%0写入i3,这里使用m,表示让编译器自动分配内存单元存储绑定的i3
        
        :"r"(i1), "r"(i2)    //输入描述部分,i1写入%1,i2写入%2,这里使用r,表示让编译器自动分配寄存器存储绑定的i1、i2
    );
    
    printf("两数相加结果为:%d\n", i3);
    return 0;
}

上面汇编代码中三个变量出现顺序是i3、i1、i2,%0绑定i3,%1绑定i1,%2绑定i2。


使用全局变量

在汇编代码中调用全局变量无需进行任何设置,直接使用变量名即可,编译器会自动转换为对应的内存地址。

#include <stdio.h>
int i1, i2;
int main()
{
    printf("输入两个整数\n");
    scanf("%d%d", &i1, &i2);
    
    __asm__
    (
        "push rax; \
        mov eax,i1; \
        add eax,i2; \
        mov i1,eax; \
        pop rax;"
    );
    
    printf("两数相加结果为:%d\n", i1);
    return 0;
}


 

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

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

相关文章

Linux中给复杂命令起别名

目录 1 前言 2 操作步骤 2.1 打开.bashrc 2.2 编辑.bashrc-添加别名 2.3 使别名生效 1 前言 在linux中有些指令会比较长&#xff0c;为了便捷的使用它们&#xff0c;我们就可以采取起别名的方式&#xff0c;具体操作如下。 2 操作步骤 2.1 打开.bashrc 输入如下指令&a…

SAP PP学习笔记 - 豆知识08 - 如何修改价格

正常的品目修改用MM02。 新建一个品目之后&#xff0c;啥都没干&#xff0c;现在想修改一下价格&#xff0c;发现MM02 修改不了了。 1&#xff0c;MR21 这里注意 转记日付 要和会计期间一致。 比如我这里的会计期间是 2024/03 有关会计期间&#xff0c;可以参照如下文章&am…

【C++】类和对象之初始化列表与static成员

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 前言2. 再谈构造函数2.1 构造函数体赋值2.2 初始化列表2.3 explicit关键字 3. static成员3.1 概念3.2 特性 1. 前言 在前面的博客中已经分享有关构造函数 【C】构造函数和…

DHCP自动获取IP地址实验(华为)

思科设备参考&#xff1a;DHCP自动获取IP地址实验&#xff08;思科&#xff09; 一&#xff0c;实验目的 路由器搭载DHCP&#xff0c;让PC通过DHCP自动获取IP地址 二&#xff0c;不划分vlan--全局地址池 实验拓扑 配置命令 Router <Huawei>system-view [Huawei]ip po…

JRebel and XRebel 插件在IDEA中的安装、激活和使用

1、JRebel安装 1、打开idea->setting->plugins->Marketplace 2、搜索插件JRebel and XRebel&#xff0c;点击安装&#xff0c;然后重启idea 如果左侧出现JRebel & XRebel代表已安装 3.离线安装JRebel 根据自己安装的idea版本进行下载电影的jrebel https://plugi…

表达式求值(中序遍历,)

题目描述&#xff1a; 分析&#xff1a; 此题是acwing的一个模板例题&#xff0c;利用中缀遍历解决&#xff0c;即可。 思路&#xff1a; 首先我们先了解一下什么是树的中序遍历&#xff1f; 中序遍历是 二叉树遍历 的一种&#xff0c;也叫做 中根遍历 、中序周游。 在二叉树中…

重头戏:盒子模型(box-model)

盒子模型(box-model): CSS处理网页时,他认为每一个标签都包含在一个不可见的盒子里面,如果我们将所有的标签都想象成盒子,那么我们对网页的布局就相当于是拜访盒子,我们只需要将相应的盒子摆放在网页中相应的位置就可以完成布局 盒子模型: 一个盒子我们往往会分成: 内容区(…

无法启动报,To install it, you can run: npm install --save @/components/iFrame/index

运行的过程中后台报错 npm install --save /components/iFrame/index&#xff0c;以为是安装三方依赖错误&#xff0c;经过多次重装node_modules依然没有用。 没办法&#xff0c;只能在项目中搜索 components/iFrame/index这个文件。。突然醒悟。。。 有时候&#xff0c;犯迷…

I.MX6ULL_Linux_驱动篇(54)linux 块设备驱动

前面我们都是在学习字符设备驱动&#xff0c;本章我们来学习一下块设备驱动框架&#xff0c;块设备驱动是Linux 三大驱动类型之一。块设备驱动要远比字符设备驱动复杂得多&#xff0c;不同类型的存储设备又对应不同的驱动子系统&#xff0c;本章我们重点学习一下块设备相关驱动…

CSS块元素,CSS的伪类和伪元素

学习建议 在你开始入手学习前&#xff0c;有一些小的建议。根据我自己学习的经验发现&#xff0c;这些建议在现在乃至我以后的岗位生涯里都是有很大帮助的。还有就是开始学习前&#xff0c;建议可以先花几天时间&#xff0c;查找一些如何入门的文章&#xff0c;通过对许多文章…

linux系统Jenkins工具配置webhook自动部署

Jenkins工具webhook自动部署 webhook自动部署webhook的意义操作流程jenkins页面操作gitlab页面操作 webhook自动部署 webhook的意义 自动化部署&#xff1a;Webhook 可以在代码提交、合并请求或其他特定事件发生时自动触发 Jenkins 构建和部署任务&#xff0c;从而实现自动化…

CSS的标准文档流,web设计与开发

CSS篇 让一个元素水平垂直居中&#xff0c;到底有多少种方案&#xff1f;浮动布局的优点&#xff0c;缺点&#xff1f;清除浮动的方式&#xff1f;使用display:inline-block会产生的问题&#xff1f;解决方法&#xff1f;布局题&#xff1a;div垂直居中&#xff0c;左右10px&a…

如何关闭远程桌面连接

远程桌面连接是一种方便的技术&#xff0c;可以让用户通过网络远程访问其他计算机的桌面界面。有时候我们可能需要关闭这个连接。本文将向你介绍如何关闭远程桌面连接。 关闭远程桌面连接的步骤 要关闭远程桌面连接&#xff0c;按照以下步骤操作&#xff1a; 打开远程桌面连接…

机器学习-面经(part6、集成学习)

10 集成学习 定义:通过结合多个学习器(例如同种算法但是参数不同,或者不同算法),一般会获得比任意单个学习器都要好的性能,尤其是在这些学习器都是"弱学习器"的时候提升效果会很明显。 10.1 Boosting(提升法) 可以用于回归和分类 问题,它每一…

关于出国留学和考研比较----以本人双非跨考计算机为例

文章目录 中心论点国内就业现状勿让旧认知害了自己那出国留学真的一无是处了吗?1. 藤校仍旧是具有极高价值2. 时间成本低3. 研究生一定比单纯的本科找工作强!4. 很多人说出国读博好,可以无脑入,真是这样吗? 中心论点 如果在选择出国留学还是国内考研的最终核心诉求都是有更好…

Luajit 2023移动版本编译 v2.1.ROLLING

文章顶部有编好的 2.1.ROLLING 2023/08/21版本源码 Android 64 和 iOS 64 luajit 目前最新的源码tag版本为 v2.1.ROLLING on Aug 21, 2023应该是修正了很多bug, 我是出现下面问题才编的. cocos2dx-lua 游戏 黑屏 并报错: [LUA ERROR] bad light userdata pointer 编…

CSS盒模型居中方法,web小程序开发工具

面试知识点 主要内容包括html&#xff0c;css&#xff0c;前端基础&#xff0c;前端核心&#xff0c;前端进阶&#xff0c;移动端开发&#xff0c;计算机基础&#xff0c;算法与数据结构&#xff0c;设计模式&#xff0c;项目等等。 html 1.浏览器页面有哪三层构成&#xff0c…

在Vue中搭建Three.js环境(超详细、保姆级),创建场景、相机、渲染器《一》

目录 Three.js简介创建vue项目引入Three.js实际操作环节文件目录创建初始化场景、相机 Three.js简介 Three.js 是一款基于 WebGL的 JavaScript 3D 库&#xff0c;它封装了 WebGL API&#xff0c;为开发者提供了简单易用的 API 来在 Web 浏览器中展示 3D 图形。Three.js 提供了…

【C#杂谈】在 .NET Framework 中使用新的C#语言特性

前排提示&#xff1a;提出一个可以让 [^1] 这中语法可以在.NET Framework运行时中使用的方法 众所都周知&#xff0c;.NET Framework&#xff08;以下简称 .NF&#xff09;作为一个被微软官方确认不在继续发布新特性的运行时&#xff0c;它所对应的C#语言版本被&#xff08;官方…

Unity使用UnityWebRequest读取音频长度不对的解决方法

在开发的过程中碰到这样一个问题&#xff0c;有的音频文件通过UnityWebRequest读取出来后&#xff0c;AudioClip的Length会不对&#xff0c;比如本身有7秒&#xff0c;读出来只有3秒。代码如下&#xff1a; IEnumerator TestEnumerator() {UnityWebRequest www UnityWebReque…