在执行procprob时,b可以是任何数据类型吗?

时间:2018-10-27 19:21:51

标签: c assembly types x86-64 reverse-engineering

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个字节。我对此有疑问。

  1. 我们假设b长(当然,我们忽略movl $ 6%eax )难道b的汇编为%sil意味着b只有1个字节的数据,其余7个字节只有0的数据吗?给我一些例子,即使b是长数据类型(8字节寄存器),b可以有%sil寄存器(1字节寄存器)

1 个答案:

答案 0 :(得分:1)

  

b%sil的程序集是否意味着b仅具有1个字节的数据,其余7个字节仅具有零的数据?

否,这意味着*v(在内存中)只有1个字节长。此后的任何字节完全不属于v所指向的对象的一部分。 (其大小不同于b

如果您应该从汇编中对ab的类型进行反向工程:请注意,它的大小为ab,而不是sizeof {{ 1}}和*u*v指令的操作数大小与addsizeof(*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 aint64_t a之一。

({uint64_t a*uuint64_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。