RISC-V学习基础(五)

news/2024/4/28 8:52:30/文章来源:https://blog.csdn.net/Caramel_biscuit/article/details/127414919

RISC-V汇编语言

C程序翻译成为可以在计算机上执行的机器语言程序的四个经典步骤。
在这里插入图片描述

函数调用规范(Calling convention)

函数调用过程通常分为6个阶段:

  1. 将参数存储到函数能够访问的位置。
  2. 跳转到函数开始位置(使用RV32I的jal指令jump and link)。
  3. 获取函数需要的局部存储资源,按需保存寄存器。
  4. 执行函数中的指令。
  5. 将返回值存储到调用者能够访问到的位置,恢复寄存器,释放局部资源。
  6. 返回调用函数的位置(使用ret指令)。

为了获得良好的性能,变量应该尽量存放在寄存器中,而不是内存中,但同时也要注意避免频繁地保持和恢复寄存器,因为它们同样会访问内存。
RISC-V有足够多的寄存器来达到两全其美的结果:既能将操作数存放在寄存器中,同时也能减少保存和恢复寄存器的次数。
其中关键点在于,在函数调用的过程中不保留部分寄存器存储的值(临时寄存器的值/另一些寄存器则对应称为保存寄存器)。不再调用其它函数的函数称为叶函数,当一个叶函数只有少量的参数和局部变量时,它们可以都被存储在寄存器中,而不会溢出spilling到内存中。如果函数参数和局部变量很多,程序还是需要把寄存器的值保存在内存中,但这种情况不多见。

函数调用中的寄存器:

  • 当做保存寄存器来使用,在函数调用前后值不变。
  • 当做临时寄存器来使用,函数调用中不保留。
  • 函数会更改用来保存返回值的寄存器,因此它们和临时寄存器类似。
  • 用来给函数传递参数的寄存器也不需要保留,它们也类似于临时寄存器。
  • 用于存储返回地址的寄存器和存储栈指针的寄存器,要保证函数调用前后保持不变。
  • 图3.2列出了寄存器的RISC-V应用程序二进制接口(ABI)名称和它们在函数调用中是否保留的规定。
    在这里插入图片描述
    根据ABI规范,标准的RV32I函数入口:
entry_label:addi sp,sp,-framesize # 调整栈指针(sp寄存器)分配栈帧sw ra,framesize-4(sp) # 保存返回地址# 按需保持其它寄存器# 函数体

如果参数和局部变量太多,在寄存器中存不下,函数的开头会在栈中为函数帧分配空间来存放。当一个函数的功能完成后,它的结尾会释放栈帧并返回调用点。

# 按需恢复其它寄存器
lw ra,framesize-4(sp) # 恢复返回地址
addi sp,sp,framesize #释放栈帧空间
ret # 返回调用点

汇编器

汇编器的作用不仅仅是产生处理器能够理解的目标代码,还可以翻译一些扩展指令,这些指令对汇编程序员或者编译器的编写者来说通常很有用。这类指令在巧妙配置常规指令的基础上实现,称为伪指令。
图3.3和3.4列出了RISC-V伪指令,前者中要求x0寄存器始终为0,后者没有此要求。
在这里插入图片描述
在这里插入图片描述
之前提到的ret实际上是一个伪指令,汇编器会用jalr x0,x1,0来替换它。大多数RISC-V伪指令依赖于x0。
因此,把一个寄存器硬编码为0便于将许多常用指令——如跳转(jump)、返回(return)、等于0时转移(branch one equal to zero)——作为伪指令,从而简化RISC-V指令集。

在这里插入图片描述
图3.5为经典的C程序Hello World,编译器产生的汇编指令如图3.6,其中使用了图3.2的调用规范和图3.3、3.4的伪指令。
在这里插入图片描述
汇编程序的开头是一些汇编指示符(assemble directives),它们是汇编器的命令,具有告诉汇编器代码和数据的位置、指定程序中使用的特定代码和数据常量等作用。
图3.6用到的指示符有:

  • .text:进入代码段。
  • .align 2:后续代码按22字节对齐。
  • .global main:声明全局符号“main”。
  • .section .rodata:进入只读数据段
  • .balign 4:数据按4字节对齐。
  • .string “Hello,%s!\n”:创建空字符结尾的字符串。
  • .string “world”:创建空字符结尾的字符串。

汇编器产生如图3.7的目标文件,格式为标准的可执行可链接文件(ELF格式)。
在这里插入图片描述

链接器

链接器允许各个文件独立地进行编译和汇编,这样在改动部分文件时,不需要重新编译全部源代码。
链接器把新的目标代码和已经存在的机器语言模块(如库函数)等拼接起来。

  • 链接器这个名字原于它的功能之一,即编辑所有对象文件的跳转并链接。
    在这里插入图片描述
  • 图3.10展示了一个典型的RISC-V程序分配给代码和数据的内存区域,链接器需要调整对象文件的指令中程序和数据的地址,使之与图中地址相符合。
  • 如果输入文件中的是与位置无关的代码(PIC),链接器的工作量会有所降低。PIC中所有的指令转移和文件内的数据访问都不受代码位置的影响。
  • RV32I的相对转移(PC-relative branch)特性使得程序更易于实现PIC。
  • 除了指令,每个目标文件还包含一个符号表,存储了程序中标签,由链接过程确定地址。
  • 其中包含了数据标签和代码标签,图3.6中有两个数据标签(string1和string2)和两个代码标签(main和printf)需要确定。
  • 由于在单个32位指令中很难指定一个32的地址,RV32I的链接器通常腰围每个标签调整两条指令。
  • 如图3.6所示:数据标签需要调整lui(load upper immediate)和addi(add immediate),代码标签需要调整auipc(add upper immediate to pc)和jalr(jump and link register).
  • RISC-V编译器支持多个ABI,具体取决于F和D扩展是否存在。
  • RV32的ABI分别名为ilp32、ilp32f和ilp32d。ilp32表示C语言的整型(int),长整型(long)和指针(point)都是32位,可选后缀表示如何传递浮点参数。ilp32中,浮点参数在整数寄存器中传递;ilp32f中,单精度浮点参数在浮点寄存器中传递;ilp32d中,双精度浮点参数也在浮点寄存器中传递。
  • 如果想在浮点寄存器中传递浮点参数,需要相应的浮点ISA添加F或D扩展。
  • 因此要编译RV32I的代码(GCC选项-march=rv32i),必须使用ilp32 ABI(GCC选项-mabi=lib32)。

常见RISC-V汇编指示符
在这里插入图片描述

静态链接和动态链接

  • 静态链接(static linking),在程序运行前所有的库都进行了链接和加载。如果这样的库很大,链接一个库到多个程序中会十分占用内存。
  • 除此之外,链接时库是绑定的,即使后期修复了BUG,强制的静态链接的代码仍然会使用旧的、有bug的版本。
  • 为了解决以上两个问题,现在许多系统都使用动态链接(dynamic linking),外部的函数在第一次调用时才会加载和链接
  • 后续所有调用都使用快速链接(fast linking),因此只会产生一次动态开销。每次程序开始运行,它都会按照需要链接最新版本的库函数,除此之外,如果多个程序使用了同一个动态链接库,库代码在内存中只会加载一次。
  • 编译器产生的代码和静态链接的代码很相似。不同之处在于,跳转的目标不是实际的函数,而是一个只有三条指令的存根函数(stub function)。存根函数会从内存中的一个表中加载实际的函数的地址并跳转。
  • 不过第一次调用时,表中没有实际的函数的地址,只有一个动态链接的过程的地址。当这个动态链接过程被调用时,动态链接器通过符号表找到实际要调用的函数,复制到内存,更新记录实际的函数地址的表。后续的每次调用的开销就是存根函数的三条指令的开销。

加载器

  • 加载器的作用就是把这个程序加载到内存中,并跳转到它开始的地址。如今的“加载器”就是操作系统。

  • 动态链接程序的加载稍微有些复杂,操作系统不直接运行程序,而是运行一个动态链接器,由动态链接器开始运行程序,并负责处理所有外部函数的第一次调用,把它们加载到内存中,并且修改程序,填入正确的调用地址。

  • 汇编器向RISC-VISA中增加了60条伪指令,使得RISC-V代码更容易读写,且不增加硬件开销。将一个寄存器编码为0使得其中很多伪指令更容易实现。使用加载高位立即数(lui)和程序计数器与高位立即数相加(auipc),简化了编译器和链接器寻找外部数据/函数的地址的过程。使用相对地址转移的代码与位置无关,减少了链接器的工作。大量的寄存器减少了寄存器保存和恢复的次数,加速函数调用和返回。

乘法和除法指令

RV32M向RV32I中添加了整数乘法和除法指令。
图4.1是RV32M扩展指令集的图形表示。
RV32M具有有符号和无符号整数的除法指令:divide(div)和divide unsigned(divu),它们将商放入目标寄存器。少数情况下,程序员需要余数而不是商,因此32RVM提供remainder(rem)和remainder unsigned(remu),它们在目标寄存器写入余数,而不是商。
在这里插入图片描述
图4.2列出了它们的操作码。
在这里插入图片描述
乘法的算式很简单:
积 = 被乘数 x 乘数

  • 但乘法比除法更为复杂,因为积的最大长度是乘数和被乘数的长度的和。将两个32位数相乘得到64位的乘积。
  • 为了正确得到一个有符号或无符号的64位积,RISC-V中带有4个乘法指令。
  • mul指令:得到整数32位乘积(64位中的低32位)。
  • mulh指令:如果操作数都是有符号整数,得到高32位。
  • mulhu指令:如果操作数都是无符号整数,得到高32位。
  • mulhsu指令:操作数一个为有符号一个为无符号,得到高32位。
  • 在一条指令中完成把64位积写入两个32位寄存器的操作会使硬件设计变得复杂,所以RV32M需要两条乘法指令才能得到一个完整的64位积。
  • 对许多微处理器来说,整数除法是相对较慢的操作。除数为2的幂次的无符号除法可以用右移来代替。事实证明,通过乘以近似倒数再修正积的高32位的方法,可以优化除数为其他数的除法。

RV32F和RV32D:单精度和双精度浮点数

在这里插入图片描述
图5.1是RV32F和RV32D扩展指令集的图形表示。
在这里插入图片描述
图5.2列出了RV32F的操作码
在这里插入图片描述
图5.3列出了RV32D的操作码

浮点寄存器

  • RV32F和RV32D使用32个独立的f寄存器而不是x寄存器。将寄存器容量和带宽乘以二。
  • 使用两组寄存器的主要原因是:可以提高处理器性能。
  • 使用两组寄存器对RISC-V指令集的主要影响是,必须要添加新的指令来对f寄存器加载和存储数据,还需要添加新指令用于x和f寄存器之间传递数据
    在这里插入图片描述
  • 图5.4列出了RV32D和RV32F寄存器以及对应的由RISC-V ABI确定的寄存器名称。
  • 如果处理器同时支持RV32F和RV32D扩展,则单精度数据仅使用f寄存器中的低32位。与RV32I中的x0不同,寄存器f0不是硬连线到常量0,而是与其它31个f寄存器一样,是一个可变寄存器。
  • 浮点运算舍入有几种方法,最准确且最常见的舍入模式是舍入到最近的偶数。舍入模式可以通过浮点控制状态寄存器fcsr进行设置。
  • 图5.5显示了fcsr并列出了舍入选项,它还包含标准所需的累积异常标志。
    在这里插入图片描述

浮点加载,存储和算术指令

  • 对于RV32F和RV32D,RISC-V有两条加载指令(flw,fld)和两条存储指令(fsw,fsd)。他们和lw和sw拥有相同的寻址模式和指令格式。
  • 添加到标准算术运算中的指令有fadd.s,fadd.d,fsub.s,fsub.d,fmul.s,fmul.d,fdiv.s,fdiv.d。
  • RV32F和RV32D还包括平方根指令fsqrt.s,fsqrt.d
  • 也有最小值和最大值指令fmin.s,fmin.d,fmax.s和fmax.d
  • 这些指令在不使用分支指令进行比较的情况下,将一对源操作数中的较小值或较大值写入目的寄存器。
  • 许多浮点算法(例如矩阵乘法)在执行完乘法运算后会立即执行一条加法或减法指令。因此RISC-V提供了指令用于先将两个操作数相乘然后将乘积加上(fmadd.s,fmadd.d)或减去(fmsub.s,fmsub.d)第三个操作数,最后再将结果写入目的寄存器。
  • 它还有在加上或减去第三个操作数之前对乘积取反的版本:fnmadd.s,fnmadd.d,fnmsub.s,fnmsub.d。
  • 这些融合的乘法-加法指令比单独的使用乘法及加法指令更准确也更快,因为它们只舍入过一次,而单独的乘法及加法指令舍入了两次。
  • 这些指令需要一条新指令格式指定第4个寄存器,称为R4。图5.2和5.3显示了R4格式,它是R格式的一个变种。
    在这里插入图片描述
    在这里插入图片描述
  • RV32F和RV32D没有提供浮点分支指令,而是提供了浮点比较指令,根据两个浮点的比较结果将一个整数寄存器设置为1或0:feq.s,feq.d,flt.s,flt.d,fle.s,fle.d。
  • 这些指令允许整数分支指令根据浮点数比较指令设置的条件进行分支跳转。
    例如,这段代码在f1<f2时,分支跳转到Exit:
flt x5,f1,f2
bne x5,x0,Exit

浮点转换和搬运

RV32F和RV32D支持在32位有符号整数,32位无符号整数,32位浮点数和64位浮点数之间进行所有组合的转换。
在这里插入图片描述
图5.6按源数据类型以及转换后的目的数据类型,罗列了这十条。
RV32F还提供了将数据从f寄存器移动到x寄存器的指令(fmv.x.w),以及反方向移动数据的指令(fmv.w.x)

其它浮点指令

  • RV32F和RV32D提供了不寻常的指令,有助于编写数学库以及提供有用的伪指令。
  • 第一个是符号注入指令,它从第一个源操作数复制了除符号位之外的所有内容。符号位的取值取决于具体是什么指令。
  • 浮点符号注入fsgjn.s,fsgnj.d:结果的符号位是rs2的符号位。
  • 浮点符号取反注入fsgnjn.s,fsgnjn.d:结果的符号位与rs2的符号位相反。
  • 浮点符号异或注入(fsgnjx.s,fsgnjx.d):结果符号位是rs1和rs2的符号位异或的结果。
  • 除了符号操作,基于符号注入指令还提供了三种流行的浮点伪指令。
  • 复制浮点寄存器:fmv.s rd,rs事实上是fsgnj.s rd,rs,rs
  • 否定:fneg.s rd,rs 映射到fsgnjn.s rd,rs,rs
  • 绝对值 fabs.s rd,rs 映射到fsgnjx.s rd,rs,rs

第二个不常见的浮点指令是classify分类指令(fclass.s,fclass.d)。

  • 测试一个源操作数满足下列10个浮点数属性中的哪些属性,然后将测试结果的掩码写入目的寄存器的低10位。十位中仅有一位被设置为1,其余被设置为0.
    在这里插入图片描述

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

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

相关文章

考研图论算法

图论——txf 倘若考研需要像写算法题目那样&#xff0c;写出图论的代码&#xff0c;那无疑图论是最难级别的。 -----Williams Tian 1. 重点表述 ①线形表可以空表&#xff0c;树可以空树&#xff0c;但是图不能一个顶点也没有&#xff08;允许一条边也没有&#xff09;. ②…

ETC-4 week 3th

ETC-4 week 3th 出奇至胜 read They are only charged for the amount of power they consume on rainy days.They needn’t pay a single cent for their power consumption(消耗能量) on sunny days.(13 june) consume v 消耗 耗尽 吃光 喝光 沉溺 浪费LOL consumes(消耗…

安装docker,打包jar包镜像文件,输出tar压缩包

打包 jar 步骤在文章最后&#xff0c;不需要安装的请直接跳到文末查看 一键安装命令&#xff1a; curl -sSL https://get.daocloud.io/docker | sh设置开机自启并启动docker systemctl enable docker.service启动docker systemctl start docker查看docker状态 systemctl s…

创新洞见|2023年B2B业务为何必须采用PLG增长策略

随着采用PLG模式的大型企业数量不断增加&#xff0c;91%的公司计划在2022年增加对PLG战略的投资&#xff0c;市场上已经验证了PLG公司的表现优于其竞争对手&#xff0c;规模增长更快&#xff0c;并拥有更高的企业价值&#xff08;EV&#xff09;。PLG象征着购买决策者的转变&am…

【附源码】计算机毕业设计SSM数据时代下的疫情管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Java多线程之Thread和Runnable关于共享资源的对比

背景 Thread和Runnable关于共享资源的对比&#xff0c;网上看到很多不正确的结论如下&#xff1a; Thread类创建多线程&#xff0c;无法保证多个线程对共享资源的正确操作&#xff0c;而Runnable接口可以保证多个线程对共享资源的正确访问。 得到这个结论的原因如下&#xff1…

【Pytorch】learning notes

文章目录【torch.xxx】torch.addmm() / torch.addmm_()torch.clamp() / torch.clamp_()torch.eq() / torch.ne()torch.manual_seed()torch.unique()torch.save() / torch.load()torch.view() / torch.permute() / torch. transpose() / torch.reshape()【torch.cuda.xxx】torch…

可以替代911s5的这几款产品还有跨境人士不知道吗?

不久前跨境电商用户都收到的坏消息无疑就是&#xff1a;911s5正式宣布停止运营并永久关闭。对于911s5&#xff0c;相信几乎所有的跨境电商用户都知道&#xff0c;因为其低廉的价格一直很受欢迎。所以一时间大家纷纷寻找911s5的替代品&#xff0c;但不是那么容易找的。今天这篇文…

投资组合图形化:EAP.util.plot

实证资产定价&#xff08;Empirical asset pricing&#xff09;已经发布于Github和Pypi. 包的具体用法(Documentation)博主将会陆续在CSDN中详细介绍&#xff0c;也可以通过Pypi直接查看。 Pypi: pip install --upgrade EAP HomePage&#xff1a; EAP a catchy description …

38 字典名[键名]=值 向字典增加键值对

38 字典名[键名]值 向字典增加键值对 文章目录38 字典名[键名]值 向字典增加键值对1. 语法2. 代码示例1. 字典中有要操作的键名—作用为修改2. 字典中没有要操作的键名—作用是增加3. 课后练习4. 列表增加元素知识回顾5. 总结1. 语法 向字典中增加键值对和修改字典的值的语法结…

开箱即用的数据缓存服务|EMQX Cloud 影子服务应用场景解析

在物联网业务高速迭代的今天&#xff0c;快速连接物联网设备与平台应用&#xff0c;实现业务快速落地与市场验证&#xff0c;是很多企业塑造核心竞争力、实现业务创新的关键。 EMQX Cloud 作为一站式运维代管的 MQTT 消息云服务&#xff0c;可以帮助用户在公有云环境中快速实现…

JavaScript:模拟拍照

实现拍照功能需要使用电脑的摄像头&#xff0c;可以使用 navigator.mediaDevices.getUserMedia() 方法&#xff0c;传递相应的参数就能开启摄像头 navigator.mediaDevices 是一个媒体设备对象&#xff0c;通过 getUserMedia( )方法开启音频和视频媒体设备。 getUserMedia 参数…

文献阅读-融合注意力机制的 IETM 细粒度跨模态检索算法

引用格式&#xff1a;翟一琛&#xff0c;顾佼佼&#xff0c;宗富强&#xff0c;姜文志&#xff0e;融合注意力机制的 IETM 细粒度跨模态 检索算法[J/OL]&#xff0e;系统工程与电子技术. https://kns.cnki.net/kcms/detail/11.2422.TN.20220823.1030.004.html 期刊&#xff1a…

跟李沐学AI-动手学深度学习1

整体内容 神经网络可以理解为是一种语言 数学和代码的结合&#xff0c;道术结合&#xff0c;关键在动手 是什么&#xff0c;怎么做&#xff0c;为什么这样 发展知识和应用 广告点击预测三个步骤 预测和训练 模型控制广告展现 数据格式 0维&#xff0c;1维&#xff0c…

【仿牛客网笔记】初识Spring Boot,开发社区首页-MyBatis入门

安装MySQL Server 安装MySQL Workbench 安装过程略。。。 Mybatis手册 Mybatis整合 Mybatis的核心组件&#xff1a; SqlSessionFactory:用于创建SqlSessionFactory工厂类。 SqlSession&#xff1a;Mybatis的核心组件&#xff0c;用于数据库执行SQL 主配置文件&#xff1a;XM…

大一学生期末大作业 html+css+javascript网页设计实例【电影购票项目】html网页制作成品代码

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

java面试题总结-1

Java语言特点 &#xff08;1&#xff09;简单易学、有丰富的类库 &#xff08;2&#xff09;面向对象&#xff08;java最重要的特性&#xff0c;让程序耦合度更低&#xff0c;内聚性更高&#xff09; &#xff08;3&#xff09;与平台无关性&#xff08;JVM是Java跨平台使用的…

拦截器和过滤器

拦截器和过滤器 参考&#xff1a; 过滤器和拦截器的区别_至今没搞明白的博客-CSDN博客_过滤器和拦截器的区别 拦截器与过滤器的区别_℡tang的博客-CSDN博客_拦截器和过滤器的区别 文章目录拦截器和过滤器过滤器概念作用Filter链与Filter生命周期SpringBoot 实现过滤器方式一…

如何将各大网盘整合到一起顺便挂载本地使用(文末附软件获取方式)

目录 1、Alist.exe 2、RaiDrive 今天发现了一个网盘变硬盘神器&#xff0c;它不仅安全免费&#xff0c;更全面支持&#xff1a;百度网盘、阿里云盘、天翼云盘、蓝奏云、闪电盘、夸克网盘、迅雷网盘、等众多你们听过&#xff0c;以及没有听过的所有网盘&#xff01; 直接先看效…

Mac环境下反编译工具的使用

日常工作中避免不了反编译工具经常安装&#xff08;换电脑设备、手滑把文件夹删除了。。。等等原因&#xff09;&#xff0c;而且时间一久忘记命令的使用&#xff0c;因此做下记录。 一、反编译工具三件套 apktool&#xff1a;获取apk里的资源文件、配置文件、清单文件、lib文…