cnmesr cnmesr - 2 months ago 13
C Question

Did I translate the very short C code correctly into assembler?

I'm currently learning assembly x86 and I have made a little task for myself.

The C code:

if (a == 4711) { a = a + 2 } else
{ a = a - 2 }


Assembler Code (
eax
is a register,
cmp
is compare,
jne
is jump if not equal and
jmp
is jump if equal):

mov eax, a
cmp eax, 4711
jmp equal
equal: add eax, 2
jne unequal
unequal: sub eax, 2


I think a little more efficient than that would be:

mov eax, a
cmp eax, 4711
jne unequal
add eax, 2
unequal: sub eax, 2


Edit:

mov eax, a
cmp eax, 4711
jne unequal
equal: add eax, 2
jmp continue
unequal: sub eax, 2
continue: ...


Did I translate it correctly?

Answer

Let's get back to your first code:

         mov eax, a
         cmp eax, 4711
         jmp equal
equal:   add eax, 2
         jne unequal
unequal: sub eax, 2

Let's pretend the first instruction load eax with "a" (it actually would in TASM/MASM, but rather stick to explicit and accurate [a], it's easier to read the source and works also in NASM).

Second instruction is cmp, which does subtract 4711 from eax, throws the result away (not storing it anywhere), and only flag register is affected. If "a" was 4711, then result of subtraction is zero, so ZF=1 then. Otherwise ZF=0. (for other flags affected by CMP see some documentation).

So on line 3 the eax still contains value from "a", and flag register contains result of cmp eax,4711. And you do jmp. This is unconditional jump, happening no matter what, so you directly continue to instruction at "equal" address, which is add eax,2. => You add 2 to "a" in every case.

Also the add itself affects flags, so for "a" == -2 the ZF=1, otherwise ZF=0!

Then comes the first conditional jump, branching the code, based on current flag register content. The jne is abbreviation of "jump not equal", and "equal" in this context means set zero flag (ZF=1).

So when "a" was -2, ZF is 1 ("is equal") ahead of jne, thus jne will NOT jump to the "unequal" address, but will continue to the next instruction (which is actually at "unequal" address anyway, so the jne is meaningless).

For "a" different from -2 the ZF will be 0 ("is not equal"), so jne will execute the jump on the provided label, continuing with instruction at address "unequal".


So you have to navigate the CPU away from instructions you don't want to execute.

    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"

Slightly modified example to show the case when condition is 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)

Summary: you should have pretty good idea what instructions affect what flags, and in what way. When unsure, keep CMP + Jcc pair together (to not affect flag results from cmp accidentally). Jcc stands for any "conditional jump" instruction. When the condition is met, the jump to provided label is executed. Otherwise the Jcc instruction is ignored, and execution does continue with instruction right after it.

Comments