Leah Leah - 7 days ago 17
C Question

Translating conditional move (CMOV) instructions from assembly into C

I'm trying to convert x86-64 assembly into C code, and I am still unsure about conditional moves.

This is the assembly code:

cmpl %esi, %edi
movl %esi, %eax
cmovge %edi, %eax // This is called a conditional move.
ret


In C, would it be:

if (edi < esi) { // am I supposed to change edi and esi to local variable names?
uint32_t variable1;
return ___; // what am I supposed to return?
}


I'm really unsure about this whole thing, so if anyone can help, that would be great.

Answer

The simplest translation of a conditional move (CMOV) instruction to C would be the conditional operator. Something like:

int a = (b < c) ? b : c;

This basically allows you to write an if-else block as a single line. The equivalent long-form if-else block would be:

int a;
if (b < c)
{
    a = b;
}
else
{
    a = c;
}

In your case, the assembly code uses the CMOVGE instruction, which means "conditionally move source to destination if flags are set to indicate greater than or equal to". The CMP instruction is what sets the flags. The intervening MOV instruction just gets the contents of the registers set up for the following CMOV, without affecting flags.

cmpl   %esi, %edi    ; compare the value of esi to edi, and set flags
movl   %esi, %eax    ; move the value of esi into eax
cmovge %edi, %eax    ; if flags indicate greater than or equal to (i.e., SF == OF),
                     ;  then move the value of edi into eax

So the C translation for your assembly code would be:

eax = (edi >= esi) ? edi : esi;

You will probably want to use descriptive variable names, rather than the names of the registers that were semi-arbitrarily chosen when writing the assembly code.

As for what you would return, all x86 ABIs that I know of leave the return value of a function in the EAX register. Therefore, the assembly code is returning whatever value is left in EAX. (This is why the intervening MOV instruction was required—to ensure that the return value ended up in EAX.) So, in translation to C, you could simply use the following one-liner:

return (edi >= esi) ? edi : esi;

and be secure in the knowledge that any compiler will translate it back into equivalent assembly code!

Comments