有了基本档案架构後,开始动工指令的部分。RISC-V将指令分成数个子集,其中包括RV32I、RV32E、RV64I、RV128I四套整数指令集,以及约14套扩充指令集,虽然号称"精简",最基本的RV32I指令集也有47条指令,实作的effort也是不小。为了能有的放矢的进行实作,目前打算先以实际编译出来最常用的指令开始处理。
为了观察实际上compiler常用的指令,需要先取得RISC-V的GNU toolchain,由於目前只打算支援riscv32架构,因此使用的是riscv32-elf-ubuntu-20.04-nightly-2021.06.26-nightly.tar.gz这个版本的toolchain。解压缩後在riscv/bin资料夹下就可以找到gcc、objdump等常用工具。首先撰写一个最基本的C程序:
int main() {
return 0;
}
使用gcc编译,并使用odjbump得到完整的assembly:
riscv/bin/riscv32-unknown-elf-gcc -o main.elf main.c
riscv/bin/riscv32-unknown-elf-objdump -D -M no-aliases main.elf > main.asm
观察入口点_start
的assembly:
00010084 <_start>:
10084: 00002197 auipc gp,0x2
10088: b5c18193 addi gp,gp,-1188 # 11be0 <__global_pointer$>
1008c: c3418513 addi a0,gp,-972 # 11814 <completed.1>
10090: c5018613 addi a2,gp,-944 # 11830 <__BSS_END__>
10094: 8e09 c.sub a2,a0
10096: 4581 c.li a1,0
10098: 2209 c.jal 1019a <memset>
1009a: 00000517 auipc a0,0x0
1009e: 26650513 addi a0,a0,614 # 10300 <atexit>
100a2: c511 c.beqz a0,100ae <_start+0x2a>
100a4: 00000517 auipc a0,0x0
100a8: 26650513 addi a0,a0,614 # 1030a <__libc_fini_array>
100ac: 2c91 c.jal 10300 <atexit>
100ae: 2049 c.jal 10130 <__libc_init_array>
100b0: 4502 c.lwsp a0,0(sp)
100b2: 004c c.addi4spn a1,sp,4
100b4: 4601 c.li a2,0
100b6: 2881 c.jal 10106 <main>
100b8: a8b9 c.j 10116 <exit>
可以发现除了一般的RV32I外,其中为了降低code size大量使用了c.
开头的压缩指令标准扩充(Standard Extension for Compressed Instructions),因此也必须实作扩充指令集C。
至此已经有一个明显的目标,就是将此ELF档能顺利跑完,并且能正确的更新所有的整数register以及PC。为达成此目标,指令实作的顺序就以从_start
开始执行的指令为准。
<<: Python 演算法 Day 5 - 理论基础 向量
设定档 昨日说明关於使用者身分验证以及权限设定的部分加以说明,并且透过第三方插件的方式展现如何在do...
练习写好架构有助於在将来程序越做越大时,可以比较好维护程序,又或者是其他人看到这只程序的时候,也比较...
EditText(输入框) 是个能与使用者互动的一个元件,我觉得也开始让程序变得稍微有点层次了,其实...
由於RDS注重资料的一致性, Transaction就相对重要, 也是RDS的优势. 从最基本的Be...
在上一篇,除了水以外,这一篇就来讲火 五行中的火,除了"灶"以外,防火也是门学问...