c代码:
*u +=a;
*v +=b;
return sizeof(a)+ sizeof(b);
x86-64代码:
movslq %edi, %rdi
addq %rdi, (%rdx)
addb %sil, (%rcx)
movl $6 %eax
ret
我知道movl $ 6%eax表示2 + 4(或4 + 2),一个是int而另一个是short。
但是当我们认为忽略movl $ 6%eax时,b可以是任何数据类型,例如该数据类型的1,2、4和8个字节。我对此有疑问。
答案 0 :(得分:1)
b
为%sil
的程序集是否意味着b
仅具有1个字节的数据,其余7个字节仅具有零的数据?
否,这意味着*v
(在内存中)只有1个字节长。此后的任何字节完全不属于v
所指向的对象的一部分。 (其大小不同于b
。)
如果您应该从汇编中对a
和b
的类型进行反向工程:请注意,它的大小为a
和b
,而不是sizeof {{ 1}}和*u
。 *v
指令的操作数大小与add
和sizeof(*u)
匹配,并且这些操作数的源操作数是将C整数提升/转换规则应用于sizeof(*v)
和a
。
例如如果我们有b
,则l += s
就像l += (long)s
如果long l; short s;
使您感到困惑,请放心,这对于字节寄存器是无效的。尝试使用GAS(addq
)进行组装会得到:
gcc -c foo.s
如果我们假设它实际上是foo.s:1: Error: `%sil' not allowed with `addq'
而不是非法的addb %sil, (%rcx)
,那么这个问题是可以回答的。
假设C语句与asm指令的顺序相同(编译器选择不对它们重新排序),那么这看起来像是来自这样的函数签名的代码,是针对x86-64 System V ABI编译的,因此args依次位于RDI,RSI,RDX,RCX中。
addq
TYPEA和TYPEU是不是相同的类型,我们已经知道了这是因为8> 6,所以任何qword类型都不适合,并且需要符号扩展。
双字int f(TYPEA a, TYPEB b, TYPEU *u, TYPEV *v);
被 sign 扩展到qword。因此a
是32位有符号整数类型。在x86-64系统V中,只有a
符合基本类型中的描述。 int
是64位,long
是16位。 (在Windows x64中,short
也是32位类型,但是从寄存器的选择上,它闻起来像x86-64 SystemV。)
long
是根据gcc上的int32_t
定义的,以防您想用固定宽度类型来考虑它。
如果是int
,我们将有movswq %di, %rdi
(或int16_t a
)。没有符号扩展,那么我们知道它是short a
或int64_t a
之一。
({uint64_t a
是*u
或uint64_t
;我们不知道哪个。int64_t
的符号扩展为(unsigned long long)(int)x;
的宽度。>
您的6 = 2 + 4逻辑是正确的。另一种类型肯定是16位= 2个字节,因为unsigned long long
在x86-64系统V中是1个字节,因此sizeof的大小以字节为单位。而且没有主流的ABI具有5字节整数类型。
char
是16位类型; short
也是如此。我们无法唯一确定它是什么。
我们从大小推断 :添加到unsigned short
的任何更大或更小的整数类型都会被截断为宽度。 (我忘记了,这里的签名溢出实际上可能是C中未定义的行为。针对x86-64编译时,生成的asm表现出您所期望的方式,并且只采用原来的整数类型的低字节。)
编译此with clang 7.0 -O3 (on the Godbolt compiler explorer) 几乎可以准确地给出您在问题中显示的asm(除了int8_t
而不是addb
之外) 。 gcc将addq
放在函数中较早的位置,这可能会使函数在较少的时钟周期内解码,或者至少将mov
解码在一个周期之前,以及2融合域之一-uop内存目标添加指令。
mov
typedef int TYPEA;
typedef short TYPEB;
typedef long TYPEU;
typedef char TYPEV;
int f(TYPEA a, TYPEB b, TYPEU *u, TYPEV *v) {
*u +=a;
*v +=b;
return sizeof(a)+ sizeof(b);
}
当然,指针类型的# clang -O3 output
f: # @f
movslq %edi, %rax # clang uses RAX instead of extending into the same register
addq %rax, (%rdx) # no difference in effect.
addb %sil, (%rcx)
movl $6, %eax
retq
或unsigned char
给出相同的asm。或unsigned long
,它也是64位类型。
但更重要的是,unsigned long long
也将给出相同的asm。