我需要在 x86 程序集中添加 to 的内容CH,EAX但似乎没有地址模式支持这一点。理想情况下,我想要一个寻址模式,如:
ADD EAX,r8
或者
ADD r32,r8
或者
ADD r/m32,r8
但ADD没有任何这些模式。我无法屏蔽ECX,因为它里面有我在其他地方使用的其他垃圾,而且我已经用完了所有其他寄存器,所以我唯一的选择似乎是使用内存访问。有什么想法可以解决这个问题吗?
注意我不能使用这样的模式,r/m8,r8因为那样就没有进位了。
我需要在 x86 程序集中添加 to 的内容CH,EAX但似乎没有地址模式支持这一点。理想情况下,我想要一个寻址模式,如:
ADD EAX,r8
或者
ADD r32,r8
或者
ADD r/m32,r8
但ADD没有任何这些模式。我无法屏蔽ECX,因为它里面有我在其他地方使用的其他垃圾,而且我已经用完了所有其他寄存器,所以我唯一的选择似乎是使用内存访问。有什么想法可以解决这个问题吗?
注意我不能使用这样的模式,r/m8,r8因为那样就没有进位了。
正如您所观察到的,x86 只是没有如此灵活的寻址模式。您不能在一个步骤中将 8 位寄存器添加到 32 位寄存器。您的选择是释放寄存器和零/符号扩展然后添加 r32,r32,或者添加 r8,r8 然后在进位标志上分支以调整结果。
我建议您应该将寄存器溢出到内存中,在现代处理器上,一对内存访问比分支便宜得多(因为它将从存储缓冲区加载),并且您可以围绕溢出改写其他代码。
使用 r/m8,r8 之类的模式,并在必要时通过向 EAX 添加常量 0x100 来传播进位。
如果你溢出一个寄存器,你可以避免分支。例如,
subl $4, %esp
使用指令序列:
movl %eax, (%esp)
...
movzbl %ch, %eax
...
addl (%esp), %eax
并在最后恢复堆栈指针:
addl $4, %esp
如果这是一个问题,它可能会对调试此块中的代码的任何尝试造成严重破坏。
或者,按照 Doug Currie 的建议:
addb %ch, %al
jnc done
addl 0x100, %eax
done:
改写道格的答案(在英特尔语法中):
add al, ch
jnc no_carry
add eax, 100h
no_carry:
这很简单,对于 eax:
add al,ch
adc ah,0
rorx eax,16
adc ax,0
rorx eax,16
在第一条指令中,您添加较低部分并保留进位标志,在第二条指令中,您将进位标志添加到寄存器的较高部分。它还保留了源的内容。但请注意寄存器停顿,并将代码与其他指令混合以避免它。
添加:
add al,ch
adc ah,0
bswap eax
xchg al,ah
adc ax
xchg al,ah
bswap eax
您还可以添加 32 位值并撤消添加 24 msb:s:
add eax, ecx
xor cl,cl // also `and ecx, 0xffffff00` is possible
sub eax, ecx
这自然会破坏要添加的值,但会保留垃圾。(并重新阅读问题,实际上需要用 包围代码块xchg cl,ch,这使得解决方案对任务来说不是最佳的。)