跳转至

sys 汇编

一、ISA 基本概念

  • ISA (Instruction Set Architecture) 是处理器架构的一部分。
  • ISA 是软件与硬件通信所使用的命令和操作的集合。
  • ISA 与微架构不同:微架构是处理器设计方法,用于执行指令集。
  • ISA 是内置于处理器微架构中的一组命令,处理器可以直接解码并执行。

二、RISC-V 概述

  • RISC-V(读作 “risk-five”)是一个 ISA 标准。
  • 基于精简指令集计算(RISC)的开源 ISA。
  • 之前有 RISC-I、II、III、IV。
  • 大多数 ISA(如 x86、ARM、Power、MIPS、SPARC)受专利保护,RISC-V 是开放的,允许任何人构建兼容计算机并使用相关软件。
  • 起源于 2010 年,由 UC Berkeley 的研究人员 Krste Asanovic、David Patterson 及其学生开发。

三、RISC-V 设计目标

  • 完全开放的 ISA,自由用于学术和工业。
  • 真正的 ISA,适合直接硬件实现,而非仅用于模拟或二进制翻译。
  • 避免“过度架构”:
  • 不针对特定微架构风格(如微码、硬连线控制、按序、解耦、乱序等)
  • 不针对特定实现技术(如全定制、ASIC、FPGA)
  • 允许在上述任何风格中高效实现
  • RISC-V ISA 包括:
  • 小型基础整数 ISA
  • 可选的标准扩展
  • 可选的自定义扩展
  • 支持修订后的 2008 IEEE-754 浮点标准。

四、RISC-V 设计原则

  • 通常保持非常简单且可扩展。
  • 指令长度可以是短、长或可变。
  • 分为多个规范:
  • 用户级 ISA 规范(计算指令)
  • 压缩 ISA 规范(16位指令)
  • 特权 ISA 规范(监管模式指令)
  • 更多...
  • ISA 支持表示为:RV + 字宽 + 支持的扩展。
  • 示例:RV64I 表示 64位 RISC-V,支持 I(整数)指令集。

五、基础指令集与扩展

基础整数 ISA(必须实现)

  • I:整数指令(ALU、分支/跳转、加载/存储)

标准扩展

  • M:整数乘除
  • A:原子指令
  • F:单精度浮点
  • D:双精度浮点
  • C:压缩指令(16位)
  • G = I + M + A + F + D

可选扩展

  • 用户可自定义扩展

六、地址空间变体

  • RV32:32位地址空间
  • RV64:64位地址空间
  • 易于子集化/扩展,适合教育/研究
  • 示例:RV64IM、RV64IMA、RV64G

七、扩展功能表(摘要)

名称 功能
RV32I 基础32位整数指令集,32个寄存器
RV32E 32位指令集,仅16个寄存器,用于极低端嵌入式
RV64I 基础64位整数指令集,所有寄存器64位
M 整数乘除
A 原子指令(并发处理)
F 单精度浮点,32个32位浮点寄存器
D 双精度浮点,64位寄存器
Q 四精度浮点,128位操作
L 64/128位十进制浮点
C 压缩指令(16位版本)
V 向量操作(未来)
B 位字段操作(未来)
T 事务内存(未来)
P 打包SIMD指令
RV128I 128位地址空间(未来)

八、RV64I 寄存器

  • 程序计数器(PC)
  • 32个64位整数寄存器(x0–x31)
  • x0 始终为 0
  • x1 用于保存返回地址
  • 32个浮点寄存器(f0–f31)
  • 每个可存放单精度或双精度浮点值(64位 IEEE FP)
  • 浮点状态寄存器(fsr),用于浮点舍入模式和异常报告

九、ALU 指令示例

示例指令 名称 含义
add x1,x2,x3 Add Regs[x1] ← Regs[x2] + Regs[x3]
addi x1,x2,3 Add immediate Regs[x1] ← Regs[x2] + 3
lui x1,42 Load upper immediate Regs[x1] ← 0'32#'42#'0'12
sll x1,x2,5 Shift left logical Regs[x1] ← Regs[x2] << 5
slt x1,x2,x3 Set less than if (Regs[x2] < Regs[x3]) Regs[x1] ← 1 else 0

十、Load/Store 指令示例(部分)

示例指令 名称 含义
ld x1,80(x2) Load doubleword 64位加载
lw x1,60(x2) Load word 符号扩展32位
lwu x1,60(x2) Load word unsigned 零扩展32位
lb x1,40(x3) Load byte 符号扩展8位
lbu x1,40(x3) Load byte unsigned 零扩展8位
fld f0,50(x2) Load FP double 64位浮点加载
sd x2,400(x3) Store double 64位存储
sw x3,500(x4) Store word 32位存储
fsw f0,40(x3) Store FP single 32位浮点存储
sh x3,502(x2) Store half 16位存储
sb x2,41(x3) Store byte 8位存储

注:所有内存引用使用单一寻址模式。


十一、控制转移指令示例

示例指令 名称 含义
jal x1,offset Jump and link Regs[x1] ← PC+4; PC ← PC+(offset<<1)
jalr x1,x2,offset Jump and link register Regs[x1] ← PC+4; PC ← Regs[x2]+offset
beq x3,x4,offset Branch equal zero if (Regs[x3]==Regs[x4]) PC ← PC+(offset<<1)
bgt x3,x4,name Branch greater than if (Regs[x3]>Regs[x4]) PC ← PC+(offset<<1)

所有控制指令(除跳转到寄存器地址外)都是 PC 相对寻址。


十二、指令编码格式总结

格式 字段(位数) 说明
R-type funct7(7), rs2(5), rs1(5), funct3(3), rd(5), opcode(7) 算术指令
I-type imm11:0, rs1(5), funct3(3), rd(5), opcode(7) 加载/立即数算术
S-type imm11:5, rs2(5), rs1(5), funct3(3), imm4:0, opcode(7) 存储
B-type imm12,10:5, rs2(5), rs1(5), funct3(3), imm4:1,11, opcode(7) 条件分支
J-type imm20,10:1,11,19:12, rd(5), opcode(7) 无条件跳转
U-type imm31:12, rd(5), opcode(7) 上立即数
  • 基础指令集(RV32)始终为32位固定长度,最低两位为 11₂。
  • 所有分支和跳转目标为16位粒度。

总结对照表

字段 全称 作用 常见位宽
rd Destination 结果写入哪个寄存器 5 位
rs1 Source 1 第一个操作数来自哪个寄存器 5 位
rs2 Source 2 第二个操作数来自哪个寄存器 5 位
imm Immediate 直接给的数值(偏移/常量) 12/20位
请给我基本的riscv指令

返回[[指令集## 十一、CPU we will be doing(我们将实现的CPU)]]


十三、特权模式

  • RISC-V 特权规范定义了3种特权级别(模式)
级别 编码 名称 缩写
0 00 User/Application U
1 01 Supervisor S
2 10 Reserved -
3 11 Machine M
  • Machine mode 是最高特权模式,也是唯一必需的模式。
  • 更高特权模式可访问低特权模式的所有功能。
  • 处理器通常在最低特权模式下执行,中断/异常切换到更高特权模式。

十四、支持的权限模式组合

级别数 支持模式 用途
1 M 简单嵌入式系统
2 M, U 安全嵌入式系统
3 M, S, U 运行类 Unix 操作系统的系统

十五、函数调用约定(Calling Convention)

六个阶段: 1. 将参数放在函数可访问的位置 2. 跳转到函数(使用 jal) 3. 获取局部存储资源,保存寄存器 4. 执行函数任务 5. 将结果放回调用者可访问的位置,恢复寄存器,释放存储资源 6. 返回调用点(使用 ret)


十六、栈与栈帧

  • :临时保存变量的内存,后进先出(LIFO),可扩展和收缩。
  • 栈帧:子例程分配并在退出时释放的私有空间,由帧指针(fp/x8)标识。

十七、寄存器 ABI 名称(部分)

寄存器 ABI 名称 说明 保存者
x0 zero 硬连线零 -
x1 ra 返回地址 调用者
x2 sp 栈指针 被调用者
x8 s0/fp 保存寄存器/帧指针 被调用者
x10-11 a0-1 函数参数/返回值 调用者
x18-27 s2-11 保存寄存器 被调用者

十八、函数进入与退出

函数序言(Prologue)

  • 调整栈指针(sp)分配栈帧空间
  • 保存返回地址(ra)等寄存器

函数尾声(Epilogue)

  • 恢复寄存器
  • 释放栈帧空间
  • 返回(ret)

十九、从源代码到运行程序的过程

步骤(逻辑上):

  1. 预处理(.c → .i):展开宏、包含文件
  2. 编译(.i → .s)
  3. 汇编(.s → .o)
  4. 链接(多个 .o → 可执行文件)
  5. 加载(运行)

二十、伪指令(Pseudo-instructions)示例

伪指令 基础指令 含义
nop addi x0, x0, 0 无操作
neg rd, rs sub rd, x0, rs 取补码
beqz rs, offset beq rs, x0, offset 如果等于零则分支
ret jalr x0, x1, 0 从子例程返回

二十一、汇编器输出:ELF 文件

  • 可执行与可链接格式(ELF)
  • 两种视图:
  • 程序头:运行时使用的段
  • 节头:节(section)的集合

可重定位目标文件

  • 二进制机器码,但不可执行
  • 可能引用外部符号
  • 包含符号表
  • 每个目标文件有自己的地址空间,地址稍后修复

可执行目标文件

  • 包含段(segments)数据
  • 入口点已记录

二十二、链接器作用

  • 将多个 .o 文件合并为可执行文件
  • 重定位每个目标文件的代码和数据段
  • 解析未解析的符号
  • 记录程序入口点

地址重定位

  • 合并同类型段(如 .text, .data)
  • 使用重定位信息修复地址

符号解析

  • 确定跨模块定义的符号位置
  • 修改引用指向正确位置

二十三、静态链接 vs 动态链接

静态链接

  • 所有库代码在运行前链接并加载
  • 库较大时浪费内存
  • 库更新后仍使用旧版本

动态链接

  • 第一次调用时才加载和链接外部函数
  • 每次程序运行时链接当前版本
  • 多个程序共享同一库代码内存
  • 使用 GOT 和 PLT 实现
  • 每次调用有少量运行时开销

二十四、静态库

  • 一组目标文件的集合(类似 zip 归档)
  • 链接器只提取需要的目标文件来解析未定义引用
  • 示例:libc.a 包含 printf.o, read.o, exit.o 等

二十五、加载器(Loader)

  • 将可执行文件加载到内存中
  • 跳转到起始地址
  • 初始化寄存器、栈、参数
  • 在现代操作系统中,加载是操作系统任务之一

加载静态链接程序步骤:

  • 确定所需地址空间大小
  • 分配地址空间
  • 将程序读入段
  • 清零未初始化数据(.bss)
  • 创建栈段
  • 设置运行时信息(参数、环境变量)
  • 启动程序

加载动态链接程序:

  • 操作系统启动动态链接器
  • 动态链接器启动目标程序
  • 处理第一次外部调用
  • 将函数复制到内存
  • 修改程序调用点指向正确函数

二十六、动态链接的优缺点

  • 优点:易于创建和更新,共享库节省内存,使用最新版本
  • 缺点:运行时性能开销更高,每次运行需重新解析符号

下一课 指令集

具体指令看risc-v使用指南 - Evelina_IS