基于LLVM的自制编译器生成代码引发指针算术相关页故障求助
自制LLVM编译器生成代码引发页故障问题定位
问题概述
基于LLVM搭建的自制编译器在开发专属操作系统时触发页故障。页故障由memeq函数触发,但根源是tarLookup函数传递给memeq的ptr指针异常指向代码段(地址高于0xFFFFFFFFFF...)。第一次循环中memeq运行完全正常,但执行特定指针算术表达式后,下一次循环传递给memeq的指针地址完全错误。
关键代码细节
生成的LLVM IR代码
define i32 @tarLookup(ptr %archive, ptr %filename, ptr %out) { entry: %fz = alloca i32, align 4 %ptr = alloca ptr, align 8 %archive1 = alloca ptr, align 8 store ptr %archive, ptr %archive1, align 8 %filename2 = alloca ptr, align 8 store ptr %filename, ptr %filename2, align 8 %out3 = alloca ptr, align 8 store ptr %out, ptr %out3, align 8 %archive4 = load ptr, ptr %archive1, align 8 store ptr %archive4, ptr %ptr, align 8 br label %cond cond: %ptr5 = load ptr, ptr %ptr, align 8 %tmpint = ptrtoint ptr %ptr5 to i64 %tmpextendr = sext i32 257 to i64 %tmp = add nsw i64 %tmpint, %tmpextendr %calltmp = call i1 @memeq(i64 %tmp, ptr @0, i32 5) br i1 %calltmp, label %loop, label %exit loop: ; preds = %cond %ptr6 = load ptr, ptr %ptr, align 8 %tmpint7 = ptrtoint ptr %ptr6 to i64 %tmpextendr8 = sext i32 124 to i64 %tmp9 = add nsw i64 %tmpint7, %tmpextendr8 %calltmp10 = call i32 @oct2bin(i64 %tmp9, i32 11) store i32 %calltmp10, ptr %fz, align 4 %filename11 = load ptr, ptr %filename2, align 8 %calltmp12 = call i32 @strlen(ptr %filename11) %tmp13 = add nsw i32 %calltmp12, 30 br label %cond15 cond15: ; preds = %loop %ptr16 = load ptr, ptr %ptr, align 8 %filename17 = load ptr, ptr %filename2, align 8 %filename18 = load ptr, ptr %filename2, align 8 %calltmp19 = call i1 @strlen(ptr %filename18) %calltmp20 = call i1 @memeq(ptr %ptr16, ptr %filename17, i32 %calltmp19) br i1 %calltmp20, label %if, label %exit14 if: ; preds = %cond15 %ptr21 = load ptr, ptr %ptr, align 8 %tmpint22 = ptrtoint ptr %ptr21 to i64 %tmpextendr23 = sext i32 512 to i64 %tmp24 = add nsw i64 %tmpint22, %tmpextendr23 %out25 = load ptr, ptr %out3, align 8 store i64 %tmp24, ptr %out25, align 4 %fz26 = load i32, ptr %fz, align 4 ret i32 %fz26 exit14: ; preds = %cond15 %ptr27 = load ptr, ptr %ptr, align 8 ;<--- 问题关联表达式 %fz28 = load i32, ptr %fz, align 4 %tmp29 = add nsw i32 %fz28, 511 %tmp30 = sdiv i32 %tmp29, 512 %tmp31 = add nsw i32 %tmp30, 1 %tmp32 = mul nsw i32 %tmp31, 512 %tmpint33 = ptrtoint ptr %ptr27 to i64 %tmpextendr34 = sext i32 %tmp32 to i64 %tmp35 = add nsw i64 %tmpint33, %tmpextendr34 store i64 %tmp35, ptr %ptr, align 4 br label %cond exit: ; preds = %cond ret i32 0 }
注:IR命名不够规范,后续了解到LLVM不强制要求默认命名规则。
触发问题的C语言表达式
ptr += (((filesize + 511) / 512) + 1) * 512;
可疑目标代码指令
编译器生成的目标代码中,以下指令被怀疑是问题根源:
and $0xfffffe00,%eax
即使关闭所有优化,该指令仍会生成;而用clang编译相同C代码时,不会生成这条指令。
环境与验证细节
- 目标平台:x86_64-elf
- 链接器:x86_64-elf-ld(源码编译)
- 引导加载程序:BOOTBOOT
- 验证情况:传递给
tarLookup的初始指针地址正确,第一次循环可正常运行(通过内核串口输出确认),问题明确出在上述指针算术表达式执行后。 - 调试限制:尚未给编译器添加调试信息,无法在QEMU中使用GDB调试。
相关参考
- USTAR格式规范(osdev相关文档)
- 完整生成的汇编代码
- 实现功能的C代码
内容的提问来源于stack exchange,提问作者Aryaman Jain
相关产品推荐
相关产品推荐

