我目前正在学习汇编x86,我为自己做了一个小任务。
C代码:
if (a == 4711) { a = a + 2 } else
{ a = a - 2 }
汇编代码(eax
是一个寄存器,cmp
是比较,如果不相等则jne
是跳跃,如果相等则跳jmp
}:
mov eax, a
cmp eax, 4711
jmp equal
equal: add eax, 2
jne unequal
unequal: sub eax, 2
我认为比这更有效:
mov eax, a
cmp eax, 4711
jne unequal
add eax, 2
unequal: sub eax, 2
编辑:
mov eax, a
cmp eax, 4711
jne unequal
equal: add eax, 2
jmp continue
unequal: sub eax, 2
continue: ...
我是否正确翻译了它?
答案 0 :(得分:1)
不。
在第一种情况下,你的jne unequal
什么都不做,因为无论如何控制都会去那里。您需要在之后跳转到。
在你的第二种情况下,如果比较为真,你加减2,什么也不做。
您也不会将结果存储回原始值的位置,只需将其保留在eax
。
答案 1 :(得分:1)
除了一件事,你的编辑是正确的。
mov eax, a
将“a”的地址移动到eax中,而不是内容/值
<小时/> 这个简短的片段是在Ubuntu 16.04 elf64上使用NASM完成的
section .text
global _start
_start
mov eax, a
cmp eax, 4711
jnz unequal
add eax, 2
jmp Done
unequal:
sub eax, 2
Done: mov [a], eax
section .rodata
a dd 180308
它反汇编;
00400080 B89C004000 mov eax,0x40009c
00400085 3D67120000 cmp eax,0x1267
0040008A 7505 jnz 0x400091
0040008C 83C002 add eax,byte +0x2
0040008F EB03 jmp short 0x400094
00400091 83E802 sub eax,byte +0x2
00400094 8904259C004000 mov [0x40009c],eax
变量“a”住在这里
0040009C 54C00200
请注意,@ 4000080将a的地址移入EAX,但是@ Done(400091),将EAX中的任何内容移动到该地址。另请注意,值@“a”以相反的顺序存储(little endian。通常在代码中,您会将其视为0x2c054
答案 2 :(得分:0)
让我们回到您的第一个代码:
mov eax, a
cmp eax, 4711
jmp equal
equal: add eax, 2
jne unequal
unequal: sub eax, 2
让我们假装第一条指令加载eax
&#34; a&#34; (它实际上是在TASM / MASM中,而是坚持明确和准确[a]
,它更容易阅读源并在NASM中也有效。)
第二条指令是cmp
,它从eax中减去4711,将结果抛出(不存储在任何地方),只有标志寄存器受到影响。如果&#34; a&#34;是4711,然后减法的结果为零,那么ZF = 1。否则ZF = 0。 (对于受CMP影响的其他标志,请参阅一些文档。)
因此,在第3行,eax
仍包含来自&#34; a&#34;的值,而标志寄存器包含cmp eax,4711
的结果。你做jmp
。这是无条件的跳跃,无论发生什么,所以你直接继续指导等于&#34;地址,add eax,2
。 =&GT;你将2添加到&#34; a&#34;在每种情况下。
add
本身也会影响旗帜,因此对于&#34; a&#34; == -2 ZF = 1,否则ZF = 0!
然后是第一个条件跳转,根据当前标志寄存器内容对代码进行分支。 jne
的缩写为&#34;跳跃不等于&#34;和&#34;等于&#34;在此上下文中表示设置零标志(ZF = 1)。
所以当&#34; a&#34;是-2,ZF在jne
之前是1(&#34;等于&#34;),因此jne
不会跳到&#34;不等于&#34;地址,但将继续到下一条指令(实际上是#34;不相等&#34;无论如何地址,所以jne
毫无意义。)
对于&#34; a&#34;与-2不同,ZF将为0(&#34;不等于&#34;),因此jne
将在提供的标签上执行跳转,继续执行地址&#34;不等于&#34;
因此,您必须远离不想执行的指令。
xor eax,eax ; sets eax to 0, and ZF=1
jz label_1 ; ZF is 1, so jump is executed, CPU goes to "label_1"
inc eax ; this instruction is then skipped and not executed
label_1:
; eax being still 0, and ZF being still set ON
; whatever instruction is here, CPU will execute it after the "jz"
略微修改的示例,以显示条件为假的情况
xor eax,eax ; sets eax to 0, and CF=0, ZF=1, ...
jc label_1 ; CF is 0, so "jump carry" is NOT executed
inc eax ; this instruction is executed after "jc"
label_1:
; here eax is 1
; CF is still 0 (not affected by INC)
; but ZF is 0 (affected by INC)
总结:您应该非常清楚哪些指令会影响哪些标志,以及以何种方式。如果不确定,请将CMP
+ Jcc
对保持在一起(以免意外影响cmp
的标记结果)。 Jcc
代表任何&#34;条件跳转&#34;指令。满足条件时,将执行跳转到提供的标签。否则,Jcc
指令将被忽略,执行将继续执行后面的指令。
if (a == 4711) { a = a + 2 } else
{ a = a - 2 }
为:
cmp [a],DWORD 4711
mov eax,2
je a_is_4711
neg eax ; -2 for non 4711 value
a_is_4711:
add [a],eax