从MCInsts获取“实际”寄存器(x86)

时间:2013-12-06 05:39:48

标签: c++ assembly x86 llvm

我正在使用llvm-mc,目的是制作一个相对智能的反汇编程序(识别和跟踪本地人,轻松跟踪分支等),其中一部分是创建反汇编指令的字符串表示。

当我开始这个时,我希望我能够相对容易地识别MCInst使用的寄存器和值,并自己掏出另一个我可以轻松使用的表示。然而,经过一些调查,我意识到显示的操作数与指令的文本表示和实际存在于MCInst对象中的操作数之间的相关性相当低。以下是一些示例(英特尔语法):

  • 将{115>作为32位立即转移到eax将使用MOV32ri操作码完成。文本表示将是mov eax, 11587。相应的MCInst将有两个操作数,一个寄存器和一个立即数。这适合我。这很棒。
  • 使用11587操作码可以将eax添加到ADD32ri。文本表示将是add eax, 11587。但是,这次,相应的MCInst三个操作数:eax有两次,而最后一次是立即数。这不是很好。我可以假设这是降级过程的一个工件,eax的第一个实例是目标寄存器,第二个实例是源(即使x86不区分这两个),我可以解决这个问题。
  • 使用eip操作码将32位eax - 相对值移至MOV32ao32。文本表示将是mov eax, dword ptr [11587]。在这种情况下,MCInst甚至没有eax的操作数,它只能从操作码名称中的操作数类型推断出来。我也可以解决这个问题,但事情变得越来越少,我只测试了x86支持的1300多个不同的指令。

显然,为了显示文字,我可以用MCInstPrinter得到文本表示,但是那里显示的内容与MCInst之间的映射仍然很混乱。

是否有一种直接的方法来判断哪些操作数出现在指令的文本表示中?

2 个答案:

答案 0 :(得分:1)

添加三个参数听起来像Three address code的编译器构建器首选项正在流行,因为在英特尔汇编程序中没有理由这样做。 (您不能使用ADD指令添加和存储到不同的寄存器,但您可以使用LEA)。

如果计算所有扩展(如SSE,FPU等),操作码将达到数百个,更糟糕的是,由于寻址模式和前缀,操作码有多种变体。

NASM汇编程序在源代码中有一些表,如果你的llvm-mc系统没有提供这些功能,你可以尝试挖掘它们。

答案 1 :(得分:0)

MC级别非常低,操作数布局取决于操作码。也就是说,有一些映射表可以告诉你它在哪里。 MCInstrDesc和MCOperandInfo将告诉您哪些操作数和源和目的地,它们是立即数,寄存器等以及一组标志。

你还需要熟悉MCRegisterClass和MCRegisterInfo以及其他一些东西。这是一个复杂的界面,因为表示任意目标信息的任务很复杂。

我会看一下各种基于MC的工具的代码。你不应该需要自己的代表,MC应该拥有你需要的一切。