如何获取Zephyr OS单个文件的LLVM IR以开展静态分析?
获取Zephyr单个源文件的LLVM IR方法
我之前在做Zephyr静态分析时也碰到过一模一样的问题——单个源文件没法直接编译,必须依赖完整编译流程生成的配置和头文件。下面几个方法亲测有效,你可以根据自己的需求选:
方法1:从完整编译日志提取单文件编译命令
这是最直接的方式,不需要额外工具:
- 先完成一次目标板卡+应用的完整编译,比如针对qemu_x86的hello_world:
west build -b qemu_x86 samples/hello_world - 重新编译并保存完整日志(包含所有编译命令):
west build -b qemu_x86 samples/hello_world 2>&1 > zephyr_build_log.txt - 在日志里找到你想要处理的源文件对应的编译行(比如
src/main.c),把输出参数从生成.o文件改成生成LLVM IR:
原命令大概长这样:
修改后:clang -D__ZEPHYR__=1 -I<一堆头文件路径> -c src/main.c -o build/zephyr/src/main.oclang -D__ZEPHYR__=1 -I<一堆头文件路径> -S -emit-llvm src/main.c -o main.ll - 直接运行修改后的命令,就能得到该文件的LLVM IR了。
方法2:利用编译数据库(compile_commands.json)
Zephyr支持生成编译数据库,里面记录了所有源文件的完整编译参数,适合批量处理:
- 编译时开启生成编译数据库:
west build -b qemu_x86 samples/hello_world -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - 编译完成后,
build/zephyr/compile_commands.json就会生成。你可以用jq提取目标文件的编译参数,然后生成IR:
如果你的系统没有# 替换成你要处理的源文件路径 TARGET_FILE="src/main.c" # 提取编译命令并修改输出为LLVM IR CLANG_CMD=$(jq -r ".[] | select(.file == \"$TARGET_FILE\") | .command" build/zephyr/compile_commands.json) # 替换生成.o的参数为生成IR的参数 MODIFIED_CMD="${CLANG_CMD/-o *.o/-S -emit-llvm -o $(basename $TARGET_FILE .c).ll}" # 执行命令 $MODIFIED_CMDjq,也可以手动打开compile_commands.json,找到目标文件的command字段,按照方法1的方式修改参数。
方法3:手动搭建单文件编译环境(适合定制化需求)
如果需要更灵活的控制,可以手动收集所有依赖:
- 先完成一次完整编译,确保
build/zephyr/include/generated/下的自动生成头文件(比如autoconf.h、offsets.h)都已生成。 - 收集该源文件的所有编译选项:
- 头文件路径:从编译日志或compile_commands.json里提取所有
-I开头的参数 - 宏定义:提取所有
-D开头的参数 - 架构相关参数:比如x86的
-m32,ARM的-mthumb等
- 头文件路径:从编译日志或compile_commands.json里提取所有
- 手动拼接clang命令生成IR:
clang -S -emit-llvm \ -Ibuild/zephyr/include \ -Ibuild/zephyr/include/generated \ -I<其他依赖头文件路径> \ -D__ZEPHYR__=1 \ -D<其他宏定义> \ -m32 \ src/main.c \ -o main.ll
注意事项
- 必须针对目标板卡完成一次完整编译,因为自动生成的头文件和配置都是板卡相关的,不同板卡的参数差异很大。
- 如果原来用gcc编译,建议改成clang编译(添加
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++到west build命令),这样生成的编译命令本身就是clang的,避免参数兼容问题。 - 部分源文件可能依赖Zephyr的库函数,但生成LLVM IR只需要编译该文件本身,不需要链接,所以不会影响IR的生成。
内容的提问来源于stack exchange,提问作者kratos
相关产品推荐
相关产品推荐

