Fixture 101

static locals

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

4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (1/3), gcc-O0 (1/3), clang-O2 (2/3), gcc-O2 (2/3).

A static local has static storage duration but block scope: the object lives in .data/.bss and survives across calls, so recovering it means recognizing a global that only one function names.

tests/decompiler_fixtures/src/101_static_locals.c source
#include <stdint.h>

/* A static local has static storage duration but block scope: the object lives
 * in .data/.bss and survives across calls, so recovering it means recognizing a
 * global that only one function names. */

__attribute__((noinline)) int32_t counter_next(int32_t increment) {
    static int32_t counter = 100;
    counter += increment;
    return counter;
}

__attribute__((noinline)) int32_t counter_reset(void) {
    static int32_t generation = 0;
    generation += 1;
    return generation;
}

__attribute__((noinline)) int32_t
static_table_lookup(int32_t index) {
    /* A read-only table with internal linkage: no relocation names it. */
    static const int32_t squares[8] = {0, 1, 4, 9, 16, 25, 36, 49};
    if (index < 0 || index > 7) {
        return -1;
    }
    return squares[index];
}

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

1/3
counter_next fail 9 lines
// glaurung: counter_next @ 0x1100
static unsigned char glaurung_global_4020[16] __attribute__((aligned(16)));
int32_t counter_next(int32_t arg0) {
    extern unsigned char glaurung_global_4020[16];
    // x86-64 prologue: save rbp
    *(int *)(&glaurung_global_4020[0]) = ((unsigned long)((unsigned int)(arg0)) + *(int *)(&glaurung_global_4020[0]));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)(&glaurung_global_4020[0]));
}
counter_reset pass 9 lines
// glaurung: counter_reset @ 0x1120
static unsigned char glaurung_global_4028[16] __attribute__((aligned(16)));
int32_t counter_reset(void) {
    extern unsigned char glaurung_global_4028[16];
    // x86-64 prologue: save rbp
    *(int *)(&glaurung_global_4028[0]) = ((unsigned long)((unsigned int)(*(int *)(&glaurung_global_4028[0]))) + 1);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)(&glaurung_global_4028[0]));
}
static_table_lookup fail 18 lines
// glaurung: static_table_lookup @ 0x1140
int32_t static_table_lookup(int32_t arg0) {
    int local_4;
    // x86-64 prologue: save rbp
    if (((long)(arg0) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 7) | ((long)(arg0) < 7)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    local_4 = *(int *)((0x2000 + ((long)(arg0) * 4)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

gcc -O0

1/3
counter_next fail 9 lines
// glaurung: counter_next @ 0x10f9
static unsigned char glaurung_global_4020[16] __attribute__((aligned(16)));
int32_t counter_next(int32_t arg0) {
    extern unsigned char glaurung_global_4020[16];
    // x86-64 prologue: save rbp
    *(int *)(&glaurung_global_4020[0]) = ((unsigned long)((unsigned int)(arg0)) + (unsigned long)((unsigned int)(*(int *)(&glaurung_global_4020[0]))));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)(&glaurung_global_4020[0]));
}
counter_reset pass 9 lines
// glaurung: counter_reset @ 0x111d
static unsigned char glaurung_global_4028[16] __attribute__((aligned(16)));
int32_t counter_reset(void) {
    extern unsigned char glaurung_global_4028[16];
    // x86-64 prologue: save rbp
    *(int *)(&glaurung_global_4028[0]) = ((unsigned long)((unsigned int)(*(int *)(&glaurung_global_4028[0]))) + 1);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)(&glaurung_global_4028[0]));
}
static_table_lookup fail 14 lines
// glaurung: static_table_lookup @ 0x113c
int32_t static_table_lookup(int32_t arg0) {
    // x86-64 prologue: save rbp
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 7) | ((long)(arg0) < 7)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)((((long)(arg0) * 4) + 0x2000)));
}

clang -O2

2/3
counter_next fail 9 lines
// glaurung: counter_next @ 0x1100
static unsigned char glaurung_global_4020[16] __attribute__((aligned(16)));
int32_t counter_next(int32_t arg0) {
    extern unsigned char glaurung_global_4020[16];
    int var1;
    var1 = ((unsigned int)(arg0) + *(int *)(&glaurung_global_4020[0]));
    *(int *)(&glaurung_global_4020[0]) = var1;
    return (unsigned int)(var1);
}
counter_reset pass 9 lines
// glaurung: counter_reset @ 0x1110
static unsigned char glaurung_global_4028[16] __attribute__((aligned(16)));
int32_t counter_reset(void) {
    extern unsigned char glaurung_global_4028[16];
    int var1;
    var1 = ((unsigned int)(*(int *)(&glaurung_global_4028[0])) + 1);
    *(int *)(&glaurung_global_4028[0]) = var1;
    return (unsigned int)(var1);
}
static_table_lookup pass 9 lines
// glaurung: static_table_lookup @ 0x1120
int32_t static_table_lookup(int32_t arg0) {
    long ret;
    ret = 0xffffffff;
    if (((unsigned long)((unsigned long)((unsigned int)(arg0))) <= (unsigned long)(7))) {
        ret = (unsigned long)((unsigned int)((((unsigned long)((unsigned int)(arg0)) == 0) ? 0 : (((unsigned long)((unsigned int)(arg0)) == 1) ? 1 : (((unsigned long)((unsigned int)(arg0)) == 2) ? 4 : (((unsigned long)((unsigned int)(arg0)) == 3) ? 9 : (((unsigned long)((unsigned int)(arg0)) == 4) ? 16 : (((unsigned long)((unsigned int)(arg0)) == 5) ? 25 : (((unsigned long)((unsigned int)(arg0)) == 6) ? 36 : (((unsigned long)((unsigned int)(arg0)) == 7) ? 49 : *(int *)((0x2000 + ((unsigned long)((unsigned int)(arg0)) * 4)))))))))))));
    }
    return ret;
}

gcc -O2

2/3
counter_next fail 9 lines
// glaurung: counter_next @ 0x1100
static unsigned char glaurung_global_4020[16] __attribute__((aligned(16)));
int32_t counter_next(int32_t arg0) {
    extern unsigned char glaurung_global_4020[16];
    int var1;
    var1 = ((unsigned int)(*(int *)(&glaurung_global_4020[0])) + arg0);
    *(int *)(&glaurung_global_4020[0]) = var1;
    return (unsigned int)(var1);
}
counter_reset pass 9 lines
// glaurung: counter_reset @ 0x1120
static unsigned char glaurung_global_4028[16] __attribute__((aligned(16)));
int32_t counter_reset(void) {
    extern unsigned char glaurung_global_4028[16];
    int var1;
    var1 = ((unsigned int)(*(int *)(&glaurung_global_4028[0])) + 1);
    *(int *)(&glaurung_global_4028[0]) = var1;
    return (unsigned int)(var1);
}
static_table_lookup pass 7 lines
// glaurung: static_table_lookup @ 0x1140
int32_t static_table_lookup(int32_t arg0) {
    if (((unsigned long)(7) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        return 0xffffffff;
    }
    return (unsigned int)(((long)(arg0) == 0) ? 0 : (((long)(arg0) == 1) ? 1 : (((long)(arg0) == 2) ? 4 : (((long)(arg0) == 3) ? 9 : (((long)(arg0) == 4) ? 16 : (((long)(arg0) == 5) ? 25 : (((long)(arg0) == 6) ? 36 : (((long)(arg0) == 7) ? 49 : *(int *)((0x2000 + ((long)(arg0) * 4)))))))))));
}

← 213 fixtures