Skip to content

docs: add book for ch5 & ch6#3

Open
AsakuraMizu wants to merge 1 commit intorcore-os:mainfrom
AsakuraMizu:docs/ch5-ch6
Open

docs: add book for ch5 & ch6#3
AsakuraMizu wants to merge 1 commit intorcore-os:mainfrom
AsakuraMizu:docs/ch5-ch6

Conversation

@AsakuraMizu
Copy link

chyyuu pushed a commit that referenced this pull request Mar 22, 2026
问题根因
lld 链接器的 .symtab(SHT_SYMTAB)和 .strtab(SHT_STRTAB)是链接器自行创建的特殊节,VMA=0、无 SHF_ALLOC 标志,不会被 QEMU -kernel 加载到内存。旧代码试图把它们合并进 .rodata 会报节类型冲突;即使放到独立输出节,VMA 仍为 0。运行时解引用地址 0 直接崩溃,连 Hello, world! 都无法输出。

解决方案:编译时 ELF 解析 + const 符号表嵌入
放弃运行时读 ELF .symtab,改为 build.rs 在编译前从上一次构建产物中提取函数符号,以 const 数组嵌入二进制。

改动的文件:

build.rs — 新增 extract_func_symbols() 和 write_func_syms_rs():直接解析 ELF64 的节头定位 .symtab+.strtab,过滤 STT_FUNC 符号(地址在 0x80200000..0x81000000),按地址排序后生成 OUT_DIR/func_syms_generated.rs。通过 cargo:rerun-if-changed 监控产物路径,产物出现或变化时自动重新提取。同时从链接脚本中移除了无效的 .symtab/.strtab 输出节。

src/symtab_resolve.rs — 完全重写:通过 include!() 引入生成的 const FUNC_SYMS: &[(u64, u64, &str)],二分查找匹配 ra,直接用 rustc_demangle + SbiWriter(core::fmt::Write)输出到串口。不再需要 alloc、Vec、运行时 ELF 解析、unsafe extern "C" 引用。

src/main.rs — 移除了 symtab_ptrs.S 的 global_asm! 引用(不再需要汇编中转指针)。

asm/symtab_ptrs.S — 已删除。

test_lec2_lab1.sh — 在 cargo run 前加了一次 cargo build(确保符号表已填充),并增加了对 bt_depth 和 rust_main 函数名的检查(共 20 项)。

运行效果:

[BACKTRACE] #0 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::stackwalk::print_backtrace
[BACKTRACE] #1 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::bt_depth3
[BACKTRACE] #2 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::bt_depth2
[BACKTRACE] #3 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::bt_depth1
[BACKTRACE] #4 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::rust_main
[BACKTRACE] end=ra_null_bottom_of_chain
从干净构建算起需要两次 cargo build(首次无上轮产物→空表;第二次提取到 554 个函数符号)。.text 在链接脚本中位于 .rodata 之前,函数地址不受符号数据大小变化影响,因此两次构建即可收敛。
chyyuu pushed a commit that referenced this pull request Mar 22, 2026
-----------------
[BACKTRACE] #1  fn=...bt_depth3(msg="hello_os", flag=true) at src/main.rs:48
[BACKTRACE] #2  fn=...bt_depth2(count=42, label="hello_os") at src/main.rs:55
[BACKTRACE] #3  fn=...bt_depth1(id=42, name="hello_os", value=-1) at src/main.rs:63
实现原理
整个方案分编译期和运行时两阶段:

编译期(build.rs) 从上一次构建的 ELF DWARF 信息中提取每个函数形参的三项关键数据:

栈偏移 — 解析 DW_AT_location 中的 DW_OP_fbreg(N) 表达式(SLEB128 编码),得到参数相对于帧指针 s0 的偏移量
字节大小 — 通过 DW_AT_type 引用找到类型 DIE,读取 DW_AT_byte_size
类型标签 — 根据 DW_AT_encoding(signed/unsigned/boolean)和结构体名称(&str)分类为五种 kind
这些信息生成为 const FUNC_PARAM_LOCS: &[(u64, &str, i16, u8, u8)] 数组。

运行时(symtab_resolve.rs) 对每一帧:

stackwalk.rs 将 frame.fp(被标识函数自身的 s0 值)传给 print_fn_for_ra
在 FUNC_PARAM_LOCS 中查找该函数的所有参数
通过 fp + fbreg_offset 计算参数在栈上的地址,直接读取原始字节
按类型格式化:整数显示十进制,bool 显示 true/false,&str 解引用后显示字符串内容
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant