Fixture 100

struct layout

C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically

All 4 lanes recompile and return the same results as the original.

Padding is part of the object but not of any member. Copying a struct copies the padding; comparing member-by-member does not. The two orderings below hold identical members and differ only in size.

tests/decompiler_fixtures/src/100_struct_layout.c source
#include <stdint.h>
#include <stddef.h>

/* Padding is part of the object but not of any member. Copying a struct copies
 * the padding; comparing member-by-member does not. The two orderings below
 * hold identical members and differ only in size. */

struct Wasteful {
    uint8_t tag;
    int32_t value;
    uint8_t flag;
    int32_t extra;
};

struct Tight {
    int32_t value;
    int32_t extra;
    uint8_t tag;
    uint8_t flag;
};

__attribute__((noinline)) int32_t layout_size_delta(void) {
    return (int32_t)(sizeof(struct Wasteful) - sizeof(struct Tight));
}

__attribute__((noinline)) int32_t layout_offsets(int32_t which) {
    switch (which & 3) {
    case 0:
        return (int32_t)offsetof(struct Wasteful, value);
    case 1:
        return (int32_t)offsetof(struct Wasteful, extra);
    case 2:
        return (int32_t)offsetof(struct Tight, tag);
    default:
        return (int32_t)offsetof(struct Tight, flag);
    }
}

__attribute__((noinline)) int32_t
struct_assignment_copies(int32_t tag, int32_t value) {
    struct Tight source;
    struct Tight destination;
    source.value = value;
    source.extra = value * 2;
    source.tag = (uint8_t)tag;
    source.flag = (uint8_t)(tag + 1);
    destination = source; /* whole-object copy, padding included */
    return destination.value + destination.extra + (int32_t)destination.tag +
           (int32_t)destination.flag;
}

Recovered C

Generated by glaurung decompile --style decbench at b47f6b43. baseline.json records the result after recompiling the C and calling it beside the original with seeded inputs.

clang -O0

3/3
layout_offsets pass 21 lines
// glaurung: layout_offsets @ 0x1110
int32_t layout_offsets(int32_t arg0) {
    int local_c;
    int var1;
    // x86-64 prologue: save rbp
    var1 = ((unsigned int)(arg0) & 3);
    local_c = var1;
    if (((unsigned long)((unsigned int)(var1)) == 0)) {
        return 4;
    } else {
        if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_c)) - 1))) == 0)) {
            return 12;
        } else {
            if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_c)) - 2))) == 0)) {
                return 8;
            } else {
                return 9;
            }
        }
    }
}
layout_size_delta pass 6 lines
// glaurung: layout_size_delta @ 0x1100
int32_t layout_size_delta(void) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return 4;
}
struct_assignment_copies pass 14 lines
// glaurung: struct_assignment_copies @ 0x1180
__attribute__((no_stack_protector)) int32_t struct_assignment_copies(int32_t arg0, int32_t arg1) {
    unsigned char local_18[12];
    unsigned char local_28[12];
    // x86-64 prologue: save rbp
    *(int *)(&local_18[0]) = arg1;
    *(int *)((&local_18[0] + 4)) = ((unsigned long)((unsigned int)(arg1)) << 1);
    *(signed char *)((&local_18[0] + 8)) = arg0;
    *(signed char *)((&local_18[0] + 9)) = ((unsigned long)((unsigned int)(arg0)) + 1);
    *(long *)(&local_28[0]) = *(long *)(&local_18[0]);
    *(int *)((&local_28[0] + 8)) = *(int *)((&local_18[0] + 8));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(&local_28[0]))) + *(int *)((&local_28[0] + 4))))) + (unsigned int)((unsigned char)(*(char *)((&local_28[0] + 8))))))) + (unsigned int)((unsigned char)(*(char *)((&local_28[0] + 9))))));
}

clang -O2

3/3
layout_offsets pass 11 lines
// glaurung: layout_offsets @ 0x1110
int32_t layout_offsets(int32_t arg0) {
    long ret;
    long var1;
    var1 = (unsigned long)((unsigned int)((arg0 & 3)));
    ret = 9;
    if (((unsigned long)((unsigned int)(var1)) != 3)) {
        ret = (unsigned long)((unsigned int)((((unsigned long)((unsigned int)(var1)) == 0) ? 4 : (((unsigned long)((unsigned int)(var1)) == 1) ? 12 : (((unsigned long)((unsigned int)(var1)) == 2) ? 8 : *(int *)((0x2000 + ((unsigned long)((unsigned int)(var1)) * 4))))))));
    }
    return ret;
}
layout_size_delta pass 4 lines
// glaurung: layout_size_delta @ 0x1100
int32_t layout_size_delta(void) {
    return 4;
}
struct_assignment_copies pass 4 lines
// glaurung: struct_assignment_copies @ 0x1130
int32_t struct_assignment_copies(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned int)((unsigned char)(((unsigned long)((unsigned int)((arg0 + 1))) & 255))) + (unsigned long)((unsigned int)(((unsigned int)((unsigned char)((arg0 & 255))) + (unsigned long)((unsigned int)((arg1 + (arg1 * 2)))))))));
}

gcc -O0

3/3
layout_offsets pass 23 lines
// glaurung: layout_offsets @ 0x1108
int32_t layout_offsets(int32_t arg0) {
    long var2;
    // x86-64 prologue: save rbp
    var2 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 3)));
    if (((unsigned long)((unsigned int)(var2)) == 2)) {
        return 8;
    } else {
        if (((((unsigned long)((unsigned int)(var2)) == 2) | ((long)((int)(var2)) < 2)) == 0)) {
            // x86-64 epilogue: restore rbp
            return 9;
        }
        if (((unsigned long)((unsigned int)(var2)) == 0)) {
            return 4;
        } else {
            if (((unsigned long)((unsigned int)(var2)) == 1)) {
                return 12;
            } else {
                return 9;
            }
        }
    }
}
layout_size_delta pass 6 lines
// glaurung: layout_size_delta @ 0x10f9
int32_t layout_size_delta(void) {
    // x86-64 prologue: save rbp
    // x86-64 epilogue: restore rbp
    return 4;
}
struct_assignment_copies pass 14 lines
// glaurung: struct_assignment_copies @ 0x114a
__attribute__((no_stack_protector)) int32_t struct_assignment_copies(int32_t arg0, int32_t arg1) {
    unsigned char local_18[12];
    unsigned char local_c[12];
    // x86-64 prologue: save rbp
    *(int *)(&local_18[0]) = arg1;
    *(int *)((&local_18[0] + 4)) = ((unsigned long)((unsigned int)(arg1)) + (unsigned long)((unsigned int)(arg1)));
    *(signed char *)((&local_18[0] + 8)) = arg0;
    *(signed char *)((&local_18[0] + 9)) = ((unsigned long)((unsigned int)(arg0)) + 1);
    *(long *)(&local_c[0]) = *(long *)(&local_18[0]);
    *(int *)((&local_c[0] + 8)) = *(int *)((&local_18[0] + 8));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned int)((unsigned char)(((unsigned int)((unsigned char)(*(char *)((&local_c[0] + 9)))) & 255))) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(&local_c[0]))) + (unsigned long)((unsigned int)(*(int *)((&local_c[0] + 4))))))) + (unsigned int)((unsigned char)(((unsigned int)((unsigned char)(*(char *)((&local_c[0] + 8)))) & 255))))))));
}

gcc -O2

3/3
layout_offsets pass 11 lines
// glaurung: layout_offsets @ 0x1110
int32_t layout_offsets(int32_t arg0) {
    long ret;
    long var1;
    var1 = (unsigned long)((unsigned int)((arg0 & 3)));
    ret = 9;
    if (((unsigned long)((unsigned int)(var1)) != 3)) {
        ret = (unsigned long)((unsigned int)(((var1 == 0) ? 4 : ((var1 == 1) ? 12 : ((var1 == 2) ? 8 : *(int *)((0x2000 + (var1 * 4))))))));
    }
    return ret;
}
layout_size_delta pass 4 lines
// glaurung: layout_size_delta @ 0x1100
int32_t layout_size_delta(void) {
    return 4;
}
struct_assignment_copies pass 4 lines
// glaurung: struct_assignment_copies @ 0x1130
int32_t struct_assignment_copies(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg1 + (arg1 * 2)))) + (unsigned int)((unsigned char)((arg0 & 255)))))) + (unsigned int)((unsigned char)(((unsigned long)((unsigned int)((arg0 + 1))) & 255)))));
}

← 213 fixtures