文章目录
- 前提
- 嵌入式开发
- 交叉编译
- GDB调试,QEMU,MAKEFILE
- 练习
目标:通过这一个系列课程的学习,开发出一个简易的在RISC-V指令集架构上运行的操作系统。
前提
这个系列的大部分文章和知识来自于:[完结] 循序渐进,学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春,以及相关的github地址。
在这个过程中,这个系列相当于是我的学习笔记,做个记录。
嵌入式开发
搞过51,32单片机的同学应该能明白什么是嵌入式开发。嵌入式开发是一种系统级别的与硬件结合比较紧密的软件开发结束。
交叉编译
参与编译与运行的机器根据角色可以分为三类:
- 构建(build)系统:执行编译构建动作的计算机
- 主机(host)系统:运行build系统生成可执行程序的计算机系统
- 目标(target)系统:特别地,当以上生成的可执行程序是GCC时,我们用target来描述用来运行GCC生成的可执行程序的计算机系统。
那么交叉编译就是:build == host != target
大白话就是:你编出来的可执行文件是在另一个不同的系统上运行的。所以你要用可以编译出在目标系统可运行的执行文件的编译器。比如如果你在x86上使用gcc编译出的程序,它只能在x86上运行,无法在risc-v上运行。要想编译出的程序可以在risc-v上运行,你就要使用risc-v的编译器。
GDB调试,QEMU,MAKEFILE
GDB调试这里不多阐述,因为我也不太懂,还在学习阶段,后面可能会出一两期关于gdb的博客。这里可以参考视频。这三者都是工具,网上有很多资料供大家学习。
练习
-
编写一个简单的打印 “hello world!” 的程序源文件:hello.c
#include<stdio.h> void main() { printf("hello world!"); }
-
对源文件进行编译,生成针对支持 rv32ima 指令集架构处理器的目标文件 hello.o。
$riscv64-unknown-elf-gcc -march=rv32ima -mabi=ilp32 -c hello.c -o hello.o $file hello.o hello.o: ELF 32-bit LSB relocatable, UCB RISC-V, version 1 (SYSV), not stripped
因为是交叉编译,所以这里使用的是risc-v上的编译器,-march=rv32ima
指定了程序是运行在risc-v32位整数(i),支持整数乘法和除法(m),原子操作(a)的CPU上,其他的扩展指令集名称如下。使用file
命令就可以看出这个这个hello.o
是risc-v文件。
- 查看 hello.o 的文件的文件头信息。
$riscv64-unknown-elf-readelf -h hello.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: RISC-V
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 10340 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
- 查看 hello.o 的 Section header table
$ riscv64-unknown-elf-readelf -S hello.o
There are 21 section headers, starting at offset 0x2864:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000034 00 AX 0 0 4
[ 2] .rela.text RELA 00000000 002020 000048 0c I 18 1 4
[ 3] .data PROGBITS 00000000 000068 000000 00 WA 0 0 1
[ 4] .bss NOBITS 00000000 000068 000000 00 WA 0 0 1
[ 5] .rodata PROGBITS 00000000 000068 00000d 00 A 0 0 4
[ 6] .debug_info PROGBITS 00000000 000075 000928 00 0 0 1
[ 7] .rela.debug_info RELA 00000000 002068 000678 0c I 18 6 4
[ 8] .debug_abbrev PROGBITS 00000000 00099d 0001ba 00 0 0 1
[ 9] .debug_aranges PROGBITS 00000000 000b57 000020 00 0 0 1
[10] .rela.debug_arang RELA 00000000 0026e0 000030 0c I 18 9 4
[11] .debug_line PROGBITS 00000000 000b77 00011d 00 0 0 1
[12] .rela.debug_line RELA 00000000 002710 000054 0c I 18 11 4
[13] .debug_str PROGBITS 00000000 000c94 0004c3 01 MS 0 0 1
[14] .comment PROGBITS 00000000 001157 000029 01 MS 0 0 1
[15] .debug_frame PROGBITS 00000000 001180 000038 00 0 0 4
[16] .rela.debug_frame RELA 00000000 002764 000048 0c I 18 15 4
[17] .riscv.attributes RISCV_ATTRIBUTE 00000000 0011b8 000026 00 0 0 1
[18] .symtab SYMTAB 00000000 0011e0 0009e0 10 19 156 4
[19] .strtab STRTAB 00000000 001bc0 00045f 00 0 0 1
[20] .shstrtab STRTAB 00000000 0027ac 0000b5 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
- 对 hello.o 反汇编,并查看 hello.c 的 C 程序源码和机器指令的对应关系。
$riscv64-unknown-elf-objdump -S hello.o
hello.o: file format elf32-littleriscv
Disassembly of section .text:
00000000 <main>:
#include<stdio.h>
void main()
{
0: ff010113 addi sp,sp,-16
4: 00112623 sw ra,12(sp)
8: 00812423 sw s0,8(sp)
c: 01010413 addi s0,sp,16
printf("hello world!");
10: 000007b7 lui a5,0x0
14: 00078513 mv a0,a5
18: 00000097 auipc ra,0x0
1c: 000080e7 jalr ra # 18 <main+0x18>
}
20: 00000013 nop
24: 00c12083 lw ra,12(sp)
28: 00812403 lw s0,8(sp)
2c: 01010113 addi sp,sp,16
30: 00008067 ret