我把很短的C代码正确地翻译成汇编程序了吗?
我目前正在学习汇编x86,我为自己做了一个小任务 C代码:我把很短的C代码正确地翻译成汇编程序了吗?,c,assembly,x86,C,Assembly,X86,我目前正在学习汇编x86,我为自己做了一个小任务 C代码: if (a == 4711) { a = a + 2 } else { a = a - 2 } 汇编程序代码(eax是寄存器,cmp是比较,jne如果不相等则是跳转,jmp如果相等则是跳转): 我认为比这更有效率的是: mov eax, a cmp eax, 4711 jne unequal add eax, 2 unequal: s
if (a == 4711) { a = a + 2 } else
{ a = a - 2 }
汇编程序代码(eax
是寄存器,cmp
是比较,jne
如果不相等则是跳转,jmp
如果相等则是跳转):
我认为比这更有效率的是:
mov eax, a
cmp eax, 4711
jne unequal
add eax, 2
unequal: sub eax, 2
编辑:
我翻译对了吗?没有
在第一种情况下,您的jne
什么也不做,因为控件无论如何都会到达那里。在那之后你需要跳转
在第二种情况下,如果比较结果为真,则加2减2,什么也不做
您也不会将结果存储回原始值所在的位置,只需将其保留在eax
否
在第一种情况下,您的jne
什么也不做,因为控件无论如何都会到达那里。在那之后你需要跳转
在第二种情况下,如果比较结果为真,则加2减2,什么也不做
您也不会将结果存储回原始值所在的位置,只需将其保留在
eax
您的编辑是正确的,除了一件事
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”是按相反顺序存储的(通常在代码中,您会将其视为0x2c054),您的编辑是正确的,但有一点除外
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”的值也是按相反顺序存储的。(通常在代码中,您会将其视为0x2c054让我们回到您的第一个代码:
mov eax, a
cmp eax, 4711
jmp equal
equal: add eax, 2
jne unequal
unequal: sub eax, 2
让我们假设第一条指令加载eax
带有“a”(实际上在TASM/MASM中是这样的,但是要坚持显式且准确的[a]
,它更容易读取源代码,并且在NASM中也能工作)
第二条指令是cmp
,它确实从eax中减去4711,将结果丢弃(不将其存储在任何地方),并且只有标志寄存器受到影响。如果“a”是4711,则减法的结果为零,因此ZF=1。否则ZF=0。(受cmp影响的其他标志见一些文档)
因此,在第3行,eax
仍然包含来自“a”的值,并且标志寄存器包含cmp eax的结果,4711
。您可以执行jmp
。这是无条件跳转,无论发生什么情况,都会发生,因此您直接继续在“equal”地址执行指令,即添加eax,2
您在每种情况下都将2添加到“a” 另外,本身也会影响标志,因此对于“a”==-2,ZF=1,否则ZF=0 然后是第一个条件跳转,根据当前标志寄存器内容对代码进行分支。add
是“跳转不相等”的缩写,在本上下文中,“相等”表示设置零标志(ZF=1) 因此,当“a”为-2时,ZF在jne
之前为1(“等于”),因此jne
将不会跳转到“不等”地址,而是将继续执行下一条指令(实际上是在“不等”地址,因此jne
没有意义) 对于不同于-2的“a”,ZF将为0(“不相等”),因此jne
将在提供的标签上执行跳转,并在地址“不相等”处继续执行指令jne
因此,您必须使CPU远离您不想执行的指令稍微修改示例以显示条件为false时的情况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
指令将被忽略,并在它之后继续执行指令Jcc
顺便说一句,我个人会写C代码:作为:if (a == 4711) { a = a + 2 } else { a = a - 2 }
让我们回到您的第一个代码:让我们假设第一条指令加载mov eax, a cmp eax, 4711 jmp equal equal: add eax, 2 jne unequal unequal: sub eax, 2
带有“a”(实际上在TASM/MASM中是这样的,但是要坚持显式且准确的eax
,它更容易读取源代码,并且在NASM中也能工作) 第二条指令是[a]
,它确实从eax中减去4711,将结果丢弃(不将其存储在任何地方),并且只有标志寄存器受到影响。如果“a”是4711,则减法的结果为零,因此ZF=1。否则ZF=0。(受cmp影响的其他标志见一些文档) 因此,在第3行,cmp
仍然包含来自“a”的值,并且标志寄存器包含eax
。您可以执行cmp eax的结果,4711
。这是无条件跳转,无论发生什么情况,都会发生,因此您直接继续在“equal”地址执行指令,即jmp
添加eax,2
您在每种情况下都将2添加到“a” 另外,本身也会影响标志,因此对于“a”==-2,ZF=1,否则ZF=0 然后是第一个条件跳转,根据当前标志寄存器内容对代码进行分支。add
是“跳转不相等”的缩写,在本上下文中,“相等”表示设置零标志(ZF=1) 因此,当“a”为-2时,ZF在jne
之前为1(“等于”),因此jne
将不会跳转到“不等”地址,而是将继续执行下一条指令(实际上它位于“不等”地址,因此jne
毫无意义)jne