【问题标题】:Why does `add cl, 2` print `80 c1 02` in x86 hex?为什么`add cl, 2`以x86 hex打印`80 c1 02`?
【发布时间】:2021-01-28 01:39:20
【问题描述】:

试图缩小我的问题范围,以便我能够克服这个障碍。 This 对我帮助不大。

我正在运行 NASM 以查看程序集的输出以十六进制表示。

test:
    @nasm -f macho64 test.asm
    @objdump -x86-asm-syntax=intel --full-leading-addr -d test.o
.PHONY: test

我有一些东西,其中之一是:

add cl, 2

输出为:

80 c1 02

查看Intel Manuals,我转到添加部分,它显示如下:

80 /0 ib

看起来很接近,80 在那里,ib 是我的号码 2 即时值。但是如何从/0 中计算出这个c1

文档说:

/digit — 0 到 7 之间的数字表示指令的 ModR/M 字节仅使用 r/m(寄存器或内存)操作数。 reg 字段包含提供指令操作码扩展的数字。

我的问题是:

  1. 为什么汇编器决定在这里放一个 ModR/M 字节?
  2. “仅使用 r/m(寄存器或内存)操作数”是什么意思?什么操作数,是说它承认有一个寄存器cl和一个立即数2,所以它选择cl,因为它是一个寄存器?
  3. “reg 字段包含提供指令操作码扩展的数字。”唔?这是什么意思?我只能从中收集到,/0 意味着它是第 0 个寄存器?但这行不通,似乎是错误的。
  4. 表 2-1 中有值c1,它与“有效地址”标题下的cl 寄存器对齐。虽然不知道那是什么意思。对应的 R/M 位就在001,它所在的列是0。虽然这些对我来说都没有多大意义。

我如何说服自己这个c1 字节是正确的?我如何阅读各种表格中的所有标志,我如何仅通过查看组件和 Intel 表格来自行推断?

【问题讨论】:

标签: assembly x86 machine-code


【解决方案1】:
  1. 因为80 /0 ibOp/En 表示MI,这表示Operand1 在MODRM:r/m 中。
  2. 这意味着它只使用 modr/m 的“r/m”部分而不是“reg”部分。
  3. 表示“reg”部分包含一个常量0 作为操作码扩展。
  4. 您查看 modr/m 表 2-2,它有一个标题行,上面写着“/digit (Opcode)”。因此,由于/0,您选择了0 列。然后选择ECX/CX/CL/MM1/XMM1 行,瞧,你得到了C1 值。

【讨论】:

  • 好吧,第 4 点越来越清楚,但我还是不明白第 2 点和第 3 点。
  • 见2.1章开头的图2-1。 modr/m 字节由 3 个字段组成,modreg/opcoder/m。一些指令使用reg 来编码一个额外的寄存器操作数,在你的情况下,其他指令使用它作为一个操作码扩展。
  • 你怎么知道这个案例使用它作为操作码扩展?
  • /0 的定义就是这个意思。请参阅第 3.1.1.1 节:"/digit 0 到 7 之间的数字表示指令的 ModR/M 字节仅使用 r/m(寄存器或内存)操作数。reg 字段包含提供指令操作码的扩展。” 此外,从逻辑上讲,“reg”字段中没有要编码的内容 - 一个操作数来自 r/m,另一个是简单附加的立即字节。
  • @LancePollard: What does the /4 mean in FF /4?How to read the Intel Opcode notation 上的答案都引用了手册的那部分内容。我对最后一个问题的回答在不引用手册的情况下解释了这一切,因为另一个答案已经转储了该手册部分。所以这个信息已经在 Stack Overflow 上流传,供未来的读者在答案中找到,而不仅仅是 cmets。
猜你喜欢
  • 1970-01-01
  • 2020-02-03
  • 2015-01-05
  • 2014-05-21
  • 2021-12-08
  • 1970-01-01
  • 2023-02-13
  • 2014-05-05
  • 2013-11-02
相关资源
最近更新 更多