为什么 SHL 到 "move" 8086 中的 2 个字节?
Why SHL to "move" 2 bytes in 8086?
我们正在使用一组有限的 8086 条指令学习汇编。
当我们在内存中有一个数组时,我们使用 SHL 在元素之间移动(取决于元素大小)。
例如,假设有一个 2 字节短裤数组。此数组位于 ES 段,第一个元素从 BX 偏移量 (ES:[BX]) 开始。
如果我们想转到下一个元素,我们使用 SHL BX,1 ,然后使用 ES:[BX] 访问它。
ADD AX, ES:[BX]
SHL BX,1
ADD AX, ES:[BX]
我不明白为什么会这样,偏移量乘以2。我们不应该给BX加2去下一个元素吗?
ADD AX, ES:[BX]
ADD BX,2
ADD AX, ES:[BX]
是的,SHL 指令移动了寄存器中的位。例如,00001111b 变为 00011110b。 SHR 向右移动。 ROL 和 ROR 循环位。由于二进制是以 2 为底,向左移动就是每移动一位乘以 2。
另一方面,如果您要使用数组,每个条目连续,我会查看 LODSW 指令。
左移是执行二进制乘法(即乘以 2 的幂)的有效方法,因此在编写汇编时常用。将值左移 1,相当于将值乘以 2 (21 = 2)。将值左移 2 相当于将该值乘以 4 (22 = 4)。依此类推,遵循明显的模式。
还有其他位操作技巧可以有效地乘以 2 的非幂,但我不会在这里讨论这些,因为它们有点复杂。要查看它们,ask a C compiler.
因此,您问题中的第一段代码不正确。您不想将指针乘以 2。
正如您所说,访问数组中下一个值的方法是将指针递增元素的大小(以字节为单位)。对于 WORD 大小的数组,这意味着将指针递增 2,这是一个简单的 ADD
指令可以做到的,就像您展示的那样:
ADD AX, ES:[BX]
ADD BX, 2
ADD AX, ES:[BX]
假设 BX
是指向数组第一个元素的指针,分配在 ES
段中,这将获取该元素的值并将其添加到 AX
.然后,它将递增 BX
以指向数组的第二个元素,并将该地址处的值添加到 AX
.
在您可能更熟悉的 C 中,这相当于:
uint16_t* ptr = ...; // ES:[BX]
uint16_t result = ...; // AX
result += *ptr;
++ptr;
result += *ptr;
请注意,C 会根据指针指向的值的大小自动递增指针。在这种情况下,由于 ptr
是指向 uint16_t
的指针,它将地址递增 2。
我们正在使用一组有限的 8086 条指令学习汇编。
当我们在内存中有一个数组时,我们使用 SHL 在元素之间移动(取决于元素大小)。
例如,假设有一个 2 字节短裤数组。此数组位于 ES 段,第一个元素从 BX 偏移量 (ES:[BX]) 开始。
如果我们想转到下一个元素,我们使用 SHL BX,1 ,然后使用 ES:[BX] 访问它。
ADD AX, ES:[BX]
SHL BX,1
ADD AX, ES:[BX]
我不明白为什么会这样,偏移量乘以2。我们不应该给BX加2去下一个元素吗?
ADD AX, ES:[BX]
ADD BX,2
ADD AX, ES:[BX]
是的,SHL 指令移动了寄存器中的位。例如,00001111b 变为 00011110b。 SHR 向右移动。 ROL 和 ROR 循环位。由于二进制是以 2 为底,向左移动就是每移动一位乘以 2。
另一方面,如果您要使用数组,每个条目连续,我会查看 LODSW 指令。
左移是执行二进制乘法(即乘以 2 的幂)的有效方法,因此在编写汇编时常用。将值左移 1,相当于将值乘以 2 (21 = 2)。将值左移 2 相当于将该值乘以 4 (22 = 4)。依此类推,遵循明显的模式。
还有其他位操作技巧可以有效地乘以 2 的非幂,但我不会在这里讨论这些,因为它们有点复杂。要查看它们,ask a C compiler.
因此,您问题中的第一段代码不正确。您不想将指针乘以 2。
正如您所说,访问数组中下一个值的方法是将指针递增元素的大小(以字节为单位)。对于 WORD 大小的数组,这意味着将指针递增 2,这是一个简单的 ADD
指令可以做到的,就像您展示的那样:
ADD AX, ES:[BX]
ADD BX, 2
ADD AX, ES:[BX]
假设 BX
是指向数组第一个元素的指针,分配在 ES
段中,这将获取该元素的值并将其添加到 AX
.然后,它将递增 BX
以指向数组的第二个元素,并将该地址处的值添加到 AX
.
在您可能更熟悉的 C 中,这相当于:
uint16_t* ptr = ...; // ES:[BX]
uint16_t result = ...; // AX
result += *ptr;
++ptr;
result += *ptr;
请注意,C 会根据指针指向的值的大小自动递增指针。在这种情况下,由于 ptr
是指向 uint16_t
的指针,它将地址递增 2。