我有一个分配,我需要将程序集转换为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;
}
答案 0 :(得分: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
然后通过删除不必要的临时变量,更改为更友好的循环形式,并添加函数体和return语句来达到此目的:
int func(int x, int n) {
int result = -1;
for (int mask = 1; mask; mask <<= n) {
result ^= (mask & x);
}
return result;
}
请注意,我已经在左移中删除了n
的低位字节。在评论中进行了一些讨论之后,我已经确定并添加了解释。
我们可以通过以下两种方式之一使用sal
:
sall $2, %edx ;; left shift EDX by 2
sall %cl, %edx ;; left shift EDX by the lower byte of ECX
由于移位整数类型或更多的位数是undefined behaviour(并且一个字节足以表示32位数字上明确定义的移位),编译器没有义务以有用的方式处理它,所以通过CL编译到转换的任何东西都不需要打扰显式屏蔽。因此,没有必要在C'翻译'中显示一个明确的掩码,但由于这是一个作业,我衷心建议实际解释你的选择。
(感谢Peter Huene在评论中提出这一点。)
您还可以从生成的C代码生成x86程序集,以查看所获得的内容。不要指望得到与你开始时完全相同的东西,而是将其作为一种学习方式。例如,您可以在我们的循环中检查<< n
是否已编译到。像clang -O0 -S -mllvm --x86-asm-syntax=att filename.c
这样的东西可以解决问题。
我不太确定您要解释的是什么,因为您已经对大部分内容进行了排序(movl $-1, %edi
初始化结果为-1
而andl %esi, %eax
未添加)