我从汇编到C代码的转换正确吗?

Ben*_*uez 5 c assembly x86-64

我有一个问题要求将汇编代码转换为C代码。

我已经尝试过转换代码,但我认为我基本上是正确的,但是我对leaq指令感到困惑。

looper:
   movl  $o, %eax
   movl  $o, %edx
   jmp   .L2

.L4:
   movq  (%rsi, %rdx, 8), %rcx
   cmpq  %rcx, %rax
   jl    .L3
   movq  %rax, %rcx

.L3:
   leaq  1(%rcx), %rax
   addq  $1, %rdx

.L2:
   cmpq  %rdi, %rdx
   jl    .L4
   rep ret
Run Code Online (Sandbox Code Playgroud)

这是我得到的C代码:

long looper(long n, long *a) {
  long i;
  long x = 0;

  for (i = 0; i < n; i++) {
    if (x < a[i]) {
      x = a[i] + 1;
    }
    x = a[i];
  }

  return x;
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*lli 9

首先,您的程序集中似乎有一个错误:看起来$o应该是$0(零)。

您的C代码几乎是正确的,存在一些错误:

  1. jl .L3实际上,如果%rax < %rcx采用分支,而指令movq %rax, %rcx被忽略,则指令生成的分支的顺序非常重要。另一方面,如果未采用分支,则进入之前执行该移动.L3。因此,您基本上交换了C代码中的两个分支。

  2. 的值a[i]并非每次都直接使用,而是在使用%rcx前先保存在寄存器中。二者movq %rax, %rcxmovq (%rsi, %rdx, 8), %rcx分配到%rcx,则该值是从传递%rcx%rax,因此%rcx应被视为一个不同的变量。这意味着写作x = a[i] + 1;是错误的。它应该是:

    tmp = a[i];
    /* ... */
    x = tmp + 1; 
    
    Run Code Online (Sandbox Code Playgroud)

生成的C代码应如下所示:

int64_t looper(int64_t n, int64_t *arr) {
    int64_t result; // rax
    int64_t tmp;    // rcx
    int64_t i;      // rdx

    result = 0;

    for (i = 0; i < n; i++) {
        tmp = arr[i];

        if (result >= tmp)
            tmp = result;

        result = tmp + 1;
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

另外,使用as -o prog prog.sRadare2 编译二进制文件然后将其反汇编,可以得到以下相当简单的控制流程图:

tmp = a[i];
/* ... */
x = tmp + 1; 
Run Code Online (Sandbox Code Playgroud)

  • @ JL2210和Marco:函数args到达RDI和RSI,因此这是x86-64 System V ABI。与Windows x64不同,long是64位类型。(LP64与LLP64)。https://zh.wikipedia.org/wiki/64-bit_computing#64-bit_data_models。但是,是的,`int64_t`更好,并且不依赖于这样的小细节。x86-64上的DeathStation 9000 C实现可能具有128位类型的long long类型。但是,如果根本存在可选类型“ int64_t”,则它必须是精确的64位,无填充和2的补码。(但签名溢出仍然是UB。) (4认同)
  • @ JL2210我决定不使用`long`,因为它依赖于平台,并且您不能轻易地从原始汇编中推断出数据类型。`int64_t`是正确的,`long` *可能是正确的*。 (3认同)