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 - 对姓名和分数进行排序

c - 这个#define 示例如何工作?

c - Atmel 处理器已复位,但 MCUSR 中未指示复位源

c# - 方法的数据类型

c - 使用GCC时出现几个编译错误

c - 在项目中使用 libfuse,没有 root 访问权限(用于安装)? FTP 安装和 inotify/kqueue/FSEvents

c - X86 汇编 - 处理 IDIV 指令

c - 按位 - 位掩码操作是如何实现的?

c++ - C++ 模板函数可以在返回参数上重载吗?

java - 如何避免误用具有多个相同类型参数的构造函数?