Whole Program LLVM核心代码解析:compilers.py与extraction.py工作原理
【免费下载链接】whole-program-llvmA wrapper script to build whole-program LLVM bitcode files项目地址: https://gitcode.com/gh_mirrors/wh/whole-program-llvm
Whole Program LLVM是一个用于构建全程序LLVM位码文件的包装脚本工具,通过本文你将深入了解其核心代码compilers.py与extraction.py的工作原理,掌握LLVM位码生成与提取的关键技术。
一、compilers.py:LLVM位码生成的核心驱动
compilers.py是Whole Program LLVM实现位码生成的核心模块,主要负责将源代码编译为LLVM位码文件并附加到位目标文件中。
1.1 编译器构建器设计
该模块定义了两种主要的编译器构建器:ClangBuilder和DragoneggBuilder,分别对应不同的LLVM编译方式:
class ClangBuilder(BuilderBase): def getBitcodeCompiler(self): cc = self.getCompiler() return cc + ['-emit-llvm'] + self.getBitcodeGenerationFlags() class DragoneggBuilder(BuilderBase): def getBitcodeCompiler(self): pth = os.getenv('LLVM_DRAGONEGG_PLUGIN') cc = self.getCompiler() cmd = cc + ['-B', asDir, f'-fplugin={pth}', '-fplugin-arg-dragonegg-emit-ir'] return cmdClangBuilder直接使用Clang编译器的-emit-llvm选项生成位码,而DragoneggBuilder则通过GCC插件Dragonegg实现位码生成。
1.2 位码生成与附加流程
位码生成的核心流程在buildAndAttachBitcode函数中实现,主要包括:
- 确定输入文件和输出文件
- 调用
buildBitcodeFile生成位码文件 - 通过
attachBitcodePathToObject将位码路径附加到目标文件
def buildAndAttachBitcode(builder, af): if len(af.inputFiles) == 1 and af.isCompileOnly: srcFile = af.inputFiles[0] (objFile, bcFile) = af.getArtifactNames(srcFile, hidden) buildBitcodeFile(builder, srcFile, bcFile) attachBitcodePathToObject(bcFile, objFile) else: # 处理多文件编译情况 ...位码附加通过objcopy或ld命令将位码路径信息写入目标文件的特定节(ELF的.llvm_bc节或Mach-O的__WLLVM段)中。
二、extraction.py:位码提取的实现机制
extraction.py提供了从编译产物中提取LLVM位码的功能,是Whole Program LLVM工具链的重要组成部分。
2.1 位码路径提取
根据不同操作系统,位码路径提取实现有所不同:
- Linux系统:通过
objdump命令解析ELF文件,获取.llvm_bc节的大小和偏移量,然后读取该节内容得到位码路径 - Darwin系统:使用
otool命令提取__WLLVM段的内容,经过十六进制解码得到位码路径
def extract_section_linux(inputFile): val = getSectionSizeAndOffset(elfSectionName, inputFile) if val is None: return [] (sectionSize, sectionOffset) = val content = getSectionContent(sectionSize, sectionOffset, inputFile) return content.split('\n')2.2 位码文件处理
提取到位码路径后,extraction.py提供了多种位码文件处理方式:
- 链接为单个位码模块:使用
llvm-link将多个位码文件链接为一个完整模块 - 创建位码归档:使用
llvm-ar将多个位码文件创建为归档文件 - 生成清单文件:记录所有提取到的位码文件路径
def linkFiles(pArgs, fileNames): linkCmd = [pArgs.llvmLinker] linkCmd.append(f'-o={pArgs.outputFile}') linkCmd.extend(fileNames) exitCode = executeLinker(linkCmd) return exitCode2.3 归档文件处理
对于静态库等归档文件,extraction.py提供了专门的处理逻辑:
- 提取归档中的目标文件
- 从每个目标文件中提取位码路径
- 整合所有位码文件生成位码归档或模块
三、两个模块的协同工作流程
compilers.py与extraction.py通过位码路径信息实现协同工作,形成完整的LLVM位码处理流程:
- 编译阶段:compilers.py在编译时生成位码文件,并将位码路径附加到目标文件中
- 提取阶段:extraction.py从目标文件或归档中提取位码路径,找到并处理位码文件
这种设计使得Whole Program LLVM能够无缝集成到现有的构建流程中,同时提供灵活的位码提取功能。
四、核心功能配置与扩展
Whole Program LLVM提供了丰富的环境变量配置,可灵活定制位码生成与提取过程:
LLVM_COMPILER:指定编译器类型(clang或dragonegg)LLVM_COMPILER_PATH:指定LLVM工具路径LLVM_BITCODE_GENERATION_FLAGS:添加额外的位码生成标志WLLVM_BC_STORE:指定位码文件存储目录
通过这些配置,开发者可以根据项目需求定制LLVM位码的生成与提取策略,实现全程序分析等高级应用。
五、总结
compilers.py和extraction.py作为Whole Program LLVM的核心模块,分别实现了LLVM位码的生成与提取功能。compilers.py通过封装Clang或GCC+Dragonegg编译器,在保持原有构建流程不变的情况下生成位码文件;extraction.py则提供了从编译产物中提取位码的能力,支持多种输出格式。两者协同工作,为全程序分析、静态分析等应用提供了强大的LLVM位码处理能力。
掌握这两个模块的工作原理,不仅有助于更好地使用Whole Program LLVM工具,也为理解LLVM位码生成与处理的底层机制提供了深入视角。无论是进行编译器开发还是程序分析,Whole Program LLVM都提供了一个灵活而强大的位码处理平台。
【免费下载链接】whole-program-llvmA wrapper script to build whole-program LLVM bitcode files项目地址: https://gitcode.com/gh_mirrors/wh/whole-program-llvm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考