我正在尝试解释以下IA32汇编程序代码并在C中编写一个具有同等效果的函数。
假设参数a
,b
和c
存储在相对于偏移8
,12
和16
的内存位置寄存器%ebp
中的地址,C中的适当函数原型为equivFunction(int a, int b, int c);
movl 12(%ebp), %edx // store b into %edx
subl 16(%ebp), %edx // %edx = b - c
movl %edx, %eax // store b - c into %eax
sall $31, %eax // multiply (b-c) * 2^31
sarl $31, %eax // divide ((b-c)*2^31)) / 2^31
imull 8(%ebp), %edx // multiply a * (b - c) into %edx
xorl %edx, %eax // exclusive or? %edx or %eax ? what is going on here?
首先,我是否正确地解释了装配?如果是这样,我将如何将其翻译成C?
答案 0 :(得分:1)
sall
/ sarl
组合具有将所有eax位设置为第0位的值的效果。首先,sal
将第0位移动到第31位,使其成为符号位。然后sar
将其移回,用其副本填充寄存器的其余部分。不要把它想象为除法/乘法 - 把它想象为按位移位,“s”实际上代表它。
因此,如果b-c为奇数,则eax为0xffffffff(-1),如果为偶数则为0。因此imull
命令将edx放入a的负数或零。然后,最后的xor
或者反转a
的所有位(这是xor
与其中的一位)或者保留零值。
整个片段都有一种人造气息。这是家庭作业吗?
答案 1 :(得分:1)
移位直接操纵符号位,而不是乘法/除法,因此代码大致为
int eqivFunction(int a, int b, int c) {
int t1 = b - c;
unsigned t2 = t1 < 0 ? ~0U : 0;
return (a * t1) ^ t2;
}
可替换地:
int eqivFunction(int a, int b, int c) {
int t1 = b - c;
int t2 = a * t1;
if (t1 < 0) t2 = -t2 - 1;
return t2;
}
当然,C代码在整数溢出时具有未定义的行为,而汇编代码是明确定义的,因此C代码在所有情况下可能不会做同样的事情(特别是如果你在不同的架构上编译它)< / p>