如何从C源和asm输出反向设计结构细节?

时间:2016-04-07 03:07:11

标签: c linux gcc assembly

我试图了解此问题的解决方案

鉴于下面的C代码和编译器的asm输出,AB是什么?

答案:A为5,B为6。

我猜测必须进行某种划分,因为96和48都可以被6整除,20可以被5整除。

编辑:我在网上找到了这个答案。但是我不确定它是否准确
"一个char从任何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 short可能是14到20

str2.z可能是32

char w [A] [B]和int X

8 184

STR2。

短[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

2 个答案:

答案 0 :(得分:8)

汇编代码告诉您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或更少。

查看qsizeof(double)可能是8(再次,除非不寻常),所以20 + sizeof(int) + 8*B + padding == 96。如果sizeof(int) == 4(通常,虽然int的不同大小比短/双更常见),这给了我们8*B + padding == 72。因此B最多为9.由于short可能比double具有更少的限制性对齐,因此可能没有填充,给出B==9,与p之前的2字节填充一致1}}

strsizeof(char) == 1(总是),A*9 + padding = 48。因此,A的最可能值为5,填充为3个字节。

当然,编译器可以随意添加它想要的任何填充,因此AB的任何较小值都是可能的,尽管是浪费。

答案 1 :(得分:1)

asm明显适用于AMD64 SysV ABI标记维基中的更多链接)。我的结论是,它是x86-64代码,前两个参数位于%rdi%rsi。您找到的答案中给出的对齐规则与ABI的结构布局规则相匹配:这些类型具有自然对齐方式。 (n字节类型是n字节对齐的,除了10B long double(x87格式),16B对齐)。

您找到的答案与您的C和asm 不匹配,因此A和B值不同。对不起,在整理问题时我没有检查过这个问题,我只是假设,因为用编译器检查答案是微不足道的。

你找到的SO answer确实有不同的结构和不同的asm输出,所以数值解决方案中的任何相似性只是巧合。很好的工作@MichaelPetch找到原始来源(并将格式化的标记复制到问题中)。

以下代码使用gcc 5.3 -O3 on the godbolt compiler explorer生成与您的实际问题相同的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,并且没有歧义,因此我们可以在担心B之前解决A

    96 = 24 + 8 * B
    72 = 8 * B
    72/8 = 9 = B

  • 一旦我们Bstr1就会给我们A

    48 = align4(A*B) = align4(A*9)
    45 <= A*9 <= 48
    5 <= A <= 5.333
    只有一个整数解决方案:A == 5

虽然老实说通过反复试验解决问题的速度更快,因为编译器资源管理器网站会在任何更改后自动重新编译。很容易迭代到B的正确值,以产生96和20个偏移。

你的A已经是正确的了,但由于这个问题是可以分开的,所以很容易就可以了。在2个未知情形中,从未有过2个联立方程。

这就是&#34;解决方案&#34;开始偏离轨道。您确定它是您发布的完全相同问题的解决方案吗?

  

str1.w很长,从5到8开始   str1.x可能有184或180

您发布的代码中的

str1.w是一个char的二维数组,从结构的开头开始。

正如我们从asm中看到的那样,

str1.x从48 str1开始。