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



旧考试中的任务(如果你不相信我,我可以提供源代码):

在不使用寄存器索引寻址的情况下更改以下汇编代码。不要使用超过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

吗?

首先,原始的寻址模式都不使用索引寄存器。[ebx+8]可以(并且将)使用EBX作为基寄存器,而不是索引寄存器,因为它可以在机器码编码中不使用SIB字节。所以寻址模式是base+ dis8,所以ModRM字节的编码将是(二进制)

  • Mod = 1(基础+ disp8)
  • r/m = 011 (ebx)
  • REG = 000 (EAX为目的寄存器)

因此ModRM字节将是0x43,如表2-2所示。带有ModR/M字节的32位寻址表单,参见Intel的指令集参考手册(卷2)(参见x86标签wiki以获取pdf的链接)。

如果EBX上有缩放因子(如[ebx*2 + 8]),则必须使用dis32 +索引寻址模式。(参见x86寻址模式)。


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

在这种情况下,第一个指令不能被加载,因为你必须先计算寄存器中的地址。通过稍后使用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