RISCV C开发调试笔记

RISCV C开发调试笔记

hello.c

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(){
long a = 0x876543210 ;
float pi = 3.1415926 ;
printf("Hello %s!\n","World");
a = a*pi;
return a ;
}

如何指定target编译

riscv64-unknown-elf-gcc -c hello.c mylib.c i2c.c 只会编译生成hello.o myprint.o i2c.o ,但不会生成.out可执行文件

1
2
```
```mylib.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
```

`riscv64-unknown-elf-gcc hello.c mylib i2c.c -o hello_exec.out ` 不仅会编译还会链接成最终的可执行文件hello.out

链接后的地址从101b0开始

### 如何生成汇编代码
`riscv64-unknown-elf-gcc -S hello.c` 只会生成汇编代码hello.s 不会生成.out文件

```s
.file "hello.c"
.option nopic
.text
.section .rodata
.align 3
.LC2:
.string "World"
.align 3
.LC3:
.string "Hello %s!\n"
.text
.align 1
.globl main
.type main, @function
main:
addi sp,sp,-32
sd ra,24(sp)
sd s0,16(sp)
addi s0,sp,32
lui a5,%hi(.LC0)
ld a5,%lo(.LC0)(a5)
sd a5,-24(s0)
lui a5,%hi(.LC1)
flw fa5,%lo(.LC1)(a5)
fsw fa5,-28(s0)
lui a5,%hi(.LC2)
addi a1,a5,%lo(.LC2)
lui a5,%hi(.LC3)
addi a0,a5,%lo(.LC3)
call printf
ld a5,-24(s0)
fcvt.s.l fa4,a5
flw fa5,-28(s0)
fmul.s fa5,fa4,fa5
fcvt.l.s a5,fa5,rtz
sd a5,-24(s0)
ld a5,-24(s0)
sext.w a5,a5
mv a0,a5
ld ra,24(sp)
ld s0,16(sp)
addi sp,sp,32
jr ra
.size main, .-main
.section .rodata
.align 3
.LC0:
.dword 36344967696
.align 2
.LC1:
.word 1078530010
.ident "GCC: (GNU) 8.1.0"

如何反汇编.out文件

首先生成.out文件riscv64-unknown-elf-gcc -o hello.out hello.c

然后反汇编 riscv64-unknown-elf-objdump -d hello.out > hello_disassemble.s

即可查看反汇编代码,搜索main函数如下,当然也包括其他内置函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
hello.out:     file format elf64-littleriscv
Disassembly of section .text:
00000000000100b0 <_start>:
100b0: 0000d197 auipc gp,0xd
100b4: fd818193 addi gp,gp,-40 # 1d088 <__global_pointer$>
100b8: 84818513 addi a0,gp,-1976 # 1c8d0 <_edata>
100bc: 8d818613 addi a2,gp,-1832 # 1c960 <_end>
.....
...

000000000001038c <printf>:
1038c: 711d addi sp,sp,-96
1038e: f832 sd a2,48(sp)
10390: fc36 sd a3,56(sp)
....
..

0000000000010198 <main>:
10198: 1101 addi sp,sp,-32
1019a: ec06 sd ra,24(sp)
1019c: e822 sd s0,16(sp)
1019e: 1000 addi s0,sp,32
101a0: 67e9 lui a5,0x1a
101a2: a687b783 ld a5,-1432(a5) # 19a68 <__clzdi2+0x54>
101a6: fef43423 sd a5,-24(s0)
101aa: 67e9 lui a5,0x1a
101ac: a707a787 flw fa5,-1424(a5) # 19a70 <__clzdi2+0x5c>
101b0: fef42227 fsw fa5,-28(s0)
101b4: 67e9 lui a5,0x1a
101b6: a5078593 addi a1,a5,-1456 # 19a50 <__clzdi2+0x3c>
101ba: 67e9 lui a5,0x1a
101bc: a5878513 addi a0,a5,-1448 # 19a58 <__clzdi2+0x44>
101c0: 1cc000ef jal ra,1038c <printf>
101c4: fe843783 ld a5,-24(s0)
101c8: d027f753 fcvt.s.l fa4,a5
101cc: fe442787 flw fa5,-28(s0)
101d0: 10f777d3 fmul.s fa5,fa4,fa5
101d4: c02797d3 fcvt.l.s a5,fa5,rtz
101d8: fef43423 sd a5,-24(s0)
101dc: fe843783 ld a5,-24(s0)
101e0: 2781 sext.w a5,a5
101e2: 853e mv a0,a5
101e4: 60e2 ld ra,24(sp)
101e6: 6442 ld s0,16(sp)
101e8: 6105 addi sp,sp,32
101ea: 8082 ret
....
...

更多信息尝试riscv64-unknown-elf-objdump --help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Usage: objdump <option(s)> <file(s)>
Display information from object <file(s)>.
At least one of the following switches must be given:
-a, --archive-headers Display archive header information
-f, --file-headers Display the contents of the overall file header
-h, --[section-]headers Display the contents of the section headers
-x, --all-headers Display the contents of all headers
-d, --disassemble Display assembler contents of executable sections
-D, --disassemble-all Display assembler contents of all sections
-s, --full-contents Display the full contents of all sections requested
-G, --stabs Display (in raw form) any STABS info in the file

....
Display DWARF info in the file
-t, --syms Display the contents of the symbol table(s)
-T, --dynamic-syms Display the contents of the dynamic symbol table
....

The following switches are optional:
-b, --target=BFDNAME Specify the target object format as BFDNAME
-m, --architecture=MACHINE Specify the target architecture as MACHINE

如何指定target编译

riscv64-unknown-elf-rvgcc --target-help显示更多指定目标编译

默认 riscv64-unknown-elf-rvgcc 会生成RV64IMADF,如果你指向生成RV32IM指令集的机器码,如下操作

rvgcc -march=rv32im -mabi=ilp32 -o b_rv32im.out b.c

注意如果用-march=rvxxxx必须要加-mbi=xxxx

RISC-V 编译器支持多个 ABI,具体取决于 F 和 D 扩展是否存在。RV32 的 ABI 分别名
为 ilp32,ilp32f 和 ilp32d。ilp32 表示 C 语言的整型(int),长整型(long)和指针(pointer)
都是 32 位,可选后缀表示如何传递浮点参数。在 lip32 中,浮点参数在整数寄存器中传递;
在 ilp32f 中,单精度浮点参数在浮点寄存器中传递;在 ilp32d 中,双精度浮点参数也在浮点
寄存器中传递。

自然,如果想在浮点寄存中传递浮点参数,需要相应的浮点 ISA 添加 F 或 D 扩展(见
第 5 章)。因此要编译 RV32I 的代码(GCC 选项-march=rv32i),必须使用 ilp32 ABI(GCC
选项-mabi=lib32)。反过来,调用约定并不要求浮点指令一定要使用浮点寄存器,因此
RV32IFD 与 ilp32,ilp32f 和 ilp32d 都兼容。

对于C代码

1
2
3
4
void main(){
int val = 0xf;
val++;
}

gcc 使用rv32im,和默认64位编译的区别如下
rv32im_vs_rv64gc
可以看出32im的指令都是16bit, 而右边指令集有采纳C,有压缩到16bit

gdb 查看CPU寄存器

RISCV-GDB启动步骤

  • print $x0
  • p $x0
  • p $pc
  • info reg
  • display $x0 ;每跑一步都会显示寄存器
  • ni ;next inst
# riscv

评论