MC Instruction Decoder属于MC层LLVM中反汇编模块,主要功能是将输入的二进制文件读写成Bytes形式,输出为对应Target 机器指令MCInst,是反汇编中不可或缺的模块:
MCDisassembler类是MC Instruction Decoder中对外提高的接口类,属于所有target disassembler的superclass,
该类位于:llvm\include\llvm\MC\MCDisassembler\MCDisassembler.h文件
该类所接口比较少,其中最重要的一个接口:getInstruction:
- virtual DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
- ArrayRef<uint8_t> Bytes, uint64_t Address,
- raw_ostream &CStream)
该接口将可执行的二进制文件以Bytes作为输入,通过反汇编输入MCInst 机器指令。
该接口是一个虚拟函数,每个target机器指令都不同,新编写一个后端都需要以MCDisassembler为基类,派生出target 对应的disassembler,实现getInstruction接口。
AMDGPU 派生关系如下:
AMDGPUDisassembler 位于llvm\lib\Target\AMDGPU\Disassembler\AMDGPUDisassembler.h
disassembler使用方法通常分为以下几个步骤:
当新添加一个后端,需要调用RegisterMCDisassembler向Target中注册所属disassemble, AMDGPU注册位于llvm\lib\Target\AMDGPU\Disassemble\AMDGPUDisassembler.cpp:
- extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUDisassembler() {
- TargetRegistry::RegisterMCDisassembler(getTheGCNTarget(),
- createAMDGPUDisassembler);
- TargetRegistry::RegisterMCSymbolizer(getTheGCNTarget(),
- createAMDGPUSymbolizer);
- }
RegisterMCDisassembler主要注册对应 创建disassamble回调函数createAMDGPUDisassembler。
- static void RegisterMCDisassembler(Target &T,
- Target::MCDisassemblerCtorTy Fn) {
- T.MCDisassemblerCtorFn = Fn;
- }
创建disassembler回调函数注册到MCDisassemblerCtorFn。
createMCDisassembler创建对应MCDisassembler:
- MCDisassembler *createMCDisassembler(const MCSubtargetInfo &STI,
- MCContext &Ctx) const {
- if (!MCDisassemblerCtorFn)
- return nullptr;
- return MCDisassemblerCtorFn(*this, STI, Ctx);
- }
调用注册的createAMDGPUDisassemble回调函数,创建AMDGPUDisassembler。
将解析的二进制文件中Text 代码段中,转成ArrayRef<uint8_t>,进行反汇编,例如:
-
- MCInst Inst;
- bool Disassembled =
- DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
- SectionAddr + Index, CommentStream);
AMDGPU 反汇编实现位于llvm\lib\Target\AMDGPU\Disassembler\AMDGPUDisassembler.cpp文件:
实现过程思路比较清晰,反汇编主要分为两个部分:
AMDGPU后端为了支持反汇编,内部将命令划分成了多个DecoderTable,getInstruction会依次匹配查询各个DecoderTable表进行匹配,目前存在DecoderTable主要有:
以上DecoderTable有TableGen在编译阶段自动生成到build/lib/Target/AMDGPU/AMDGPUGenDisassemblerTables.inc文件中,手动生成命令:
llvm-tblgen -gen-disassembler./AMDGPU.td -I ../../../include
以DecoderTableGFX932为例说明GFX 32位 DecoderTable表:
每行开头MCD::OPC_XXXX为对应状态,以及决定后续数字值意义
例如开头 MCD::OPC_ExtractField 后续25,7为下一步跳转匹配的起始和结束位置,start=25, end=31.
decodeInstruction为根据传入的DecoderTable 表,进行反汇编解码,位于build/lib/Target/AMDGPU/AMDGPUGenDisassemblerTables.inc文件中,
根据匹配表中MCD::OPC_XXXX进行匹配操作,直到MCD::OPC_Decode 状态说明在该DecoderTable表匹配成功,否则 MCD::OPC_Fail匹配失败,尝试使用下一个DecoderTable表进行匹配
以下为例:
/* 62 */ MCD::OPC_Decode, 236, 127, 46, // Opcode: V_ADDC_CO_U32_e32_gfx9
236,127为对应求解出对应的opcode, 最高第8个bit位标志位,当置位代表该opcode大于128 需要拆分成多个,直到最高位不是1为止,计算方法如下:
(236&~128)+ 127<<7
46对应DecodeIdx,decodeToMCInst决定后续operand 寄存器解析操作:
最终将反汇编出机器指令MCInst.