Linux内核中的内联汇编

目录

一、概述

二、内联汇编语法

1、内联汇编常规语法说明

①、 asm

② 、asm-qualifiers

③ 、AssemblerTemplate

④、 OutputOperands

⑤、 InputOperands

⑥ 、Clobbers

2、内联汇编中的earlyclobber

3、根据语法编写一个简单的add函数

总结


一、概述

C语言在线编译工具:https://gcc.godbolt.org/

内联汇编是一种在高级编程语言(如C或C++)中直接嵌入汇编代码的技术。这种方法允许程序员在源代码中直接插入汇编指令,从而实现对底层硬件的更直接控制和优化。

  • 内联汇编通常使用asm关键字将汇编代码嵌入到C/C++源代码中。

  • 在GCC编译器中,内联汇编遵循AT&T语法,其中操作数的顺序是源操作数在前,目的操作数在后。

  • 寄存器名称前有%前缀,如%eax

  • 可以使用C/C++变量和函数,并能通过汇编指令直接操作这些变量。

二、内联汇编语法

1、内联汇编常规语法说明

如下图

①、 asm

也可以写作“__asm__”,表示这是一段内联汇编。

② 、asm-qualifiers

有3个取值:volatile、inline、goto。

volatile的意思是易变的、不稳定的,用来告诉编译器不要随便优化这段代码,否则可能出问题。比如汇编指令“mov r0, r0”,它把r0的值复制到r0,并没有实际做什么事情,你的本意可能是用这条指令来延时。编译器看到这指令后,可能就把它去掉了。加上volatile的话,编译器就不会擅自优化。

③ 、AssemblerTemplate

汇编指令,用双引号包含起来,每条指令用“\n”分开,比如:

“mov %0, %1\n” “add %0, %1, %2\n”
④、 OutputOperands

输出操作数,内联汇编执行时,输出的结果保存在哪里。

格式如下,当有多个变量时,用逗号隔开:

[ [asmSymbolicName] ] constraint (cvariablename)

asmSymbolicName是符号名,随便取,也可以不写。

constraint表示约束,有如下常用取值:

constraint

描述

m

memory operand,表示要传入有效的地址,只要CPU能支持该地址,就可以传入

r

register operand,寄存器操作数,使用寄存器来保存这些操作数

i

immediate integer operand,表示可以传入一个立即数

constraint前还可以加上一些修饰字符,比如“=r”、“+r”、“=&r”,含义如下:

constraint Modifier Characters

描述

=

表示内联汇编会修改这个操作数,即:写

+

这个操作数即被读,也被写

&

它是一个earlyclobber操作数

cvariablename:C语言的变量名。

示例1如下:

[result] "=r" (sum)

它的意思是汇编代码中会通过某个寄存器把结果写入sum变量。在汇编代码中可以使用“%[result]”来引用它。

示例2如下:

"=r" (sum)

在汇编代码中可以使用“%0”、“%1”等来引用它。

⑤、 InputOperands

输入操作数,内联汇编执行前,输入的数据保存在哪里。

格式如下,当有多个变量时,用逗号隔开:

[ [asmSymbolicName] ] constraint (cexpression)

asmSymbolicName是符号名,随便取,也可以不写。

constraint表示约束,参考上一小节,跟OutputOperands类似。

cexpression:C语言的表达式。

示例1如下:

[a_val]"r"(a), [b_val]"r"(b)

它的意思变量a、b的值会放入某些寄存器。在汇编代码中可以使用%[a_val]、%[b_val]使用它们。

示例2如下:

"r"(a), "r"(b)

它的意思变量a、b的值会放入某些寄存器。在汇编代码中可以使用%0、%1等使用它们。

⑥ 、Clobbers

在汇编代码中,对于“OutputOperands”所涉及的寄存器、内存,肯定是做了修改。但是汇编代码中,也许要修改的寄存器、内存会更多。比如在计算过程中可能要用到r3保存临时结果,我们必须在“Clobbers”中声明r3会被修改。

下面是一个例子:

: "r0", "r1", "r2", "r3", "r4", "r5", "memory"

我们常用的是有“cc”、“memory”,意义如下:

Clobbers

描述

cc

表示汇编代码会修改“flags register”

memory

表示汇编代码中,除了“InputOperands”和“OutputOperands”中指定的之外,

还会会读、写更多的内存

2、内联汇编中的earlyclobber

OutputOperands的约束中经常可以看到“=&r”,其中的“&”表示earlyclobber,它是最难理解的。有一些输出操作数在汇编代码中早早就被写入了新值A,在这之后,汇编代码才去读取某个输入操作数,这个输出操作数就被称为earlyclobber(早早就被改了)。

这可能会有问题:假设早早写入的新值A,写到了r0寄存器;后面读输入操作数时得到数值B,也可能写入r0寄存器,这新值A就被破坏了。

核心原因就在于输出操作数、输入操作数都用了同一个r0寄存器。为什么要用同一个?因为编译器不知道你是earlyclobber的,它以为是先读入了所有输入操作数,都处理完了,才去写输出操作数的。按这流程,没人来覆盖新值A。

所以,如果汇编代码中某个输出操作数是earlyclobber的,它的constraint就要加上“&”,这就是告诉编译器:给我分配一个单独的寄存器,跟输入操作数用同一个寄存器。

比如现在有这段代码

反汇编如下:

为了避免这种问题,此时只需要在输出结果出加上"&"即可。这是告诉编译器,对于%0操作数它是earlyclobber的,不能跟其他操作数共用寄存器。

3、根据语法编写一个简单的add函数

int  add_asm1(int a, int b)
{int res;__asm__ volatile ("add %0, %1, %2":"=&r"(res):"r"(a), "r"(b):"cc");return res;
}

代码实现的就是把第1、2个操作数相加,存入第0个操作数。也就是把a、b相加,存入res。还可以使用另一种写法,在Linux内核中这种用法比较少见。

int  add_asm2(int a, int b)
{int res;__asm__ volatile ("add %[result], %[v1], %[v2]":[result]"=&r"(res):[v1]"r"(a), [v2]"r"(b):"cc");return res;
}

总结

文章将C语言中的内联汇编的基本语法做了介绍,并说明一些参数的应用场景和注意事项。最后添加了一个函数例子来理解语法。

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

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

相关文章

JSON.toJSONString() 输出 “$ref“:“$[0]“问题解决及原因分析

一、背景 在构建一个公共的批处理方法类的时候,在测试输出的时候,打印了" r e f " : " ref":" ref":"[0][0]"的内容,这让我比较疑惑。不由得继续了下去… 二、问题分析 首先,我们需要…

c语言:打印任意行数的菱形

例如&#xff1a;以下图片形式 #include <stdio.h> int main() {int line 0;scanf_s("%d", &line);int i 0;//打印上半部分for (i 0; i < line; i){//打印空格数int j 0;for (j 0; j < line - 1 - i; j){printf(" ");}//打印*数量for…

饥荒服务器搭建centos

服务器环境需要64位32位不可用 uname -r 查看服务器版本 更新yum sudo yum update 安装依赖环境 sudo yum -y install glibc.i686 libstdc.i686 libcurl4-gnutls-dev.i686 libcurl.i686 screen 安装steam cd /home && mkdir steamcmd && cd steamcmd 国…

Istio基础知识

一、什么是Istio Istio 提供⼀种简单的⽅式来为已部署的服务建⽴⽹络&#xff0c;该⽹络具有 负载均衡、服务间认证、监控等功能&#xff0c;只需要对服务的代码进⾏⼀点或不需要做任何改动。想要让服务⽀持 Istio&#xff0c;只需要在您的环境中部署⼀个特殊的 sidecar 代 理&…

【C语言】简单有趣的扫雷游戏

**©作者:末央&#xff06; ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨&#xff0c;书写未来之大梦 目录 一、分析游戏规则二、分文件三、菜单实现四、游戏内容核心实现1.初始化棋盘2.打印棋盘3.布置雷4.排查雷5.game()函数实现调用 五、全部源码 一、分…

OpenHarmony实战开发-如何实现动画帧

请求动画帧 请求动画帧时通过requestAnimationFrame函数逐帧回调&#xff0c;在调用该函数时传入一个回调函数。 runframe在调用requestAnimationFrame时传入带有timestamp参数的回调函数step&#xff0c;将step中的timestamp赋予起始的startTime。当timestamp与startTime的差…

VScode添加c/c++头文件路径

1.设置工作区include path方法&#xff1a; 命令面板 -> 输入c/c 修改配置文件&#xff0c;添加路径&#xff1a; 2.全局路径&#xff1a; 设置 - > 搜索include path

即将完成60亿美元最大融资,马斯克旗下xAI公司牛在哪里?

【科技明说 &#xff5c; 科技热点关注】 60亿美元融资&#xff0c;约合人民币435亿元。xAI公司之所以这么牛&#xff0c;如此吸金&#xff0c;主要得益于几个关键因素。科技明说尝试为大家捋一捋。 首先是高估值&#xff0c;xAI以180亿美元的估值进行融资&#xff0c;显示出市…

代码随想录算法训练营DAY48|C++动态规划Part9|121.买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

文章目录 121.买卖股票的最佳时机思路CPP代码 122.买卖股票的最佳时机II思路CPP代码 123.买卖股票的最佳时机III思路CPP代码 121.买卖股票的最佳时机 力扣题目链接 文章讲解&#xff1a;121.买卖股票的最佳时机 视频讲解&#xff1a;动态规划之 LeetCode&#xff1a;121.买卖股…

Spring IoC注解式开发无敌详细(细节丰富)

1. Spring IoC注解式开发无敌详细&#xff08;细节丰富&#xff09; 文章目录 1. Spring IoC注解式开发无敌详细&#xff08;细节丰富&#xff09;每博一文案2. 注解回顾3. Spring 声明Bean的注解3.1 Spring注解的使用3.1.1 特别的&#xff1a;如果要扫描的是多个包3.1.2 Sprin…

面向新手在无人机竞速场景下的飞行辅助系统——浙大 FAST-Lab 高飞团队 ICRA 论文三项 Best Paper 入围

恭喜浙江大学 FAST-Lab 钟宇航同学的论文 A Trajectory-based Flight Assistive System for Novice Pilots in Drone Racing Scenario 顺利发表 ICRA 2024&#xff0c;并同时入选三项 Finalist&#xff1a; the IEEE ICRA Best Conference Paper Awardthe IEEE ICRA Best Pape…

滑动验证码登陆测试编程示例

一、背景及原理 处理登录时的滑动验证码有两个难点&#xff0c;第一个是找到滑块需要移动的距离&#xff0c;第二个是模拟人手工拖动的轨迹。模拟轨迹在要求不是很严的情况下可以用先加速再减速拖动的方法&#xff0c;即路程的前半段加速度为正值&#xff0c;后半段为负值去模…