从 MCInsts 获取"actual"寄存器 (x86)

Getting "actual" registers from MCInsts (x86)

本文关键字:x86 寄存器 actual MCInsts 获取      更新时间:2023-10-16

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

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

  • 将11587作为32位立即数移动到eax将使用MOV32ri操作码完成。文本表示将是mov eax, 11587。对应的MCInst将有两个操作数,一个寄存器和一个立即数。这对我有用。这太棒了
  • 11587添加到eax将使用ADD32ri操作码来完成。文本表示将是add eax, 11587。然而,这一次,对应的MCInst三个操作数:eax在那里两次,立即数在最后。这不太好。我可以假设这是降低过程的产物,eax的第一个实例是目标寄存器,第二个实例是源寄存器(尽管x86不区分两者),我可以绕过这一点
  • 将32位eip相对值移动到eax将使用MOV32ao32操作码来完成。文本表示将是mov eax, dword ptr [11587]。在这种情况下,MCInst甚至没有eax的操作数,只能根据操作码名称中的操作数类型推断。我也可以绕过这一点,但事情越来越不好看了,我只测试了x86支持的1300多条指令中的5-6条

显然,为了显示文本,我可以用MCInstPrinter获得文本表示,但那里显示的内容和MCInst所具有的内容之间的映射仍然很模糊。

有没有一种简单的方法来判断哪些操作数出现在指令的文本表示中?

添加三个参数听起来像是编译器构建者对"三个地址代码"的偏好正在渗透,因为在英特尔汇编程序中没有理由这样做。(您不能使用add指令将数据添加并存储到不同的寄存器中,但可以使用LEA)。

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

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

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

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

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