RISC-V assembly (easy)
在虚拟机终端运行
$ make fs.img
阅读在user/call.asm
中生成可读的汇编版本
0000000000000000 <g>:
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int g(int x) {
0: 1141 addi sp,sp,-16
2: e422 sd s0,8(sp)
4: 0800 addi s0,sp,16
return x+3;
}
6: 250d addiw a0,a0,3
8: 6422 ld s0,8(sp)
a: 0141 addi sp,sp,16
c: 8082 ret
000000000000000e <f>:
int f(int x) {
e: 1141 addi sp,sp,-16
10: e422 sd s0,8(sp)
12: 0800 addi s0,sp,16
return g(x);
}
14: 250d addiw a0,a0,3
16: 6422 ld s0,8(sp)
18: 0141 addi sp,sp,16
1a: 8082 ret
000000000000001c <main>:
void main(void) {
1c: 1141 addi sp,sp,-16
1e: e406 sd ra,8(sp)
20: e022 sd s0,0(sp)
22: 0800 addi s0,sp,16
printf("%d %d\n", f(8)+1, 13);
24: 4635 li a2,13
26: 45b1 li a1,12
28: 00000517 auipc a0,0x0
2c: 7a850513 addi a0,a0,1960 # 7d0 <malloc+0x102>
30: 00000097 auipc ra,0x0
34: 5e6080e7 jalr 1510(ra) # 616 <printf>
exit(0);
38: 4501 li a0,0
3a: 00000097 auipc ra,0x0
3e: 274080e7 jalr 628(ra) # 2ae <exit>
- 哪些寄存器保存函数的参数?例如,在main对printf的调用中,哪个寄存器保存13?
a0-a7存放函数的参数
由第39行,即如下
24: 4635 li a2,13
可见,寄存器a2存放13
- main的汇编代码中对函数f的调用在哪里?对g的调用在哪里(提示:编译器可能会将函数内联)
源代码中, main调用函数f, 函数f调用函数g
在生成的汇编中,main函数进行了内联优化处理。
优化为内联(Inline Optimization)是指将函数的调用替换为函数的实际代码,以减少函数调用的开销。
f(8)+1可能直接替换看作为8+3+1来计算
在汇编语言中,内联优化通常是由编译器在生成汇编代码时自动完成的,程序员不需要手动插入汇编代码。
在第40行,即如下
26: 45b1 li a1,12
可见main直接计算出了结果并储存
- printf函数位于哪个地址?
30: 00000097 auipc ra,0x0
34: 5e6080e7 jalr 1510(ra) # 616 <printf>
printf函数的调用在第44行,
第一行代码 00000097H=00...0 0000 1001 0111B
对比指令格式,可见imm=0,dest=00001,opcode=0010111
对比汇编指令可知,uipc的操作码是0010111,ra寄存器代码是00001
这行代码将0x0左移12位(还是0x0)加到PC(当前为0x30)上并存入ra中,即ra中保存的是0x30
由第44行的跳转可知跳转的位置为
0x30 + 1510 = 0x030 + 0x5e6 = 0x616
- 在main中printf的jalr之后的寄存器ra中有什么值?
jalr (jump and link register):jalr rd, offset(rs1)跳转并链接寄存器
jalr指令会将当前PC+4保存在rd中,然后跳转到指定的偏移地址offset(rs1)
跳转到printf函数,且将PC + 4 = 0x34 + 4 = 0x38 存到ra中
- 运行以下代码。
unsigned int i = 0x00646c72;
printf("H%x Wo%s", 57616, &i);
程序的输出是什么?这是将字节映射到字符的ASCII码表。
输出取决于RISC-V小端存储的事实。如果RISC-V是大端存储,为了得到相同的输出,你会把i设置成什么?是否需要将57616更改为其他值?
十进制57616 = 十六进制0xE110
小端存储将0x00646c72划分72 6c 64 00
再将各部分十六进制转为十进制对应为114 108 100 0
由ASCII码表 对应为r l d
所以输出为 HE110 World
若为大端存储,i改为0x726c6400,不需要改变57616
- 在下面的代码中,“y=”之后将打印什么(注:答案不是一个特定的值)?为什么会发生这种情况?
printf("x=%d y=%d", 3);
函数需要两个参数, 而只传入了一个参数, y=后面缺失的参数会使用之前a2中保存的数据