4

我有一个任务需要将程序集转换为 C。程序集是 x86。我对程序集进行了注释并开始填写 C 中的空白,但我对一些事情有点迷茫,有人可以帮忙吗?请解释不要只给出我想要学习的答案。

集会:

x at %ebp+8, n at %ebp+12

1 movl 8(%ebp), %esi  //store x in esi
2 movl 12(%ebp), %ebx //store n in ebx
3 movl $-1, %edi      //result in edi
4 movl $1, %edx       //i of loop in edx
5 .L2:
6 movl %edx, %eax     //move edx to eax
7 andl %esi, %eax     //sum += 1 ...? i think
8 xorl %eax, %edi     //results = results ^ (i & x)
9 movl %ebx, %ecx     //store n in ecx
10 sall %cl, %edx     //shift edx by %cl (low byte of ecx)
11 testl %edx, %edx   //check if zeroed out
12 jne .L2            //jump to .L2 if flag
13 movl %edi, %eax    //move result to eax

C代码:

int loop(int x, int n) {
  int result = _______;
  int mask;
  for (mask = 1; mask != 0; mask = ______) {
     result ^= mask & x;
  }
  return result;
}
4

1 回答 1

5

我是这样开始的:

movl 8(%ebp), %esi  ;; esi :=  x
movl 12(%ebp), %ebx ;; ebx :=  n
movl $-1, %edi      ;; edi := -1
movl $1, %edx       ;; edx :=  1
.L2:
movl %edx, %eax     ;; eax := edx
andl %esi, %eax     ;; eax &= esi (:= x) 
xorl %eax, %edi     ;; edi ^= eax
movl %ebx, %ecx     ;; ecx := ebx (:= n)
sall %cl, %edx      ;; edx <<= ecx & 0x000000FF
testl %edx, %edx    ;; set flags with edx & edx
jne .L2             ;; loop if not ZF
movl %edi, %eax     ;; eax := edi

并通过直接翻译进展到这一点,尽我所能减少角落:

int x, n, foo = -1, bar = 1;

do {
    int baz = bar;
    baz &= x;
    foo ^= baz;

    int qux = n;
    bar <<= qux & 0xFF;
} while (bar);

// now do something with foo

然后通过删除不必要的临时变量、更改为更友好的循环形式并添加函数体和返回语句来达到此目的:

int func(int x, int n) {
    int result = -1;

    for (int mask = 1; mask; mask <<= n) {
        result ^= (mask & x);
    }
    return result;
}

请注意,我已经放弃了屏蔽n左移中低字节的所有条形。在评论中进行了一些讨论之后,我已经确定了这一点并添加了解释。我们可以使用sal以下两种方式之一:

  1. 立即,例如sall $2, %edx ;; left shift EDX by 2
  2. 通过 CL 移位,例如sall %cl, %edx ;; left shift EDX by the lower byte of ECX

由于整数类型或更多位数的移位是未定义的行为(一个字节足以表示对 32 位数的明确定义的移位),编译器没有义务以有用的方式处理它方式,因此任何通过 CL 编译为转变的东西都不需要显式屏蔽。因此,无需在 C“翻译”中显示明确的掩码,但由于这是一项任务,我衷心建议以任何一种方式实际解释您的选择。

(感谢Peter Huene在评论中提出这一点。)

您还可以从生成的 C 代码生成 x86 程序集以查看您得到的结果。不要期望得到与您开始时完全相同的东西,而是将其用作学习的一种方式。例如,您可以检查是否<< n已编译到我们的循环中。类似的东西clang -O0 -S -mllvm --x86-asm-syntax=att filename.c可以解决问题。

我不太确定你想要解释什么,因为你已经对大多数东西进行了排序(除了movl $-1, %edi初始化结果-1andl %esi, %eax不是添加)

于 2013-10-29T02:44:59.850 回答