更改这个简短的汇编程序代码,使其在没有寄存器索引的情况下工作

Change this short assembler code so it works just without register-indexed

旧考试的作业(如果你不相信我,我可以提供来源):

在不使用寄存器索引寻址的情况下更改以下汇编代码。不要使用超过 4 条指令。

mov eax, [ebx+8]
add eax, 1
add ebx, 8
mov [ebx], eax

我已将其更改为:

mov eax, [ebx]
add eax, 9
add ebx, 8
mov [ebx], eax

我无法想象它会如此轻松地完成,这就是我不确定的原因:D

如果我所做的是正确的,另一种选择是:

mov eax, [ebx]
add eax, 1
add ebx, 16
mov [ebx], eax

还是现在完全错了?非常感谢大家!

编辑:更正版本:

mov eax, [ebx]
add [ebx], 9
add ebx, 8
mov [ebx], eax

现在?

首先,none原来的寻址方式都是使用变址寄存器。 [ebx+8] 可以(并且将)使用 EBX 作为基址寄存器,而不是索引寄存器,因为它可以在机器代码编码中没有 SIB 字节的情况下做到这一点。所以寻址方式是base+disp8,所以ModRM字节的编码就是(二进制)

  • Mod=01 (base+disp8)
  • R/M = 011 (EBX)
  • REG = 000(EAX 作为寄存器目的地)

因此 ModRM 字节将为 0x43,根据 Table 2-2。 Intel 的指令集参考手册(第 2 卷)中的 ModR/M 字节 的 32 位寻址形式。 (有关 PDF 的链接,请参阅 标签 wiki)。

如果EBX上有比例因子(如[ebx*2 + 8]),则必须使用disp32+索引寻址方式。 (另请参阅 )。


大概你的意思是你不能在你的寻址模式中使用位移。

在那种情况下,第一条指令不能作为加载,因为你必须先计算寄存器中的地址。通过稍后使用 ADD 指令计算您需要作为地址的相同 ebx+8 值,该问题对您来说很容易。所以您可以重新排序,而不必修改 EBX 两次。

add ebx, 8
mov eax, [ebx]
add eax, 1
mov [ebx], eax

或更慢但指令更少:

add   ebx, 8
add   dword [ebx], 1     ; read-modify-write
mov   eax, [ebx]         ; and then reload

x86有很多奇葩的指令,其中就包括XADD。你甚至可以这样做:

                           ; LEA ebx, [ebx+8]  might count as breaking the rules, even though it's not a load.
sub   ebx, -8              ; use a different instruction just for variety.  
mov   eax, 1
xadd  dword [ebx], eax     ; read-modify-write, leaving the old value in eax
inc   eax                  ; do the same add again, so the register matches what xadd put into memory.

但是不要这样做。 XADD 比普通的简单指令慢。它的主要目的是多线程同步。 C++11 的 std::atomic::fetch_add 与 XADD 实现的操作相同,因此 fetch_add() 可以在 x86 上高效地编译为 lock xadd.