RISC-V架构学习——C语言内嵌汇编总结

1、C语言内嵌汇编的作用

(1)优化:对于特别重要代码进行优化,出于性能的考虑;
(2)C语言需要借助汇编指令来实现特殊功能。比如:C语言中访问系统寄存器就需要借助CSR指令;

2、基础内嵌汇编

2.1、基础内嵌汇编格式

asm asm-qualifiers(AssemblerInstructions)
关键字含义
asm这是内嵌汇编的关键字,表明这是一个GNU扩展
asm-qualifiers修饰词,比如:volatile、inline
AssemblerInstructions要内嵌的汇编语句,如果是多条汇编语句指令,需要使用"\n\t"来换行

(1)基础内嵌汇编指令支持带参数;
(2)gcc编译器不会去解析内嵌汇编指令,当做一个字符串处理;

2.2、基础内嵌汇编举例

#同时内嵌多条汇编指令
asm( "pushl %eax\n\t""movl $0,%eax\n\t"
"popl %eax");# 也可以将多条的内嵌汇编语句拆开写,效果一样
asm("movl %eax,%ebx");
asm("xorl %ebx,%edx");
asm("movl $0,_booga);

3、扩展内嵌汇编

3.1、扩展内嵌汇编的格式

3.1.1、格式说明

asm关键字 修饰词(指令部:输出部:输入部:损坏部:GotoLables(goto修饰时才有该部))
关键字含义
asm关键字扩展汇编指令的关键字:__asm__
指令部要内嵌的汇编指令,可以是一条或者多条
输出部用于描述在指令部中可以被修改的C语言变量以及约束条件
输入部用于描述在指令部中只能被读取访问的C语言变量以及约束条件
损坏部告诉编译器内嵌汇编可能带来的影响

3.1.2、修饰词

修饰词含义
volatile用于关闭gcc优化,可参考博客:《C语言中volatile关键字详解以及常见的面试问题》
inline用于内联,gcc会把汇编代码编译成尽可能短的代码
goto用于在汇编代码里跳转到C语言的标签处

3.1.3、内嵌汇编操作符号/修饰符

操作符/修饰符含义
=被修饰的操作数是只写属性
+被修饰的操作数具有可读可写属性
&被修饰的操作数只能作为输出,这个操作数在输入参数的指令执行完成之后才能写入

输出部通常用“=”或者“+”修饰符;输入部分则不能用“=”或者“+”约束条件,否则编译器会报错,因为输入部是用来描述只能读取的C语言变量,不能具有写属性;

3.1.4、操作数约束符

操作符/修饰符含义
p内存地址
m内存变量
r通用寄存器
o内存地址,基地址寻址
i立即数
V内存变量,不允许偏移的内存操作数
n立即数

3.1.5、损坏部介绍

关键字含义
memory告诉编译器,内嵌汇编代码改变了内存中的值,执行完汇编代码后重新加载该值
cc告诉编译器,内嵌汇编代码修改了状态寄存器的相关标志位

3.1.6、指令部的参数表示

3.1.6.1 、用"前缀% + 数字"表示变量

asm volatile(
"add %0, %1, %2" 
: "=r"(res)
: "r"(i), "r"(j)
);

(1)%0对于"=r"(res),%1对应"r"(i),%2对应"r"(j),内嵌汇编的功能:把i+j的结果写到res中;
(2)"r"修饰词,表示该变量需要使用一个通用寄存器;
总结:用%+数字来引用后面输入部和输出部的参数;

3.1.6.2 、用汇编符号来表示变量

asm volatile(
"add %[result], %[input_i], %[input_j]" 
: [result] "=r"(res)
: [input_i] "r"(i), [input_j] "r"(j)
);

在输出部和输入部定义变量时就绑定符号,然后在指令部就可以通过符号来引用变量,提高代码的可读性;

3.1.7、goto修饰词介绍

asm goto("addi %0, %0, -1\n""beqz %0, %1[label]\n":: "r"(a): "memory": label);return 0;label:printf("11111\n");

(1)输出部必须是空的。goto是用于跳转功能,在满足某个条件下进行跳转,没有输出数据的必要;
(2)相较于其他情况,goto修饰的情况下多了标签部,表明最后要跳转的标签处;
(3)上面内嵌汇编的功能:当变量a是1时,则跳转到标签label处;

3.2、扩展汇编实例分析

//读取csr寄存器的宏
#define read_csr(csr)						\
({								\register unsigned long __v;				\__asm__ __volatile__ ("csrr %0, " #csr			\: "=r" (__v) :			\: "memory");			\__v;							\
})unsigned long val;
val = read_csr(mstatus);//将上面的代码按宏定义展开
val = ({ register unsigned long __v; \__asm__ __volatile__ ("csrr %0, " "mstatus" : "=r" (__v) : : "memory");\__v; });

3.3、内嵌汇编和宏结合

//用ATOMIC_OP宏定义内嵌汇编的函数,摘抄自linux源码
#define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix)		\
static __always_inline							\
void arch_atomic##prefix##_##op(c_type i, atomic##prefix##_t *v)	\
{									\__asm__ __volatile__ (						\"	amo" #asm_op "." #asm_type " zero, %1, %0"	\: "+A" (v->counter)					\: "r" (I)						\: "memory");						\
}	#define ATOMIC_OPS(op, asm_op, I)					\ATOMIC_OP (op, asm_op, I, w, int,   )				\ATOMIC_OP (op, asm_op, I, d, s64, 64)ATOMIC_OPS(add, add,  i)//将上面的宏展开
static __always_inline void arch_atomic_add(int i, atomic_t *v)
{__asm__ __volatile__ ( "amoadd.w " zero, %1, %0" : "+A" (v->counter) : "r" (i): "memory"); 
}

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

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

相关文章

Python 使用raise引发异常

视频版教程 Python3零基础7天入门实战视频教程 当程序出现错误时,系统会自动引发异常。除此之外,Python也允许程序自行引发异常,自行引发异常使用raise语句来完成。 一般是业务逻辑上,业务异常问题,我们可以自行引发…

Soft-Serve小巧强大-轻量级Git服务

文章目录 前言一、Soft-Serve官方解释:我的要求 二、使用步骤我的环境公钥、私钥生成安装镜像参数解释: 配置config.yamlconfig 实操创建用户及绑定公钥创建代码仓库及添加合作者之后就是 git 基本操作了 总结 前言 用过 Gitlab, 也挺好用。 遇到几个问…

十一、MySql的事务(上)

文章目录 一、引入(一)CURD不加控制,会有什么问题?(二)CURD满足什么属性,能解决上述问题? 二、什么是事务?三、事务的特性(一)原子性:…

数据库计算机三级等级考试--数据库技术相关知识点和笔记

数据库计算机三级等级考试–数据库技术 计算机三级等级考试笔记,是博主通过计算机三级数据库技术考试的相关笔记,此篇博客,不仅适合需要考计算机三级考试的各位考生,也适合在职场处理关于数据库的部分操作,个人认为算是一篇使用性…

视频监控管理平台/视频汇聚/视频云存储EasyCVR安全检查的相关问题及解决方法3.0

智能视频监控系统/视频云存储/集中存储/视频汇聚平台EasyCVR具备视频融合汇聚能力,作为安防视频监控综合管理平台,它支持多协议接入、多格式视频流分发,视频监控综合管理平台EasyCVR支持海量视频汇聚管理,可应用在多样化的场景上&…

Matlab数组操作教程

Matlab是一种强大的数值计算和科学编程语言,它提供了许多强大的数组操作功能。在本教程中,我们将介绍一些常用的Matlab数组操作,并提供一些示例代码来帮助您更好地理解。 1. 创建数组在Matlab中,可以使用以下方法创建数组&#x…

python 学习笔记(6)—— Flask 、MySql

目录 Flask 1、起步 2、渲染项目的首页 3、处理无参数的 GET 请求 4、处理有 query 参数的 GET 请求 6、处理 params 参数的 get 请求 6、处理 application/json 类型请求体的 POST 请求 7、根据参数渲染模板页面 8、上传文件 数据库操作(mysql&#xff0…

「聊设计模式」之中介者模式(Mediator)

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅! 前言 在软件开发过程中,我们通常会遇到一个问题&…

(二)随机变量的数字特征:探索概率分布的关键指标

文章目录 🍋1. 随机变量的数学期望🍋1.1 离散型随机变量的数学期望🍋1.2 连续型随机变量的数学期望 🍋2. 随机变量函数的数学期望🍋2.1 一维随机变量函数的数学期望🍋2.2 二维随机变量函数的数学期望 &…

Hive 数据仓库介绍

目录 ​编辑 一、Hive 概述 1.1 Hive产生的原因 1.2 Hive是什么? 1.3 Hive 特点 1.4 Hive生态链关系 二、Hive架构 2.1 架构图 2.2 架构组件说明 2.2.1 Interface 2.2.1.1 CLI 2.2.1.2 JDBC/ODBC 2.2.1.3 WebUI 2.2.2 MetaData 2.2.3 MetaStore 2.2…

巨人互动|Facebook海外户Facebook客户反馈分数

Facebook客户反馈分数是一项用于衡量用户对Facebook产品和服务满意度的指标。该指标被广泛应用于各种调研和评估活动,帮助Facebook了解用户对其平台和功能的意见和建议,并从中识别出改进的机会。 巨人互动|Facebook海外户&Facebook新闻提要的算法&am…

Python 文件写入操作

视频版教程 Python3零基础7天入门实战视频教程 w模式是写入,通过write方法写入内容。 # 打开文件 模式w写入,文件不存在,则自动创建 f open("D:/测试3.txt", "w", encoding"UTF-8")# write写入操作 内容写入…

浅谈C++|运算符重载

重载原因 C 中的运算符重载是一种特性,允许程序员定义自定义类类型的运算符操作。通过运算符重载,可以对类对象执行类似于内置类型的操作,例如加法、减法、乘法等。 运算符重载通过定义特定的成员函数或非成员函数来实现。成员函数的运算符重…

Spring 依赖注入和循环依赖

一.依赖注入的方式 依赖注入(Dependency Injection,简称DI)是一种软件设计模式和编程技术,用于实现类之间的解耦和依赖关系的管理。它的核心思想是:在对象创建时,由外部容器负责将该对象所依赖的其他对象&a…

【react】慎用useLayoutEffect转而使用useEffect

由于useLayoutEffect钩子是在dom获得后、渲染组件前。因此,如果在useLayoutEffect中设置一些长耗时的,或者死循环之类的任务,会导致内存堆栈溢出。这时候需要转用useEffect。 // 适配全局宽度拉动变化时,legend显示数量React.use…

OpenAI 模型列表模型

〖ChatGPT实践指南 - 零基础扫盲篇⑧〗- OpenAI 的 模型(Model) 介绍 最新模型描述最大 TOKENS训练日期 gpt-4比任何 GPT-3.5 模型都更强大,能够执行更复杂的任务, 并针对聊天进行了优化。将使用我们最新的模型迭代进行更新。 8,192 tokens Up to Sep 20…

[git] 撤销已经push的提交

1.首先先撤销在本地的commit&#xff1a; git reset --soft HEAD~1这段的意思是撤销最近的一次commit&#xff0c;并且保留工作区的修改。 2.撤销了commit之后&#xff0c;使用git push提交变更到远程 git push origin <本地分支名>:<远程分支名> -f注意&#…

【Linux】shell 提示符

​ Shell俗称壳程序&#xff0c;是一种由C语言编写的用于和操作系统交互的命令解析器软件。它用来接收用户输入命令&#xff0c;然后调用相应的应用程序。 Shell同时又是一种程序设计语言。作为命令语言&#xff0c;它交互式解释和执行用户输入的命令或者自动地解释和执行预先…

PyG-GAT-Cora(在Cora数据集上应用GAT做节点分类)

文章目录 model.pymain.py参数设置运行图 model.py import torch.nn as nn from torch_geometric.nn import GATConv import torch.nn.functional as F class gat_cls(nn.Module):def __init__(self,in_dim,hid_dim,out_dim,dropout_size0.5):super(gat_cls,self).__init__()s…

java学习--day6(数组)

文章目录 day5作业今天的内容1.数组1.1开发中为啥要有数组1.2在Java中如何定义数组1.3对第二种声明方式进行赋值1.4对数组进行取值1.5二维数组【了解】1.6数组可以当成一个方法的参数【重点】1.7数组可以当成一个方法的返回值1.8数组在内存中如何分配的【了解】 2.数组方法循环…