我把很短的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

我目前正在学习汇编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: 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”

另外,
add
本身也会影响标志,因此对于“a”==-2,ZF=1,否则ZF=0

然后是第一个条件跳转,根据当前标志寄存器内容对代码进行分支。
jne
是“跳转不相等”的缩写,在本上下文中,“相等”表示设置零标志(ZF=1)

因此,当“a”为-2时,ZF在
jne
之前为1(“等于”),因此
jne
将不会跳转到“不等”地址,而是将继续执行下一条指令(实际上是在“不等”地址,因此
jne
没有意义)

对于不同于-2的“a”,ZF将为0(“不相等”),因此
jne
将在提供的标签上执行跳转,并在地址“不相等”处继续执行指令


因此,您必须使CPU远离您不想执行的指令

    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"
稍微修改示例以显示条件为false时的情况

    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
让我们假设第一条指令加载
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”

另外,
add
本身也会影响标志,因此对于“a”==-2,ZF=1,否则ZF=0

然后是第一个条件跳转,根据当前标志寄存器内容对代码进行分支。
jne
是“跳转不相等”的缩写,在本上下文中,“相等”表示设置零标志(ZF=1)

因此,当“a”为-2时,ZF在
jne
之前为1(“等于”),因此
jne
将不会跳转到“不等”地址,而是将继续执行下一条指令(实际上它位于“不等”地址,因此
jne
毫无意义)