我很好奇有多少种方法可以在x86汇编中将寄存器设置为零。使用一条指令。有人告诉我,他设法找到了至少10种方法。
我能想到的是:
xor ax,ax
mov ax, 0
and ax, 0
答案 0 :(得分:12)
如果在IA32 ...
下将0移入ax,有很多可能性 lea eax, [0]
mov eax, 0FFFF0000h //All constants form 0..0FFFFh << 16
shr eax, 16 //All constants form 16..31
shl eax, 16 //All constants form 16..31
也许最奇怪......:)
@movzx:
movzx eax, byte ptr[@movzx + 6] //Because the last byte of this instruction is 0
和...
@movzx:
movzx ax, byte ptr[@movzx + 7]
修改:
对于16位x86 cpu模式,未经测试......:
lea ax, [0]
和...
@movzx:
movzx ax, byte ptr cs:[@movzx + 7] //Check if 7 is right offset
如果 ds 段寄存器不等于cs段寄存器, cs:前缀是可选的。
答案 1 :(得分:4)
还有几种可能性:
sub ax, ax
movxz, eax, ah
编辑:我应该注意movzx
并非所有eax
都为零 - 它只是零ah
(加上无法作为寄存器访问的前16位)本身)。
至于速度最快,如果内存服务于sub
且xor
是等效的。它们比(大多数)其他人更快,因为它们很常见,CPU设计者为它们添加了特殊优化。具体而言,对于正常sub
或xor
,结果取决于寄存器中的先前值。 CPU特别识别xor-with-self和subtract-from-self,因此它知道依赖链在那里被破坏。之后的任何指令都不依赖于任何先前的值,因此它可以使用重命名寄存器并行执行上一条和后续指令。
特别是在较旧的处理器上,我们预计'mov reg,0'会因为它有额外的16位数据而变慢,大多数早期处理器(特别是8088)主要受限于它们加载流的能力从内存中 - 事实上,在8088上你可以用任何参考表完全准确地估计运行时间,并且只需要注意所涉及的字节数。对于div
和idiv
说明,这确实有所不同,但这就是它。 OTOH,我应该闭嘴,因为8088确实对任何人都没什么兴趣(现在至少十年)。
答案 2 :(得分:3)
您可以使用LOOP $
将寄存器CX设置为0。
答案 3 :(得分:1)
当然,特定情况下还有其他方法可以将寄存器设置为0:例如如果您将eax
设置为正整数,则可以使用edx
将cdq/cltd
设置为0(此技巧用于着名的24字节shellcode,出现在“不安全的编程”中例子“)。
答案 4 :(得分:1)
这个帖子已经陈旧,但还有其他一些例子。简单的:
xor eax,eax
sub eax,eax
and eax,0
lea eax,[0] ; it doesn't look "natural" in the binary
更复杂的组合:
; flip all those 1111... bits to 0000
or eax,-1 ; eax = 0FFFFFFFFh
not eax ; ~eax = 0
; XOR EAX,-1 works the same as NOT EAX instruction in this case, flipping 1 bits to 0
or eax,-1 ; eax = 0FFFFFFFFh
xor eax,-1 ; ~eax = 0
; -1 + 1 = 0
or eax,-1 ; eax = 0FFFFFFFFh or signed int = -1
not eax ;++eax = 0
答案 5 :(得分:1)
每DEF CON 25 - XlogicX - Assembly Language is Too High Level:
立即基数为0的AAD将始终将AH设为零,而将AL保持不变。从Intel's pseudocode出发:
AL ← (oldAL + (oldAH ∗ imm8)) AND FFH;
在asm来源中:
AAD 0 ; assemblers like NASM accept this
db 0xd5,0x00 ; others many need you to encode it manually
显然(至少在某些CPU上),bswap eax
前面有66个操作数大小的前缀(即尝试对66 0F C8
进行编码的bswap ax
)将AX设为零。
答案 6 :(得分:0)
mov eax,0
shl eax,32
shr eax,32
imul eax,0
sub eax,eax
xor eax,eax
and eax,0
andn eax,eax,eax
loop $ ;ecx only
pause ;ecx only (pause="rep nop" or better="rep xchg eax,eax")
;twogether:
push dword 0
pop eax
or eax,0xFFFFFFFF
not eax
xor al,al ;("mov al,0","sub al,al",...)
movzx eax,al
...