Open
Conversation
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
…rameters. 现在每一帧的 backtrace 输出已包含三层信息: 改进前: [BACKTRACE] #1 fp=0x... ra=0x802005dc [BACKTRACE] fn=tg_rcore_tutorial_ch1_show::bt_depth3 改进后: [BACKTRACE] #1 fp=0x... ra=0x0000000080200910 [BACKTRACE] fn=tg_rcore_tutorial_ch1_show::bt_depth3() at src/main.rs:44 实现方案总结 整体思路是编译期提取 DWARF 调试信息,避免运行时解析的所有问题: 行号表(LINE_TABLE)——build.rs 用 addr2line crate(作为 build-dependency)读取上一次构建的 ELF 中的 DWARF .debug_line,以 2 字节步长遍历整个 .text 段,为每个指令地址解析 file:line。去重后生成约 5981 条条目的 const 数组。运行时对 ra - 2(指向 call 指令本身)做二分查找,定位到调用行。 函数形参名(FUNC_PARAMS)——通过 addr2line::gimli 遍历 .debug_info 中的 DW_TAG_subprogram,提取子节点 DW_TAG_formal_parameter 的 DW_AT_name。运行时按函数入口地址精确匹配后显示。 链接脚本简化——移除了之前将 .debug_* 合并进 .rodata 的做法,让调试节保持标准的 non-ALLOC 状态。这使宿主机工具(包括 GDB、addr2line)能正常读取,同时减小了运行时内存占用(.rodata 从 ~1.4MB 降至 ~100KB)。 关于实际参数值:在裸机环境中,函数参数通过寄存器 a0-a7 传递,回溯时这些寄存器早已被覆盖。要恢复实际值需要 DWARF Location Expression + 栈/寄存器快照,这本质上是调试器(GDB)的工作,超出了简易 backtrace 的范畴。当前显示的是函数签名中的形参名,帮助学生理解函数的接口。
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 解引用后显示字符串内容
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
And then you will see a lot, lot, lot of warnings, haha.