8086 内存到累加器编码:为什么 mov al, [absolute] 和 mov ah, [absolute] 有不同的大小?

问题描述 投票:0回答:1
mov al, [10] ; a0 0a 00
mov ah, [10] ; 8a 26 0a 00

使用 NASM 组装上述 8086 汇编代码后,我注意到生成的机器代码存在长度差异(如上面的注释所示,第一个是 3 个字节,另一个是 4 个字节)。两条指令如此相似,为什么会出现这种差异?

enter image description here

从8086手册来看,第一条指令似乎是使用内存到累加器编码来组装的,第二条指令是使用内存到寄存器编码来编码的。

我是汇编新手,所以我确信我遗漏了一些东西,但是为什么第二条指令需要用 mem 编码到 reg 而不是 mem 到累加器? AH不还是累加器寄存器吗?

assembly x86-16 disassembly machine-code instruction-encoding
1个回答
0
投票

AH 不是 8 位版本的“累加器”,而是 AL。

没有 ModRM 字节的特殊情况编码需要操作码来暗示寄存器操作数。 对于方向和操作数大小(加载/存储、8 位和 16 位)的每个组合,只有一个这样的操作码,因此没有剩余位来编码 AH 与 AL。

a0
操作码意味着目标寄存器是AL。 没有暗示 AH 并采用 16 位绝对地址的操作码,因此实际上唯一的选择是 8 位操作数大小的操作码
mov r, r/m

8位累加器也是如此,立即运算

test al, imm8
sub al, imm8
为2字节,仅针对AL进行特殊编码。
(有关历史的一些信息,请参阅我的codegolf x86机器代码提示答案。我认为其他人也写过一些可能的设计原因,例如8080 asm源代码的高效机械翻译,因为8080是累加器机器,其中大多数ALU指令只能对累加器执行操作,8位A。即使是8086也有一些指令只能对累加器起作用,包括符号扩展,因此花费8
xchg
reg 上的操作码字节与累加器 (AX))


英特尔当前的手册仍然适用于 16 位模式,并且是可搜索的文本,而不仅仅是倾斜的图片:P https://www.felixcloutier.com/x86/mov 是 PDF 的 HTML 抓取SDM 第 2 卷中的 MOV 条目。
令人困惑的是,

moffs8
是带有绝对地址的8位操作数大小;地址大小是该模式的默认大小,而不是 8 位。 所以相关条目是
A0  MOV AL, moffs8

在 386 及更高版本上,

66
字节是操作数大小前缀,可与 16 位操作数大小操作码一起使用以使操作数大小为 32 位。 如果模式的默认值是 32 位,则相反。 并且
67
字节使地址大小与模式的默认大小相反,例如如果处于 16 位模式,则为 32 位地址;如果处于 32 位模式,则为 16。 不管怎样,要点是你会看到
MOV AX, moffs16
MOV EAX, moffs32
具有相同的
A1
操作码,并且取决于你正在组装的模式(
bits 16
bits 32
bits 64
),汇编器将使用
66h
前缀字节或不使用所需的操作数大小。

知道,英特尔当前的手册应该是可读的,并且它使用特定的寄存器名称,而不仅仅是“累加器”,因为它具有带有确切操作码字节的单独条目,而不是在表中留下通配符

w
位。 这使得阅读起来更加臃肿,并且对于查看模式的帮助较小(例如宽度和方向通常是低 2 位),但确实消除了“累加器”等术语含义的任何歧义。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.