Rust

1.2 Even Better TOML,支持 .toml 文件完整特性 Error Lens, 更好的获得错误展示 One Dark Pro, 非常好看的 VSCode 主题 CodeLLDB, Debugger 程序 1.3 Cargo cargo new hello_world tree cargo run is equal to cargo build + ./target/debug/world_hello 默认的是debug模式,编译器不会做任何的优化,编译速度快,运行慢。 高性能模式,生产发布模式: cargo run --release cargo build --release cargo check 检查编译能否通过 cargo.toml 项目数据描述文件 cargo.lock 项目依赖详细清单 在cargo.toml中定义依赖的三种方式: [dependencies] rand = "0.3" hammer = { version = "0.5.0"} color = { git = "https://github.com/bjz/color-rs" } geometry = { path = "crates/geometry" } 2....

2023-05-20 · 3 min

RISC-V手册 第十章 RISC-V特权架构

10.1 导言 到目前为止,本书主要关注RISC-V 对通用计算的支持:我们引入的所有指令都在用户模式(User mode 应用程序的代码在此模式下运行)下可用。本章介绍两种新的权限模式:运行最可信的代码的机器模式(machine mode),以及为Linux,FreeBSD 和Windows 等操作系统提供支持的监管者模式(supervisor mode)。 图10.1是RISC-V 特权指令的图形表示,图10.2列出了这些指令的操作码。显然,特权架构添加的指令非常少。作为替代,几个新的控制状态寄存器(CSR)显示了附加的功能。 10.2 简单嵌入式系统的机器模式 机器模式(缩写为M模式, M-mode)是 RISC-V中(hart hardware thread,硬件线程)可以执行的最高权限模式。程)可以执行的最高权限模式。在M模式下运行的hart对内存,I/O和一些对于启动和配置系统来说必要的底层功能有着完全的使用权。因此它是唯一所有标准RISC-V处理器都必须实现的权限模式。实际上简单的 RISC-V微控制器仅支持 M模式。 机器模式最重要的特性是拦截和处理异常的能力。RISC-V将异常分为两类。一类是同步异常。另一类是中断,它是与指令流异步的外部事件,比如鼠标的单击。 在 M模式运行期间可能发生的同步异常有五种: 访问错误异常:当物理内存的地址不支持访问类型时发生(例如尝试写入 ROM)。 断点异常:在执行 ebreak指令,或者地址或数据与调试触发器匹配时发生。 环境调用异常:在执行 ecall指令时发生。 非法指令异常:在译码阶段发现无效操作码时发生。 非对齐地址异常:在有效地址不能被访问大小整除时发生,例如地址为0x12的amoadd.w。 有三种标准的中断源:软件、时钟和外部来源。软件中断通过向内存映射寄存器中存数来触发。 10.3 机器模式下的异常处理 八个控制状态寄存器(CSR)是机器模式下异常处理的必要部分: mtvec (Machine Trap Vector) 它保存发生异常时处理器需要跳转到的地址。 mepc (Machine Exception PC) 它指向发生异常的指令。 mcause (Machine Exception Cause) 它指示发生异常的种类。 mie (Machine Interrupt Enable) 它指出处理器目前能处理和必须忽略的中断。 mip (Machine Interrupt Pending) 它列出目前正准备处理的中断。 mtval (Machine Trap Value) 它保存了陷入 trap 的附加信息:地址例外中出错的地址、发生非法指令例外的指令本身,对于其他异常,它的值为 0。 mscratch (Machine Scratch) 它暂时存放一个字大小的数据。 mstatus (Machine Status) 它保存全局中断使能,以及许多其他的状态,如图10....

2023-01-09 · 2 min

RISC-V手册 第三、四章 RISC-V汇编语言,乘法和除法指令

第三章 RISC-V汇编语言 3.2 函数调用规范 3.3 汇编器 这类指令在巧妙配置常规指令的基础上实现,称为伪指令。图 3.3和 3.4列出了 RISC-V伪指令。 汇编程序的开头是一些汇编指示符,它们是汇编器的命令。图 3.9是RISC-V的汇编指示符。其中图 3.6中用到的指示符有: .text:进入代码段。 .align 2:后续代码按2^2字节对齐。 .globl main:声明全局符号 “main” .section .rodata:进入只读数据段 .balign 4:数据段按4字节对齐 .string “Hello, %s!\n": 创建空字符结尾的字符串 .string “world": 创建空字符结尾的字符串 3.4 链接器 3.5 静态链接和动态链接 上一节对 静态链接进行了说明,在程序运行前所有的库都进行了链接和加载。如果这样的库很大,链接一个库到多个程序中会十分占用内存。另外,链接时库是绑定的,即使它们后来的更新修复了 bug,强制的静态链接的代码仍然会使用旧的、有bug的版本。 为了解决这两个问题,现在的许多系统使用动态链接,外部的函数在第一次被调用时才会加载和链接。后续所有调用都使用快速链接,因此只会产生一次动态开销。每次程序开始运行,它都会按照需要链接最新版本的库函数。另外,如果多个程序使用了同一个动态链接库,库代码在内存中只会加载一次。 编译器产生的代码和静态链接的代码很相似。其不同之处在于,跳转的目标不是实际的函数,而是一个只有三条指令的存根函数( stub function)。存根函数会从内存中的一个表中加载实际的函数的地址并跳转。不过,在第一次调用时,表中还没有实际的函数的地址,只有一个动态链接的过程的地址。当这个动态链接过程被调用时,动态链接器通过符号表找到实际要调用的函数,复制到内存中,更新记录实际的函数地址的表。后续的每次调用的开销就是存根函数的三条指令的开销。 第四章 乘法和除法指令 RV32M向RV32I中添加了整数乘法和除法指令。图4.1是RV32M扩展指令集的图形表示,图4.2列出了它们的操作码。 RV32M具有有符号和无符号整数的除法指令:divide(div)和divide unsigned(divu),它们将商放入目标寄存器。在少数情况下,程序员需要余数而不是商,因此RV32M提供remainder(rem)和remainder unsigned(remu),它们在目标寄存器写入余数,而不是商。 将两个32位数相乘得到的是64位的乘积。为了正确地得到一个有符号或无符号的64位积,RISC-V中带有四个乘 法指令。要得到整数要得到整数32位乘积( 64位中的低 32位)就用 mul指令。要得到高32位,如果操作数都是有符号数,就用mulh指令;如果操作数都是无符号数,就用mulhu指令。指令;如果一个有符号一个无符号,可以用mulhsu指令。在一条指令中完成把64位积写入两个 32位寄存器的操作会使硬件设计变得复杂,所以RV32M需要两条乘法指令才能得到一个完整的64位积。 对许多微处理器来说,整数除法是相对较慢的操作。如前述,除数为2的幂次的无符号除法可以用右移来代替。事实证明,通过乘以近似倒数再修正积的高32位的方法,可以优化除数为其它数的除法。例如,图 4.3显示了 3为除数的无符号除法的代码。 {% note danger %} lui t0, 0xaaaab 为什么t0=0xaaaaaaab而不是0xaaaab000 {% endnote %}

2023-01-06 · 1 min

RISC-V手册 第二章 RV32I基础整数指令集

1.2 模块化与增量型 ISA ​和几乎所有以往的 ISA不同,RISC-V是模块化的。它的核心是一个名为RV32I的基础 ISA,运行一个完整的软件栈。RV32I是固定的,永远不会改变。模块化来源于可选的标准扩展,根据应用程序的需要,硬件可以包含或不包含这些扩展。可以生成当前硬件条件下的最佳代码。惯例是把代表扩展的字母附加到指令集名称之后作为指示。例如,RV32IMFD将乘法( RV32M),单精度浮点(RV32F)和双精度浮点(RV32D)的扩展添加到了基础指令集 RV32I)中。 2.2 RV32I 指令格式 ​用于寄存器-寄存器操作的R类型指令,用于短立即数和访存load操作的I型指令,用于访存store操作的S型指令,用于条件跳转操作的B类型指令,用于长立即数的U型指令和用于无条件跳转的J型指令。 2.3 RV32I 寄存器 ​RV32I有31寄存器加上一个值恒为0的x0寄存器。 2.4 RV32I 整数计算 ​简单的算术指令(add, sub)、逻辑指令(and, or, xor),以及图2.1中的移位指令(sll, srl, sra)和其他ISA差不多。他们从寄存器读取两个32位的值,并将32位结果写入目标寄存器。 ​程序可以根据比较结果生成布尔值。为应对这种使用场景下,RV32I提供一个当小于时置位的指令(slt)。 ​图2.1剩下的两条整数计算指令主要用于构造大的常量数值和链接。加载立即数到高位(lui)将20位常量加载到寄存器的高20位。接着便可以使用标准的立即指令来创建32位常量。 有什么不同之处? RISC-V中没有字节或半字宽度的整数计算操作。操作始终是以完整的寄存器宽度。 RV32I也不包含乘法和除法,它们包含在可选的RV32M扩展中。 2.5 RV32I 的Load 和 Store ​除了提供32位字(lw,sw)的加载和存储外,图2.1中说明,RV32I 支持加载有符号和无符号字节和半字(lb,lbu,lh,lhu)和存储字节和半字(sb,sh)。有符号字节和半字符号扩展为32位再写入目的寄存器。即使是自然数据类型更窄,低位宽数据也是被扩展后再处理,这使得后续的整数计算指令能正确处理所有的32位。在文本和无符号整数中常用的无符号字节和半字,在写入目标寄存器之前都被无符号扩展到32位。 RV32I 条件分支 ​相等(beq),不相等 (bne),大于等于(bge),或小于(blt)。最后两种比较有符号比较,RV32I也提供相应的无符号版本比较的:bgeu和bltu。分支指令的寻址方式是12位的立即数乘以2,符号扩展它,然后将得到值加到PC上作为分支的跳转地址。{% label danger @这句话没理解 %} {% note info %} 补充说明:获取PC 当前的PC可以通过将auipc的U立即数字段设置为0来获得。 {% endnote %} 2.7 RV32I无条件跳转 ​图2.1中的跳转并链接指令(jal)具有双重功能。若将下一条指令PC + 4的地址保存到目标寄存器中,通常是返回地址寄存器ra(见图2.4),便可以用它来实现过程调用。如果使用零寄存器(x0)替换ra作为目标寄存器,则可以实现无条件跳转,因为x0不能更改。像分支一样,jal将其20位分支地址乘以2,进行符号扩展后再添加到PC上,便得到了跳转地址。 {% note info %} jal x1, X means jump to X, and save the return address which is normally PC+4 to the x1....

2023-01-06 · 1 min

程序员的自我修养学习笔记

objdump -h # 显示段结构 objdump -s # 将所有段以16进制打印出来 objdump -d # 反汇编 objdump -D # 反汇编更多信息 objdump -t # 查看符号 objdump -R # 查看目标文件重定位表 readelf -S # 显示段结构 readelf -h # 查看文件头 readelf -s # 查看符号表 readelf -l # 查看ELF加载时的Segment readelf -d 第二章 编译和链接 2.1.1 预处理 gcc –E hello.c –o hello.i 展开宏定义 处理预编译指令 “#if”、“#ifdef”等等 处理 “#include ”预编译指令 删除注释 添加行号和文件名标识 保留所有的 #pragma 编译器指令 2.1.2 编译 编译:gcc –S hello.i –o hello.s 预编译+编译:gcc –S hello....

2022-01-27 · 2 min · YC-Xiang