将条件移动(CMOV)指令从汇编转换为C.

时间:2016-11-27 17:14:46

标签: c assembly x86 x86-64

我正在尝试将x86-64程序集转换为C代码,我仍然不确定条件移动。

这是汇编代码:

public Class Circle{
    double radius;
    public Circle(){
        super();
        radius = 1.0;
    }
    public Circle(double newRadius){
        super();
        if(newRadius>0)
            radius = newRadius;
        else
            radius = 1.0;
    }
    public Circle(int newX, int newY, double newRadius){
        super(newX,newY);
        if(newRadius>0)
            radius = newRadius;
        else
            radius = 1.0;
    }
    public double getRadius(){
        return radius;
    }
    public void setRadius(double newRadius){
        if(newRadius>0)
            radius = newRadius;
        else
            radius = 1.0;
    }
}

在C中,它会是:

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

我真的不确定这一切,所以如果有人可以提供帮助,那就太好了。

2 个答案:

答案 0 :(得分:2)

条件移动(CMOV)指令到C的最简单转换将是条件运算符。类似的东西:

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

这基本上允许您将if-else块写为单行。等效的长形if-else块将是:

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

在您的情况下,汇编代码使用CMOVGE指令,这意味着“如果将flags设置为指示大于或等于”,则“有条件地将源移动到目标”。 CMP指令用于设置标志。介入的MOV指令只获取为以下CMOV设置的寄存器的内容,而不影响标志。

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

因此汇编代码的C转换将是:

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

您可能希望使用描述性变量名,而不是在编写汇编代码时半任意选择的寄存器名称。

至于你要返回的内容,我所知道的所有x86 ABI都会在EAX寄存器中保留函数的返回值。因此,汇编代码返回EAX中剩余的任何值。 (这就是为什么需要介入MOV指令 - 以确保返回值最终在EAX中。)因此,在转换为C时,您可以简单地使用以下单行:

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

并确保任何编译器都将转换为等效的汇编代码!

答案 1 :(得分:1)

这实际上取决于您的ABI,但通常eax是包含返回值的寄存器。

所以它更像是

eax = esi;
if (edi >= esi) eax = edi;
return eax;

相当于

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