找出汇编代码段的作用

时间:2018-10-08 21:37:49

标签: c linux assembly

我有以下汇编代码:

0000000000400711 <foo>:
  400711:   55                      push   rbp
  400712:   48 89 e5                mov    rbp,rsp
  400715:   48 89 7d e8             mov    QWORD PTR [rbp-0x18],rdi
  400719:   48 c7 45 f8 00 00 00    mov    QWORD PTR [rbp-0x8],0x0
  400720:   00
  400721:   eb 10                   jmp    400733 <foo+0x22>
  400723:   48 8b 45 e8             mov    rax,QWORD PTR [rbp-0x18]
  400727:   48 8d 50 ff             lea    rdx,[rax-0x1]
  40072b:   48 89 55 e8             mov    QWORD PTR [rbp-0x18],rdx
  40072f:   48 01 45 f8             add    QWORD PTR [rbp-0x8],rax
  400733:   48 83 7d e8 00          cmp    QWORD PTR [rbp-0x18],0x0
  400738:   75 e9                   jne    400723 <foo+0x12>
  40073a:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  40073e:   5d                      pop    rbp
  40073f:   c3                      ret

我已经尝试了几个小时才能弄清楚这段代码的作用。从C代码的试错到汇编代码转换器,我非常确定QWORD部分来自char数组,其上方的行(push rbp,mov rbp,rsp)就像前言一样。我真的不确定如何解释此后的内容。我尝试将上面的代码存储为一个名为“ file.S”的文件,然后使用以下C代码和终端命令来尝试确定其作用:

#include <stdio.h>
int foo(int, int);

int main()
{
   // printf() displays the string inside quotation
   printf("%d", foo(2,2));
   return 0;
}

我使用的终端命令是

gcc -g -Og -no-pie -fno-pie -m32 main.c file.S

但是我只会遇到很多错误。

我已经尝试了许多小时,但是在解密此代码方面没有取得任何进展。任何帮助深表感谢。另外,有没有一种快速的方法(例如反编译器)可以在将来为我执行此操作?我也找不到。

1 个答案:

答案 0 :(得分:1)

从直接翻译开始,然后从那里添加语义可能会更好。

(注意:我使用uint64_t是因为该代码未进行任何已签名的比较。int64_t将适用于此代码运行不到十年的所有值,但是uint64_t更合适。)

// 0000000000400711 <foo>:
//   400711:   55                      push   rbp
//   400712:   48 89 e5                mov    rbp,rsp
uint64_t foo(uint64_t n) {

    //   400715:   48 89 7d e8             mov    QWORD PTR [rbp-0x18],rdi
    uint64_t i = n;

    //   400719:   48 c7 45 f8 00 00 00    mov    QWORD PTR [rbp-0x8],0x0
    //   400720:   00
    uint64_t sum = 0;
    //   400721:   eb 10                   jmp    400733 <foo+0x22>
    goto label_0x22;

label_0x12:
    //   400723:   48 8b 45 e8             mov    rax,QWORD PTR [rbp-0x18]
    uint64_t rax = i;
    //   400727:   48 8d 50 ff             lea    rdx,[rax-0x1]
    uint64_t rdx = rax - 1;
    //   40072b:   48 89 55 e8             mov    QWORD PTR [rbp-0x18],rdx
    i = rdx;
    //   40072f:   48 01 45 f8             add    QWORD PTR [rbp-0x8],rax
    sum += rax;

label_0x22:
    //   400733:   48 83 7d e8 00          cmp    QWORD PTR [rbp-0x18],0x0
    //   400738:   75 e9                   jne    400723 <foo+0x12>
    if (i != 0) goto label_0x12;

    //   40073a:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
    //   40073e:   5d                      pop    rbp
    //   40073f:   c3                      ret
    return sum;
}

去除注释:

uint64_t foo(int64_t n) {
    uint64_t i = n;
    uint64_t sum = 0;
    goto label_0x22;

label_0x12:
    uint64_t rax = i;
    uint64_t rdx = rax - 1;
    i = rdx;
    sum += rax;

label_0x22:
    if (i != 0) goto label_0x12;

    return sum;
}

这应该可以工作(如果不行,则可能只需要在两个标签之间的代码周围加上大括号),但是无论哪种方式,它都是丑陋的。 goto和标签更适合作为while循环。

uint64_t foo(int64_t n) {
    uint64_t i = n;
    uint64_t sum = 0;

    while (i != 0) {
        uint64_t rax = i;
        uint64_t rdx = rax - 1;
        i = rdx;
        sum += rax;
    }

    return sum;
}

现在,使用raxrdx制作整个rigamarole的目标是获取i的旧值,将其递减,然后将旧值添加到sum 。听起来像后缀递减可以优雅地完成工作。

uint64_t foo(uint64_t n) {
    uint64_t i = n, sum = 0;

    while (i != 0) { sum += i--; }
    return sum;
}

(此外:这是一种执行代码看起来很慢的方法。一些数学运算会导致效率更高的uint64_t foo(uint64_t n) { return (n + 1) * n / 2; }。)