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个字节。我对此有疑问。
假设b长(当然,我们忽略movl $ 6%eax)b的汇编为%sil是否意味着b只有1个字节的数据,其余7个字节只有0的数据?给我一些例子,即使b是长数据类型(8字节寄存器),b可以有%sil寄存器(1字节寄存器)
最佳答案
b
是%sil
的程序集是否意味着b
仅具有1个字节的数据,其余7个字节仅具有零的数据?
不,这意味着*v
(在内存中)只有1个字节长。此后的任何字节都根本不是v
指向的对象的一部分。 (它的大小与b
不同。)
如果您应该对asm中的a
和b
类型进行反向工程:请注意,它是sizeof a
和b
,而不是sizeof *u
和*v
。 add
指令的操作数大小与sizeof(*u)
和sizeof(*v)
匹配,并且这些源操作数是将C整数提升/转换规则应用于a
和b
的结果。
例如如果我们有l += s
,l += (long)s
就像long l; short s;
如果addq
让您感到困惑,请放心,这对于字节寄存器是无效的。尝试使用GAS(gcc -c foo.s
)进行组装可以得到:
foo.s:1: Error: `%sil' not allowed with `addq'
如果我们假设它实际上是
addb %sil, (%rcx)
而不是非法的addq
,那么这个问题是可以回答的。假设C语句与asm指令的顺序相同(编译器选择不对它们进行重新排序),那么这看起来像是来自类似x86-64 System V ABI的函数签名的代码,因此args在RDI中,RSI,RDX,RCX的顺序。
int f(TYPEA a, TYPEB b, TYPEU *u, TYPEV *v);
TYPEA和TYPEU是不同的类型,我们已经知道了这是因为8> 6,所以任何qword类型都不适合,并且需要符号扩展。
dword
a
被符号扩展到qword。因此a
是32位有符号整数类型。在x86-64 System V中,只有int
满足基本类型之外的描述。 long
是64位,short
是16位。 (在Windows x64中,long
也是32位类型,但是从寄存器选择上看,它闻起来像x86-64 SystemV。)int32_t
是根据gcc上的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;
符号扩展为unsigned long long
的宽度。您的6 = 2 + 4逻辑是正确的。另一种类型肯定是16位= 2字节,因为在x86-64系统V中
char
是1字节,因此sizeof的大小以字节为单位。而且没有主流的ABI具有5字节整数类型。short
是16位类型; unsigned short
也是如此。我们无法唯一确定它是哪个。我们仅从大小推断出它:添加到
int8_t
的任何更大或更小的整数类型都会被截断为宽度。 (我忘记了,这里的签名溢出实际上可能是C中未定义的行为。当针对x86-64进行编译时,生成的asm会以您期望的方式运行,并且仅采用原来的整数类型的低字节。)编译此with clang 7.0 -O3 (on the Godbolt compiler explorer)几乎可以得到您在问题中显示的asm(用
addb
而不是addq
除外)。 gcc将mov
立即放在函数中,这可能使函数在较少的时钟周期内解码,或者至少在mov
之前解码一个周期,再加上2个融合域uop存储器之一,目的地添加说明。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
或unsigned long
给出相同的asm。或unsigned long long
,它也是64位类型。但更重要的是,
unsigned short b
也将给出相同的asm。
关于c - 在执行procprob时,b可以是任何数据类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53025490/