|
| 1 | +# [rcore lab1 qemu gdb](/2023/08/rcore_os_lab1_qemu_gdb) |
| 2 | + |
| 3 | +yay -S riscv-gnu-toolchain-bin |
| 4 | + |
| 5 | +riscv64-unknown-elf-gdb: error while loading shared libraries: libpython3.8.so.1.0 |
| 6 | + |
| 7 | +从 ubuntu20.04 拷贝 libpython3.8.so 之后 |
| 8 | + |
| 9 | +> Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding |
| 10 | +Python runtime state: core initialized |
| 11 | + |
| 12 | +好吧还是从 https://github.com/riscv-collab/riscv-gnu-toolchain 源码安装 |
| 13 | + |
| 14 | +结果 make linux 卡在 `git clone submodule`... 所以 rcore 官方教程推荐下载 <https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.3.0-2020.04.1-x86_64-linux-ubuntu14.tar.gz> |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## rcore 实验一 |
| 19 | + |
| 20 | +<http://rcore-os.cn/rCore-Tutorial-Book-v3/chapter1/4first-instruction-in-kernel2.html?highlight=strip%20all> |
| 21 | + |
| 22 | +先掌握下作业题和实验代码的方法论,在操作系统训练营中 |
| 23 | + |
| 24 | +- 作业题通常是 github classroom 克隆一份代码仓库 make rustlings 解决完编译错误提交代码跑 CI 打分 |
| 25 | +- 实验题通常是克隆一个代码仓库,例如实验一就 git checkout ch1 最后 make run |
| 26 | + |
| 27 | +由于 makefile 没有 `set -x` 我也不熟悉,我把 rcore 实验一的 makefile 代码整理成 shell 脚本 |
| 28 | + |
| 29 | +```sh |
| 30 | +<<- EOF |
| 31 | +[build] |
| 32 | +target = "riscv64gc-unknown-none-elf" |
| 33 | +[target.riscv64gc-unknown-none-elf] |
| 34 | +rustflags = [ |
| 35 | + "-Clink-arg=-Tsrc/linker.ld", "-Cforce-frame-pointers=yes" |
| 36 | +] |
| 37 | +EOF |
| 38 | +cargo clean |
| 39 | +cp src/linker-qemu.ld src/linker.ld |
| 40 | +cargo b |
| 41 | + |
| 42 | +# objcopy --only-section copy code/data section only? |
| 43 | +target=target/riscv64gc-unknown-none-elf/debug |
| 44 | +riscv64-unknown-elf-objcopy $target/os --strip-all -O binary $target/os.bin |
| 45 | + |
| 46 | +qemu-system-riscv64 -machine virt -nographic \ |
| 47 | + -bios ../bootloader/rustsbi-qemu.bin \ |
| 48 | + -s -S \ |
| 49 | + -device loader,file=$target/os.bin,addr=0x80200000 |
| 50 | +``` |
| 51 | + |
| 52 | +`-device` 告诉 qemu 帮忙将二进制镜像加载到内存指定位置 |
| 53 | + |
| 54 | +想着 gdb 能看点函数符号,我尝试去掉 --strip-all 结果 qemu 一运行就卡死了 |
| 55 | + |
| 56 | +我的思考是 0x802 内存地址必须紧凑排满生成出的代码块,因此就不能 debug symbol? 这里我没想明白,linux kernel 确实也有 debug symbol 相关配置 |
| 57 | + |
| 58 | +解答: 看本文后续 ELF section 解释以及 linker-qemu.ld 源码中都是将各个 section 位置写死装载到内存中 |
| 59 | + |
| 60 | +## qemu gdb 初体验 |
| 61 | + |
| 62 | +> riscv64-unknown-elf-gdb -ex 'file target/riscv64gc-unknown-none-elf/debug/os' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234' |
| 63 | +
|
| 64 | +ubuntu 用 gdb-multiarch 亦可 |
| 65 | + |
| 66 | +用 `i r` 命令也就是 info registers 的缩写看看寄存器的值 |
| 67 | + |
| 68 | +`i r mstatus` 能看一些特殊寄存器 |
| 69 | + |
| 70 | +结果全是 0 只有当前执行指令地址的 pc 寄存器有值 0x1000 |
| 71 | + |
| 72 | +``` |
| 73 | +(gdb) x/10x 0x1000 |
| 74 | +0x1000: 0x00000297 0x02828613 0xf1402573 0x0202b583 |
| 75 | +0x1010: 0x0182b283 0x00028067 0x80000000 0x00000000 |
| 76 | +0x1020: 0x87e00000 0x00000000 |
| 77 | +``` |
| 78 | + |
| 79 | +用 `x /10x 0x1000` 命令看内存地址 0x1000 开始,往后看 10 个 32bit,x 表示用 16 进制显示 |
| 80 | + |
| 81 | +由于 RustSBI 版本有所变动,所以这 10 个指令内容跟书中不一样很正常 |
| 82 | + |
| 83 | +## vscode gdb 看不到寄存器 |
| 84 | + |
| 85 | +毕竟内核代码是编译出来的 ELF 文件 strip 掉一堆元信息,vscode 调试窗口看不到变量值,估计 CLion 也是看不到 |
| 86 | + |
| 87 | +```json |
| 88 | +{ |
| 89 | + "name": "rcore-os", |
| 90 | + "type": "cppdbg", |
| 91 | + "request": "launch", |
| 92 | + "program": "${workspaceFolder}/os/target/riscv64gc-unknown-none-elf/debug/os", |
| 93 | + "args": [ |
| 94 | + "-ex", |
| 95 | + "file target/riscv64gc-unknown-none-elf/debug/os", |
| 96 | + "-ex", |
| 97 | + "set arch riscv:rv64" |
| 98 | + ], |
| 99 | + "stopAtEntry": false, |
| 100 | + "cwd": "${workspaceFolder}", |
| 101 | + "environment": [], |
| 102 | + "externalConsole": false, |
| 103 | + "MIMode": "gdb", |
| 104 | + "setupCommands": [ |
| 105 | + { |
| 106 | + "description": "", |
| 107 | + "text": "-enable-pretty-printing", |
| 108 | + "ignoreFailures": true |
| 109 | + } |
| 110 | + ], |
| 111 | + "miDebuggerPath": "/home/w/files/apps/riscv64_toolchain/bin/riscv64-unknown-elf-gdb", |
| 112 | + "miDebuggerServerAddress": "localhost:1234" |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +## 常用工具使用方法笔记 |
| 117 | + |
| 118 | +http://rcore-os.cn/rCore-Tutorial-Book-v3/appendix-b/index.html# |
| 119 | + |
| 120 | +### readelf/rust-readobj |
| 121 | + |
| 122 | +readelf -h os/target/riscv64gc-unknown-none-elf/debug/os |
| 123 | + |
| 124 | +``` |
| 125 | +ELF Header: |
| 126 | + Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |
| 127 | + Class: ELF64 |
| 128 | + Data: 2's complement, little endian |
| 129 | + Version: 1 (current) |
| 130 | + OS/ABI: UNIX - System V |
| 131 | + ABI Version: 0 |
| 132 | + Type: EXEC (Executable file) |
| 133 | + Machine: RISC-V |
| 134 | +``` |
| 135 | + |
| 136 | +rust-readobj require cargo-binutils and rustup llvm-tools-preview component |
| 137 | + |
| 138 | +rust-readobj -all os/target/riscv64gc-unknown-none-elf/debug/os | head |
| 139 | + |
| 140 | +``` |
| 141 | +File: os/target/riscv64gc-unknown-none-elf/debug/os |
| 142 | +Format: elf64-littleriscv |
| 143 | +Arch: riscv64 |
| 144 | +AddressSize: 64bit |
| 145 | +LoadName: <Not found> |
| 146 | +ElfHeader { |
| 147 | + Ident { |
| 148 | + Magic: (7F 45 4C 46) |
| 149 | + Class: 64-bit (0x2) |
| 150 | +``` |
| 151 | + |
| 152 | +Magic 前 4 byte 是固定组合让加载器快速确定文件是不是一个 ELF |
| 153 | + |
| 154 | +text section 就是代码段一般在前两个位置 text section 的例子 |
| 155 | + |
| 156 | +``` |
| 157 | + Section { |
| 158 | + Index: 1 |
| 159 | + Name: .text (1) |
| 160 | + Type: SHT_PROGBITS (0x1) |
| 161 | + Flags [ (0x6) |
| 162 | + SHF_ALLOC (0x2) |
| 163 | + SHF_EXECINSTR (0x4) |
| 164 | + ] |
| 165 | + Address: 0x80200000 |
| 166 | + Offset: 0x1000 |
| 167 | + Size: 21684 |
| 168 | +``` |
| 169 | + |
| 170 | +当将程序加载到内存的时候,对于每个 program header 所指向的区域,我们需要将对应的数据从文件复制到内存中 |
| 171 | + |
| 172 | +!> 这也是为什么 cargo b 编译出 elf 必须 strip-all 去掉所有无关 section 才能让首个地址才是代码 |
| 173 | + |
| 174 | +由于实验一代码限定死了内存布局,只有 strip-all 才能让我们手动完成【加载】任务 |
| 175 | + |
| 176 | +说起 ELF 文件加载想起一本必须要看的经典书《程序员的自我修养:链接、装载与库》 |
| 177 | + |
| 178 | +### ELF 三个核心 section |
| 179 | + |
| 180 | +- text: 放代码和常量 |
| 181 | +- bss: 未初始化的 static 变量 |
| 182 | +- data: 已初始化的 static 变量 |
| 183 | + |
| 184 | +## objdump 反汇编 |
| 185 | + |
| 186 | +rust-objdump -all target/riscv64gc-unknown-none-elf/release/os |
| 187 | + |
| 188 | +可以去找下 main/_start 的汇编代码 |
| 189 | + |
| 190 | +## objcopy |
| 191 | +实验一中已经用熟练了 |
0 commit comments