![](/img/trans.png)
[英]Reverse engineer array dimensions / struct layout from compiler asm output?
[英]How to reverse engineer struct details from C source and asm output?
我试图理解这个问题的解决方案 :
鉴于下面的C代码和编译器的asm输出, A
和B
什么?
答案: A
是5, B
是6。
我猜测必须进行某种划分,因为96和48都可以被6整除,20可以被5整除。
编辑: 我在网上找到了答案。 但是我不确定它是否准确
“一个字母从任何一个BYTE开始
短路仅在偶数字节处开始
一个int从BYTE开始,但可被4整除
很快就开始了BYTE,可以被8整除
str1.w很长,从5到8开始
str1.x可能有184或180
str2.p是int从值8开始,因此str1.array保持5到8个BYTES
str2.q短期可能是14到20
str2.z可能是32
char w [A] [B]和int X.
8 184
STR2。
short [B] int p doublez [B] short q
20 4 8 9
因此A = 5和B = 6“的值
代码如下:
// #define A ?? // 5
// #define B ?? // 6, but the question is how to figure that out from the asm
typedef struct {
char w[A][B];
int x;
} str1;
typedef struct {
short y[B];
int p;
double z[B];
short q;
} str2;
void doSub(str1 *t, str2 *u) {
int v1 = u->p;
int v2 = u->q;
t->x = v1-v2;
}
为doSub过程生成的汇编代码:
# t in %rdi, u in %rsi
doSub:
movswl 96(%rsi), %edx
movl 20(%rsi), %eax
subl %edx, %eax
movl %eax, 48(%rdi)
ret
汇编代码告诉您C代码中使用的字段的偏移量。 所以,你可以说
offsetof(str1, x) == 48
offsetof(str2, p) == 20
offsetof(str2, q) == 96
现在让我们来看看p
。 它来自y
和sizeof(short)
可能是2(除非这是一个非常不寻常的机器或编译器),所以这告诉我们B*2 + padding == 20
。 所以B最多为10,可能不是8或更少。
看q
, sizeof(double)
可能是8(再次,除非异常),所以20 + sizeof(int) + 8*B + padding == 96
。 如果sizeof(int) == 4
(常见,虽然int的不同大小比short / double更常见),这给了我们8*B + padding == 72
。 所以B最多为9.因为short
可能比double
更少限制,所以可能没有填充,给出B==9
,与p
之前的2个字节填充一致
看看str
, sizeof(char) == 1
(总是),所以A*9 + padding = 48
。 所以A
的最可能值是5,有3个字节的填充。
当然,编译器可以自由添加它想要的任何填充,因此A
和B
任何较小值都是可能的,尽管是浪费。
asm显然适用于AMD64 SysV ABI ( x86标签wiki中的更多链接)。 我的结论是,它是x86-64代码,前两个参数是%rdi
, %rsi
。 您找到的答案中给出的对齐规则与ABI的结构布局规则相匹配:这些类型具有自然对齐方式。 (n字节类型是n字节对齐的,除了10B long double(x87格式),它是16B对齐的)。
您找到的答案与您的C和asm不匹配 ,因此A和B值不同。 对不起,我在整理问题时没有检查这个,我只是假设,因为用编译器检查答案是微不足道的。
您找到的SO答案确实具有不同的结构和不同的asm输出,因此数值解决方案中的任何相似性只是巧合。 很好的工作@MichaelPetch找到原始来源(并将格式化的标记复制到问题中)。
以下代码使用godbolt编译器资源管理器上的gcc 5.3 -O3生成与实际问题完全相同的asm:
#define A 5
#define B 9
typedef struct {
char w[A][B]; // stored from 0 to A*B - 1
int x; // offset = 48 = A*B padded to a 4B boundary
} str1;
typedef struct {
short y[B]; // 2*B bytes
int p; // offset = 20 = 2*B rounded up to a 4byte boundary
double z[B]; // starts at 24 (20+4, already 8byte aligned), ends at 24 + 8*B - 1
short q; // offset = 96 = 24 + 8 * B
} str2;
void doSub(str1 *t, str2 *u) {
int v1 = u->p;
int v2 = u->q;
t->x = v1-v2;
}
我在asm中添加了我们对结构的评论。
str2
只依赖于B,并且没有歧义,所以我们可以在担心A
之前解决B
:
96 = 24 + 8 * B
72 = 8 * B
72/8 = 9 = B
一旦我们有了B
, str1
给了我们A
:
48 = align4(A*B) = align4(A*9)
45 <= A*9 <= 48
5 <= A <= 5.333
只有一个整数解: A == 5
虽然老实说,通过反复试验解决问题的速度更快,因为编译器资源管理器网站会在任何更改后自动重新编译。 很容易迭代到B的正确值,以产生96和20个偏移。
你的A
已经是正确的了,但由于这个问题是可以分离的,所以很容易就可以了。 在2个未知情形中,从未有过2个联立方程。
这就是“解决方案”开始偏离轨道的地方。 您确定它是您发布的完全相同问题的解决方案吗?
str1.w
很长,从5到8开始
str1.x
可能有184或180
你发布的代码中的str1.w
是一个二维char
数组,从结构的开头开始。
str1.x
从48字节开始进入str1
,正如我们从asm中看到的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.