考虑以下C函数原型,其中num_t
是使用typedef声明的数据类型:
void store_prod(num_t *dest, unsigned x, num_t y) {
*dest = x*y;
}
gcc生成以下汇编代码,实现计算主体:
什么数据类型是num_t
?
正确的答案是num_t
是unsigned long long
,但我真的不明白为什么,我们将非常感谢任何帮助!!
# dest at %ebp +8, x at %ebp +12, y at %ebp +16
movl 12(%ebp), %eax
movl 20(%ebp), %ecx
imull %eax, %ecx
mull 16(%ebp)
leal (%ecx,%edx), %edx
movl 8(%ebp), %ecx
movl %eax, (%ecx)
movl %edx, 4(%ecx)
答案 0 :(得分:4)
从使用(%ebp)
寻址模式可以看出这是32位代码,而不是x86-64。
在32位模式下,unsigned long long
是唯一的64位无符号整数类型,在任何常见的ABI中。 (例如,在Linux上使用的i386 System V ABI)。 long
是32位。
我们可以告诉num_t
是一个64位整数类型,因为它是从整数乘法和加法的结果中存储在两个32位的一半中。
我们可以告诉它它是unsigned
整数类型,因为gcc在mul
和{{1}的低半部分之间使用了imul
而不是x
}}。 (将y
与imul %eax, %ecx
的上半部分相乘的2操作数x
与有符号或无符号的二进制操作相同:仅全乘(N x N => 2N位)关心签名。)
IDK为什么gcc会使用y
代替leal (%ecx,%edx), %edx
。也许你用add %ecx, %edx
或其他东西编译?保留标志是不必要的。
无论如何,它是普通的64 x 32 => 64位扩展精度乘法。
这是C,而不是C ++,因此也可以排除包含64位整数和重载-mtune=atom
运算符的类。
我们可以排除FP类型,因为它会使用FP乘法。