我正在使用llvm-mc,目的是制作一个相对聪明的反汇编程序(识别和跟踪本地人,轻松跟踪分支等),其中一部分是创建反汇编指令的字符串表示 .
当我开始这个时,我希望我能够相对容易地识别 MCInst
使用的寄存器和值,然后用我可以轻松处理的另一个表示法 . 然而,经过一些调查,我意识到用指令的文本表示显示的操作数与实际存在于 MCInst
对象中的操作数之间的相关性相当低 . 以下是一些示例(英特尔语法):
-
将11587作为32位立即移动到
eax
将使用MOV32ri
操作码完成 . 文字表示将是mov eax, 11587
. 相应的MCInst
将有两个操作数,一个寄存器和一个立即数 . 这适合我 . 这很棒 . -
将
11587
添加到eax
将使用ADD32ri
操作码完成 . 文字表示将是add eax, 11587
. 但是,这次,相应的MCInst
有三个操作数:eax
有两次,而最后是立即数 . 这不是很好 . 我可以假设这是降级过程的一个工件,eax
的第一个实例是目标寄存器,第二个实例是源(即使x86不区分两者),我可以破解在那附近 . -
使用
MOV32ao32
操作码将32位eip
-relative值移动到eax
. 文字表示将是mov eax, dword ptr [11587]
. 在这种情况下,MCInst
甚至没有eax
的操作数,它只能从操作码名称中的操作数类型推断出来 . 我也可以解决这个问题,但事情越来越少,我只测试了x86支持的1300个不同的指令 .
显然,为了显示文本,我可以用 MCInstPrinter
获得文本表示,但是那里显示的内容和 MCInst
之间的映射仍然很混乱 .
是否有一种直接的方法来判断哪些操作数出现在指令的文本表示中?
2 回答
添加三个参数听起来像Three address code的编译器构建器首选项正在流行,因为在英特尔汇编程序中没有理由这样做 . (您不能使用ADD指令添加和存储到不同的寄存器,但您可以使用LEA) .
如果计算所有扩展(如SSE,FPU等),操作码将达到数百个,更糟糕的是,由于寻址模式和前缀,操作码有多种变体 .
NASM汇编程序在源代码中有一些表,如果你的llvm-mc系统没有提供功能,你可以尝试挖掘它们 .
MC级别非常低,操作数布局取决于操作码 . 也就是说,有一些映射表可以告诉你它在哪里 . MCInstrDesc和MCOperandInfo将告诉您哪些操作数和源和目标,它们是立即数,寄存器等以及一组标志 .
您还需要熟悉MCRegisterClass和MCRegisterInfo以及其他一些东西 . 这是一个复杂的界面,因为表示任意目标信息的任务很复杂 .
我会看一下各种基于MC的工具的代码 . 你不应该需要自己的代表,MC应该拥有你需要的一切 .