8086 中通用寄存器之间的差异:[bx] 有效,[cx] 无效?
Differences between general purpose registers in 8086: [bx] works, [cx] doesn't?
在8086中这个结构是正确的:
mov bh,[bx]
但这不正确:
mov bh,[cx]
我不知道为什么。我认为通用寄存器(AX、BX、CX、DX、SP、BP、SI 和 DI)是我们可以用于任何目的的寄存器,BX 用于基地址或 CX 用于计数器的声明只是一个约定,它们根本没有区别。但似乎我错了。你能解释一下原因吗?这些寄存器之间的确切区别是什么? (比如为什么不能在cx寄存器中保存基地址?)
在 8086(和 x86 中的 16 位寻址)上,只有以下寻址模式可用:
[bx] [bx + foo]
[foo] [bp + foo]
[si] [si + foo]
[di] [di + foo]
[bx + si] [bx + si + foo]
[bx + di] [bx + di + foo]
[bp + si] [bp + si + foo]
[bp + di] [bp + di + foo]
其中 foo
是某个常数值,例如123
或段内符号的偏移量,例如文字 foo
在某处引用 foo:
标签。 (有趣的事实:编码 [bp]
的唯一方法实际上是 [bp+0]
,汇编器会为你做这个。注意 table [foo]
是 [bp]
否则会是;这反映了 x86 机器代码如何将编码表示为没有寄存器的位移的特殊情况。)
bp
作为基础意味着 SS(堆栈)段;其他寻址模式暗示 DS(数据)段。如有必要,可以用前缀覆盖。
请注意,不存在涉及 cx
的寻址模式,因此 [cx]
不是有效的内存操作数。
寄存器 ax、cx、dx、bx、sp、bp、si 和 di 被称为通用寄存器,因为它们在所有通用指令中都可以作为操作数访问.这与特殊用途的寄存器如 es、cs、ss、ds(段寄存器)、ip(指令指针)或标志寄存器形成对比,这些寄存器只能通过为此目的制定的特殊指令访问。
如您所见,并非所有通用寄存器都可以用作内存操作数的变址寄存器。注册代码时必须牢记这一点。
除此限制外,还有一些指令隐式操作固定寄存器。例如,loop
指令只对 cx
进行操作,而 16 位 imul r/m16
只对 dx:ax
进行操作。如果您想有效地使用这些指令,请牢记每个通用寄存器的建议用途。
值得注意的是,lods
/ stos
/ scas
/ movs
/ cmps
use DS:SI or/and ES:DI implicitly, and on cx
when used with a rep
or repz
/ repnz
prefix,因此那些用于在数组上循环指针的寄存器允许代码大小优化。
General purpose 是指这些寄存器可以作为"general purpose instructions"的操作数,例如mov
或add
.
然而,所有这些寄存器至少具有一项特殊功能(列表不完整):
ax
始终为 mul
/ div
操作提供输入并接收结果
ax
因为默认的累加器寄存器有一些更短的各种指令编码
bx
是四个寄存器(bx
、bp
、di
、si
)之一,可用于间接内存寻址在 16 位寻址模式下。
cx
被多个指令用作计数器,例如移位计数、loop
和 rep
dx
包含 16 位到 32 位乘法结果的高位,以及 32 位到 16 位除法中输入的高位
sp
受push
和pop
指令以及各种call
和ret
类型控制传输指令的影响和使用。也被硬件中断异步使用。
bp
受 enter
和 leave
指令的影响。 (但不要使用enter
,它很慢)。
si
和di
被movsb
等字符串指令使用
在8086上,只有以下寻址方式可用。总共有17个。一般来说,写同一个地址的方法不止一种。例如 [a][b][c]
可能是 [a + b + c]
.
的有效表示
segment:[a]
表示地址[a]
是相对于一个段地址segment
。 (有关详细信息,请参阅下文 link。)
# Displacement
[foo]
# Register, Indirect
[bx] = ds:[bx]
[bp] = ss:[bp]
[si] = ds:[si]
[di] = ds:[di]
# Indexed Addressing
foo[bx] = [bx + foo] = ds:[bx + foo]
foo[bp] = [bp + foo] = ss:[bp + foo]
foo[si] = [si + foo] = ds:[si + foo]
foo[di] = [di + foo] = ds:[di + foo]
# where ds:[] indicates the base address, given by the 16
# bit base offset register `ds` (or `ss`)
# The 8086 uses a 20 bit addressing mode of which the high
# 16 bits are set by the segment offset and the low 16 bits
# are set by the bx, bp, si and di registers. The calculated
# address is non-unique, as 12 of the 16 bits from each register
# overlap. See the Intel programmers manual for more details
# Based Indexed Addressing
[bx + si] = ds:[bx + si]
[bx + di] = ds:[bx + di]
[bp + si] = ss:[bp + si]
[bp + di] = ss:[bp + si]
# the data segment is used for addressing modes intended for use with
# data (the first two in this list)
# the stack segment is used for addressing modes intended for use with
# the stack (the last two in this list)
# Displacement + Based Indexed
foo[bx + si] = ds:[bx + si + foo]
foo[bx + di] = ds:[bx + di + foo]
foo[bp + si] = ss:[bp + si + foo]
foo[bp + di] = ss:[bp + di + foo]
# These are the same as above with an additional offset `foo`
foo
是一些任意值。请注意,不存在涉及 cx
的寻址模式,因此 [cx]
不是有效的内存操作数。
在8086中这个结构是正确的:
mov bh,[bx]
但这不正确:
mov bh,[cx]
我不知道为什么。我认为通用寄存器(AX、BX、CX、DX、SP、BP、SI 和 DI)是我们可以用于任何目的的寄存器,BX 用于基地址或 CX 用于计数器的声明只是一个约定,它们根本没有区别。但似乎我错了。你能解释一下原因吗?这些寄存器之间的确切区别是什么? (比如为什么不能在cx寄存器中保存基地址?)
在 8086(和 x86 中的 16 位寻址)上,只有以下寻址模式可用:
[bx] [bx + foo]
[foo] [bp + foo]
[si] [si + foo]
[di] [di + foo]
[bx + si] [bx + si + foo]
[bx + di] [bx + di + foo]
[bp + si] [bp + si + foo]
[bp + di] [bp + di + foo]
其中 foo
是某个常数值,例如123
或段内符号的偏移量,例如文字 foo
在某处引用 foo:
标签。 (有趣的事实:编码 [bp]
的唯一方法实际上是 [bp+0]
,汇编器会为你做这个。注意 table [foo]
是 [bp]
否则会是;这反映了 x86 机器代码如何将编码表示为没有寄存器的位移的特殊情况。)
bp
作为基础意味着 SS(堆栈)段;其他寻址模式暗示 DS(数据)段。如有必要,可以用前缀覆盖。
请注意,不存在涉及 cx
的寻址模式,因此 [cx]
不是有效的内存操作数。
寄存器 ax、cx、dx、bx、sp、bp、si 和 di 被称为通用寄存器,因为它们在所有通用指令中都可以作为操作数访问.这与特殊用途的寄存器如 es、cs、ss、ds(段寄存器)、ip(指令指针)或标志寄存器形成对比,这些寄存器只能通过为此目的制定的特殊指令访问。
如您所见,并非所有通用寄存器都可以用作内存操作数的变址寄存器。注册代码时必须牢记这一点。
除此限制外,还有一些指令隐式操作固定寄存器。例如,loop
指令只对 cx
进行操作,而 16 位 imul r/m16
只对 dx:ax
进行操作。如果您想有效地使用这些指令,请牢记每个通用寄存器的建议用途。
值得注意的是,lods
/ stos
/ scas
/ movs
/ cmps
use DS:SI or/and ES:DI implicitly, and on cx
when used with a rep
or repz
/ repnz
prefix,因此那些用于在数组上循环指针的寄存器允许代码大小优化。
General purpose 是指这些寄存器可以作为"general purpose instructions"的操作数,例如mov
或add
.
然而,所有这些寄存器至少具有一项特殊功能(列表不完整):
ax
始终为mul
/div
操作提供输入并接收结果ax
因为默认的累加器寄存器有一些更短的各种指令编码bx
是四个寄存器(bx
、bp
、di
、si
)之一,可用于间接内存寻址在 16 位寻址模式下。cx
被多个指令用作计数器,例如移位计数、loop
和rep
dx
包含 16 位到 32 位乘法结果的高位,以及 32 位到 16 位除法中输入的高位sp
受push
和pop
指令以及各种call
和ret
类型控制传输指令的影响和使用。也被硬件中断异步使用。bp
受enter
和leave
指令的影响。 (但不要使用enter
,它很慢)。si
和di
被movsb
等字符串指令使用
在8086上,只有以下寻址方式可用。总共有17个。一般来说,写同一个地址的方法不止一种。例如 [a][b][c]
可能是 [a + b + c]
.
segment:[a]
表示地址[a]
是相对于一个段地址segment
。 (有关详细信息,请参阅下文 link。)
# Displacement
[foo]
# Register, Indirect
[bx] = ds:[bx]
[bp] = ss:[bp]
[si] = ds:[si]
[di] = ds:[di]
# Indexed Addressing
foo[bx] = [bx + foo] = ds:[bx + foo]
foo[bp] = [bp + foo] = ss:[bp + foo]
foo[si] = [si + foo] = ds:[si + foo]
foo[di] = [di + foo] = ds:[di + foo]
# where ds:[] indicates the base address, given by the 16
# bit base offset register `ds` (or `ss`)
# The 8086 uses a 20 bit addressing mode of which the high
# 16 bits are set by the segment offset and the low 16 bits
# are set by the bx, bp, si and di registers. The calculated
# address is non-unique, as 12 of the 16 bits from each register
# overlap. See the Intel programmers manual for more details
# Based Indexed Addressing
[bx + si] = ds:[bx + si]
[bx + di] = ds:[bx + di]
[bp + si] = ss:[bp + si]
[bp + di] = ss:[bp + si]
# the data segment is used for addressing modes intended for use with
# data (the first two in this list)
# the stack segment is used for addressing modes intended for use with
# the stack (the last two in this list)
# Displacement + Based Indexed
foo[bx + si] = ds:[bx + si + foo]
foo[bx + di] = ds:[bx + di + foo]
foo[bp + si] = ss:[bp + si + foo]
foo[bp + di] = ss:[bp + di + foo]
# These are the same as above with an additional offset `foo`
foo
是一些任意值。请注意,不存在涉及 cx
的寻址模式,因此 [cx]
不是有效的内存操作数。