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

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


假设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中的ab类型进行反向工程:请注意,它是sizeof ab,而不是sizeof *u*vadd指令的操作数大小与sizeof(*u)sizeof(*v)匹配,并且这些源操作数是将C整数提升/转换规则应用于ab的结果。

例如如果我们有l += sl += (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 auint64_t a之一。

*uuint64_tint64_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 charunsigned long给出相同的asm。或unsigned long long,它也是64位类型。

但更重要的是,unsigned short b也将给出相同的asm。

关于c - 在执行procprob时,b可以是任何数据类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53025490/

相关文章:

c - sem_t的结构和信号量的实现

linux - 将代码段的十六进制表示变回二进制

assembly - MOV r/m8,r8 和 MOV r8,r/m8 的区别

C++ : Make multiple constructors with the same argument types

haskell - 为什么参数可以接受类型类的任何构造,但不能有条件地构造其值?

c - 如何使用格式字符串攻击覆盖变量

c - Linux 中的多线程服务器

c - stdlib.h、stdio.h 中所有函数和常量的引用?

c - 从函数返回结构时可能存在 GCC 错误

php - 我应该在哪里检查 PHP 7 的变量类型?