Fixture 126
x macros
C · 3 functions · 4 lanes · 9 of 12 function-lanes behave identically
3 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (2/3), clang-O2 (2/3), gcc-O0 (2/3).
X-macros: one list expanded into several different constructs. The source has a single point of truth, but the binary contains a table, a switch and a sum with no trace of the macro that generated them.
#include <stdint.h>
/* X-macros: one list expanded into several different constructs. The source
* has a single point of truth, but the binary contains a table, a switch and a
* sum with no trace of the macro that generated them. */
#define OPCODE_LIST(X) \
X(NOP, 0, 1) \
X(INC, 1, 2) \
X(DEC, 2, 3) \
X(SHL, 3, 5) \
X(NEG, 4, 8)
#define AS_ENUM(name, value, weight) OPCODE_##name = (value),
enum Opcode { OPCODE_LIST(AS_ENUM) OPCODE_COUNT = 5 };
#undef AS_ENUM
#define AS_WEIGHT(name, value, weight) [value] = (weight),
static const int32_t OPCODE_WEIGHTS[5] = {OPCODE_LIST(AS_WEIGHT)};
#undef AS_WEIGHT
__attribute__((noinline)) int32_t opcode_weight(int32_t opcode) {
if (opcode < 0 || opcode >= (int32_t)OPCODE_COUNT) {
return -1;
}
return OPCODE_WEIGHTS[opcode];
}
__attribute__((noinline)) int32_t apply_opcode(int32_t opcode, int32_t value) {
switch (opcode) {
#define AS_CASE(name, value_, weight) case OPCODE_##name:
AS_CASE(NOP, 0, 1)
return value;
AS_CASE(INC, 1, 2)
return (int32_t)((uint32_t)value + 1u);
AS_CASE(DEC, 2, 3)
return (int32_t)((uint32_t)value - 1u);
AS_CASE(SHL, 3, 5)
return (int32_t)((uint32_t)value << 1);
AS_CASE(NEG, 4, 8)
return (int32_t)(0u - (uint32_t)value);
#undef AS_CASE
default:
return -1;
}
}
__attribute__((noinline)) int32_t total_weight(void) {
int32_t total = 0;
#define AS_SUM(name, value, weight) total += (weight);
OPCODE_LIST(AS_SUM)
#undef AS_SUM
return total;
} 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
2/3apply_opcode pass 19 lines
// glaurung: apply_opcode @ 0x1140
int32_t apply_opcode(int32_t arg0, int32_t arg1) {
// x86-64 prologue: save rbp
switch ((unsigned int)(arg0)) {
case 0:
return (unsigned int)(arg1);
case 1:
return (unsigned int)(((unsigned int)(arg1) + 1));
case 2:
return (unsigned int)(((unsigned int)(arg1) - 1));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) << 1));
case 4:
return (unsigned int)((0 - arg1));
default:
return (unsigned int)(-1);
}
// x86-64 epilogue: restore rbp
} opcode_weight fail 18 lines
// glaurung: opcode_weight @ 0x1100
int32_t opcode_weight(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 ((5 <= (long)(arg0))) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
local_4 = *(int *)((0x2020 + ((long)(arg0) * 4)));
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} total_weight pass 13 lines
// glaurung: total_weight @ 0x11c0
int32_t total_weight(void) {
int total;
// x86-64 prologue: save rbp
total = 0;
total = ((unsigned int)(total) + 1);
total = ((unsigned int)(total) + 2);
total = ((unsigned int)(total) + 3);
total = ((unsigned int)(total) + 5);
total = ((unsigned int)(total) + 8);
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} clang -O2
2/3apply_opcode fail 7 lines
// glaurung: apply_opcode @ 0x1120
int32_t apply_opcode(int32_t arg0, int32_t arg1) {
if (((unsigned long)((unsigned long)((unsigned int)(arg0))) <= (unsigned long)(4))) {
/* unrecovered indirect jump through ((long)((int)((((unsigned long)((unsigned int)(arg0)) == 0) ? 0xfffff142 : (((unsigned long)((unsigned int)(arg0)) == 1) ? 0xfffff139 : (((unsigned long)((unsigned int)(arg0)) == 2) ? 0xfffff143 : (((unsigned long)((unsigned int)(arg0)) == 3) ? 0xfffff147 : (((unsigned long)((unsigned int)(arg0)) == 4) ? 0xfffff14a : *(int *)((0x2000 + ((unsigned long)((unsigned int)(arg0)) * 4)))))))))) + 0x2000) */
}
return 0xffffffff;
} opcode_weight pass 9 lines
// glaurung: opcode_weight @ 0x1100
int32_t opcode_weight(int32_t arg0) {
long ret;
ret = 0xffffffff;
if (((unsigned long)((unsigned long)((unsigned int)(arg0))) <= (unsigned long)(4))) {
ret = (unsigned long)((unsigned int)((((unsigned long)((unsigned int)(arg0)) == 0) ? 1 : (((unsigned long)((unsigned int)(arg0)) == 1) ? 2 : (((unsigned long)((unsigned int)(arg0)) == 2) ? 3 : (((unsigned long)((unsigned int)(arg0)) == 3) ? 5 : (((unsigned long)((unsigned int)(arg0)) == 4) ? 8 : *(int *)((0x2020 + ((unsigned long)((unsigned int)(arg0)) * 4))))))))));
}
return ret;
} total_weight pass 4 lines
// glaurung: total_weight @ 0x1150
int32_t total_weight(void) {
return 19;
} gcc -O0
2/3apply_opcode pass 19 lines
// glaurung: apply_opcode @ 0x1130
int32_t apply_opcode(int32_t arg0, int32_t arg1) {
// x86-64 prologue: save rbp
switch ((unsigned long)((unsigned int)(arg0))) {
case 0:
return (unsigned int)(arg1);
case 1:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + 1));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) - 1));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + (unsigned long)((unsigned int)(arg1))));
case 4:
return (-(unsigned long)((unsigned int)(arg1)));
default:
return 0xffffffff;
}
// x86-64 epilogue: restore rbp
} opcode_weight fail 14 lines
// glaurung: opcode_weight @ 0x10f9
int32_t opcode_weight(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)) == 4) | ((long)(arg0) < 4)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
// x86-64 epilogue: restore rbp
return (unsigned int)(*(int *)((((long)(arg0) * 4) + 0x2000)));
} total_weight pass 13 lines
// glaurung: total_weight @ 0x1192
int32_t total_weight(void) {
int total;
// x86-64 prologue: save rbp
total = 0;
total = (total + 1);
total = (total + 2);
total = (total + 3);
total = (total + 5);
total = (total + 8);
// x86-64 epilogue: restore rbp
return (unsigned int)(total);
} gcc -O2
3/3apply_opcode pass 17 lines
// glaurung: apply_opcode @ 0x1130
int32_t apply_opcode(int32_t arg0, int32_t arg1) {
switch ((unsigned long)((unsigned int)(arg0))) {
case 0:
return (unsigned int)(arg1);
case 1:
return (unsigned int)((arg1 + 1));
case 2:
return (unsigned int)((arg1 - 1));
case 3:
return (unsigned int)((arg1 + arg1));
case 4:
return (-(unsigned long)((unsigned int)(arg1)));
default:
return (unsigned int)(-1);
}
} opcode_weight pass 7 lines
// glaurung: opcode_weight @ 0x1100
int32_t opcode_weight(int32_t arg0) {
if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
return 0xffffffff;
}
return (unsigned int)(((long)(arg0) == 0) ? 1 : (((long)(arg0) == 1) ? 2 : (((long)(arg0) == 2) ? 3 : (((long)(arg0) == 3) ? 5 : (((long)(arg0) == 4) ? 8 : *(int *)((0x2020 + ((long)(arg0) * 4))))))));
} total_weight pass 5 lines
// glaurung: total_weight @ 0x1180
int32_t total_weight(void) {
int total;
return 19;
}