更改这个简短的汇编程序代码,使其在没有寄存器索引的情况下工作
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 的链接,请参阅 x86 标签 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
.
旧考试的作业(如果你不相信我,我可以提供来源):
在不使用寄存器索引寻址的情况下更改以下汇编代码。不要使用超过 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 的链接,请参阅 x86 标签 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
.