从编译器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
可以包含184
或180
个字节。
str2.t
字段是一个int
,从8
开始,这意味着, str1.array
可以保存5
到8
个字节。
str2.u
字段是一个long
,从32
开始,这意味着, str2.S
可以保持14
到20
个字节。
这是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 = 9
, B = 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。