【问题标题】:x86 Assembly: How do Disassemblers know how to break up instructions?x86 汇编:反汇编程序如何知道如何分解指令?
【发布时间】:2011-04-28 09:04:16
【问题描述】:

x86 反汇编器如何知道在哪里分解指令?

我正在查看8088 指令集。例如,移动指令有 7 个变体,范围从 2 到 4 个字节。说明本身似乎没有特定的顺序。 Why is x86 ugly? 的另一个原因。

例如:

                        76543210  76543210  76543210  76543210
reg/mem to/from reg     100010dw  ||regr/m  
imm to reg/mem          1100011w  ||000r/m  dat       dat w=1
imm to reg              1011wreg  data      dat w=1
imm to accum            1010000w  addr-low  addrhigh
accum to mem            1010001w  addr-low  addrhigh
reg/mem to seg          10001100  ||0ssr/m
seg to reg/mem          10001100  ||0ssr/m

Legend:
||=mod {NO-DISP=0,DISP-LOW,DISP-HIGH,REG}
ss=seg enum{es=0,cs,ss,ds}
reg=enum{ax=0,bx,cd,dx,bx,sp,bp,si,di (if w=1)} enum{al,bl...} (if w=0)
r/m=reg or mem (mod=3 then REG, else mem)

许多指令可以在第一个字节重叠:

                        76543210  76543210  76543210  76543210
push                    11111111  ||110r/m
inc                     1111111w  ||000r/m

位掩码似乎具有任意分配。反汇编程序如何分解指令?

这个问题是How to write a disassembler.的子集

【问题讨论】:

标签: assembly x86 disassembly


【解决方案1】:

查看我的 8086/8088 用户手册程序员参考 (ISBN 1-55512-010-5),可能已绝版数十年...附录 A 显示了操作码顺序 0b00000000 到 0b11111111 的指令解码。看起来一点也不混乱。 Add、sub、and、xor、cmp 等都以这样一种方式分组,即多路复用器可以直接使用操作码位来路由输入和输出,而其他位选择 alu 对这些位执行的操作。

在编写反汇编程序时,您希望使用这种表格或操作码图表对指令进行顶级排序。

在您的特定示例中,请注意,每当您看到第一个操作码为 0xFF 时,第二个字节中间的三个位会告诉您故事的其余部分,即哪个指令是哪个。所有 8 种组合(一个未定义)都可以从这 3 位表示并轻松解码。

是的,x86 指令集很疯狂。有趣且有趣的功能,但从那以后发明了更好的指令集。例如,x86 没有像 6502 那样走的唯一原因是动力,而不是质量。

你也应该看看这个:

How are hex sequence translated to assembly without ambiguity?

如何反汇编这个和任何其他可变字长指令集是按执行顺序进行的。如果您尝试按地址顺序线性执行,您将失败。从向量表开始获取入口地址,然后按地址顺序遵循这些指令,记下并遵循所有分支,直到您遇到无条件分支或返回或其他终止该指令串的指令。对每个分支目的地重复此操作。这不会涵盖所有可能的指令,因为代码可能会在执行时计算地址(您对反汇编无能为力)。

如果此代码中的任何代码是有意或无意地手写以使反汇编程序出错,您可能会发生冲突,其中基于一个执行路径的一个操作码的第二个或第三个字节似乎是基于一个指令的第一个操作码不同的执行路径。例如,如果标志被清除,则清除标志指令后跟条件分支,然后是数据字节,然后是作为分支目标的真实指令。是的,我遇到过这个。它应该被你的反汇编程序捕获,当它们发生冲突时,你需要检查以停止反汇编这些执行路径中的一个或两个。对于完全反汇编,期望必须支持某种用户输入以将地址排除为操作码,以及让用户手动添加有效的操作码,以便您遵循执行路径。

对于固定长度的指令集,您可以轻松地按地址或执行顺序进行反汇编,您的选择,从 0 到内存末尾的地址顺序当然是最简单的。不要在未定义的指令上出错,只需将它们标记为这样并继续,其中一些是数据。

x86 绝对是我尝试反汇编的最后一个可变长度指令集,并且我编写了许多反汇编程序。不想尝试那个项目。从一些固定长度的开始,比如图片和手臂/拇指。尝试可变字长的 msp430,然后可能是 6502(小行星、豪华小行星、月球着陆器等)。可能需要一两个星期的晚上来涵盖以上内容并感受它,然后如果欲望仍然存在,则攻击 x86。如果您将自己严格限制在 8088/8086 上,那还不错,需要确保您的工具正在生成这些指令,而不是进入 386 on up 指令。

如果 push vs inc 让您感到困扰,请务必先尝试其他类似 msp430 的产品。

【讨论】:

  • 非常感谢您提供详细的描述性答案。事情开始变得更有意义了。 OP Code map 让我想起了 EBCDIC mlsite.net/8086/#tbl_oper (8086 Map)。它不再显得那么随意了。我试图将其设想为线性或设置位掩码来标记指令类型。本站提供用 Python 编写的反汇编程序:mlsite.net/blog/?p=58
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-04
  • 2011-07-08
  • 2013-08-11
  • 2015-06-29
  • 1970-01-01
相关资源
最近更新 更多