从装配中反向设计优化的c代码

sco*_*bby 7 c x86 assembly reverse-engineering compiler-optimization

这个问题的关键是对使用2级优化运行编译器后生成的c代码进行逆向工程.原始c代码如下(计算最大公约数):

int gcd(int a, int b){
    int returnValue = 0;
    if (a != 0 &&  b != 0){
        int r;
        int flag = 0;
        while (flag == 0){
            r = a % b;
            if (r ==0){
                flag = 1;
            } else {
                a = b;
                b = r;
            }
        }
        returnValue = b;
    }
    return(returnValue);
}
Run Code Online (Sandbox Code Playgroud)

当我运行优化编译时,我从命令行运行它:

gcc -O2 -S Problem04b.c
Run Code Online (Sandbox Code Playgroud)

获取此优化代码的程序集文件

.gcd:
    .LFB12:
        .cfi_startproc
        testl   %esi, %esi
        je  .L2
        testl   %edi, %edi
        je  .L2
    .L7:
        movl    %edi, %edx
        movl    %edi, %eax
        movl    %esi, %edi
        sarl    $31, %edx
        idivl   %esi
        testl   %edx, %edx
        jne .L9
        movl    %esi, %eax
        ret
        .p2align 4,,10
        .p2align 3
    .L2:
        xorl    %esi, %esi
        movl    %esi, %eax
        ret
        .p2align 4,,10
        .p2align 3
    .L9:
        movl    %edx, %esi
        jmp .L7
        .cfi_endproc
Run Code Online (Sandbox Code Playgroud)

我需要将此汇编代码转换回c代码,这是我现在所处的位置:

int gcd(int a int b){
    /*
       testl %esi %esi
       sets zero flag if a is 0 (ZF) but doesn't store anything
       */
    if (a == 0){
        /*
           xorl %esi %esi
           sets the value of a variable to 0. More compact than movl
           */
        int returnValue = 0;
        /*
           movl %esi %eax
           ret

           return the value just assigned
           */
        return(returnValue);
    }
    /*
       testl %edi %edi
       sets zero flag if b is 0 (ZF) but doesn't store anything
       */
    if (b == 0){
        /*
           xorl %esi %esi
           sets the value of a variable to 0. More compact than movl
           */
        int returnValue = 0;
        /*
           movl %esi %eax
           ret

           return the value just assigned
           */
        return(returnValue);
    }

    do{
        int r = b;
        int returnValue = b;

    }while();


}
Run Code Online (Sandbox Code Playgroud)

任何人都可以帮我写回c代码吗?我很丢失.

Dan*_*ein 8

首先,您在代码中混合了值.%esi从值开始b%edi从值开始a.

您可以从用作开始的循环的条件变量的testl %edx, %edx行推断(如果不同于0则控制转移到块然后返回到).我们将把为我们的逆向工程代码.%edx.L7%edx.L9.L7%edxremainder


让我们开始对主循环进行逆向工程:

movl    %edi, %edx
Run Code Online (Sandbox Code Playgroud)

由于%edi存储a,这相当于初始化remainderwith a:的值int remainder = a;.

movl    %edi, %eax
Run Code Online (Sandbox Code Playgroud)

商店 int temp = a;

movl    %esi, %edi
Run Code Online (Sandbox Code Playgroud)

执行int a = b;(记住%edia%esib).

sarl $31, %edx

该算术移位指令将remainder变量31位向右移位,同时保持数字的符号.通过移位31位remainder,如果它为正(或零)则设置为0,如果为负则设置为-1.所以它相当于remainder = (remainder < 0) ? -1 : 0.

idivl %esi

除以%edx:%eax通过%esi,或在我们的情况下,除remainder * tempb(变量).在其余的将被存储在%edx,或在我们的代码,remainder.将此与前一条指令结合使用时:if remainder < 0then remainder = -1 * temp % b,等等remainder = temp % b.

testl   %edx, %edx
jne .L9
Run Code Online (Sandbox Code Playgroud)

检查是否remainder等于0 - 如果不是,跳转到.L9.那里的代码只是b = remainder;在返回之前设置.L7.为了在C中实现这一点,我们将保留一个count变量来存储循环迭代的次数.我们将b = remainder在循环的开始执行但仅在第一次迭代之后执行,这意味着什么时候count != 0.

我们现在准备构建完整的C循环:

int count = 0;
do {
    if (count != 0)
        b = remainder;
    remainder = a;
    temp = a;
    a = b;
    if (remainder < 0){
        remainder = -1 * temp % b;
    } else {
        remainder = temp % b;
    }

    count++;
} while (remainder != 0)
Run Code Online (Sandbox Code Playgroud)

循环结束后,

movl    %esi, %eax
ret
Run Code Online (Sandbox Code Playgroud)

将返回程序计算的GCD(在我们的代码中它将存储在b变量中).