从编译器asm输出反向设计数组维度/结构布局?

在此代码中,A和B是使用#define定义的常量。 A和B的值是多少?

 typedef struct { int x[A][B]; long y; } str1; typedef struct { char array[B]; int t; short S[A]; long u; } str2; void setVal(str1 *p, str2 *q) { long v1 = q->t; long v2 = q->u; p->y = v1+v2; } 

setVal过程生成以下汇编代码:

 setVal: movslq 8(%rsi), %rax addq 32(%rsi), %rax movq %rax, 184(%rdi) ret 

该结构具有以下对齐要求:

  • char可以从任何字节开始
  • short可以从偶数字节开始
  • int可以从byte开始,可以被4整除
  • long可以从byte开始,可以被8整除

str1.y字段是一个long ,从184开始,这意味着str1.x可以包含184180个字节。

str2.t字段是一个int ,从8开始,这意味着, str1.array可以保存58个字节。

str2.u字段是一个long ,从32开始,这意味着, str2.S可以保持1420个字节。

这是str1结构字段的图表:

 +---------------+---+--------+ | int x[A][B] | ? | long y | +---------------+---+--------+ | 184 | 8 | +-------------------+--------+ 

这是str2字段的图表:

 +---------------+---+-------+------------+---+--------+ | char array[B] | ? | int t | short S[A] | ? | long u | +---------------+---+-------+------------+---+--------+ | 8 | 4 | 20 | 8 | +-------------------+-------+----------------+--------+ 

之后,您应该解决以下系统:

 177 <= 4 * A * B <= 184 5 <= B <= 8 14 <= A * 2 <= 20 // 7 <= A <= 10 

答案是: A = 9B = 5


您可以使用遵循生成原始代码的编译器所使用的相同ABI /调用约定的编译器来测试您的答案(以及每个不等式的范围)。 它使用8字节long :注意addq的64位操作数大小,而不是addl和8字节存储。 因此,我们可以推断它最有可能是x86-64 System V ABI,而不是Windows x86-64调用约定(使用4字节long )。

Godbolt编译器资源管理器具有gcc,clang,ICC和MSVC。 前3个目标Linux,但MSVC以Windows调用约定为目标,因此不会同意结构布局的long较小long需要较少的对齐。

char t[177] (或其他大小)替换int x[A][B]certificate177是最小值,184是导致存储到184(%rdi)的最大大小。 所以我们可以写出176 < 4*A*B <= 184 。 或者,为了保持4的倍数, 180 <= 4*A*B <= 184也或多或少是正确的; 我们可以根据int的大小排除177..179。