Fixture 103
computed goto
C · 1 functions · 4 lanes · 0 of 4 function-lanes behave identically
4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (0/1), clang-O2 (0/1), gcc-O0 (0/1), gcc-O2 (0/1).
Labels as values (a GCC extension both compilers implement): a jump table the source builds explicitly. The dispatch is an indirect branch to an address loaded from an array, which is exactly the shape a decompiler must not mistake for a compiler-generated switch table.
#include <stdint.h>
/* Labels as values (a GCC extension both compilers implement): a jump table the
* source builds explicitly. The dispatch is an indirect branch to an address
* loaded from an array, which is exactly the shape a decompiler must not
* mistake for a compiler-generated switch table. */
#define TOKEN_MAX 16
__attribute__((noinline)) int32_t
threaded_interpreter(const int32_t *program, int32_t length, int32_t seed) {
static void *const targets[4] = {&&do_add, &&do_double, &&do_negate,
&&do_clamp};
int32_t accumulator = seed;
int32_t position = 0;
if (program == 0 || length < 0 || length > TOKEN_MAX) {
return -1;
}
while (position < length) {
int32_t opcode = program[position] & 3;
position += 1;
goto *targets[opcode];
do_add:
accumulator += position;
continue;
do_double:
accumulator = (int32_t)((uint32_t)accumulator * 2u);
continue;
do_negate:
accumulator = (int32_t)(0u - (uint32_t)accumulator);
continue;
do_clamp:
if (accumulator > 1000) {
accumulator = 1000;
}
continue;
}
return accumulator;
} 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
0/1threaded_interpreter fail 34 lines
// glaurung: threaded_interpreter @ 0x1100
int32_t threaded_interpreter(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int accumulator;
int position;
int opcode;
long local_30;
int local_4;
accumulator = arg2;
position = 0;
if ((arg0 != 0)) {
if ((0 <= (long)(arg1))) {
if ((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16))) {
goto L_1146;
}
}
}
local_4 = -1;
goto L_11d1;
L_1146: ;
goto L_114b;
L_114b: ;
if ((position < arg1)) {
opcode = ((unsigned int)(arg0[(long)(position)]) & 3);
position = ((unsigned int)(position) + 1);
local_30 = *(long *)((0x3e30 + ((long)(opcode) * 8)));
goto L_11d6;
}
local_4 = accumulator;
L_11d1: ;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
L_11d6: ;
/* unrecovered indirect jump through local_30 */
} clang -O2
0/1threaded_interpreter fail 17 lines
// glaurung: threaded_interpreter @ 0x1100
int32_t threaded_interpreter(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int opcode;
int position;
long ret;
ret = 0xffffffff;
if ((arg0 == 0)) {
return ret;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return (unsigned int)(arg2);
}
/* unrecovered indirect jump through *(long *)((0x3e30 + ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((long)arg0))) & 3))) * 8))) */
} gcc -O0
0/1threaded_interpreter fail 28 lines
// glaurung: threaded_interpreter @ 0x10f9
int32_t threaded_interpreter(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int accumulator;
int position;
int opcode;
// x86-64 prologue: save rbp
accumulator = arg2;
position = 0;
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((long)(arg1) < 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
// x86-64 epilogue: restore rbp
return 0xffffffff;
}
if ((position < arg1)) {
opcode = ((unsigned int)(arg0[(long)(position)]) & 3);
position = (position + 1);
/* unrecovered indirect jump through *(long *)((((long)(opcode) * 8) + 0x3e60)) */
}
// x86-64 epilogue: restore rbp
return (unsigned int)(accumulator);
} gcc -O2
0/1threaded_interpreter fail 16 lines
// glaurung: threaded_interpreter @ 0x1100
int32_t threaded_interpreter(const int32_t * arg0, int32_t arg1, int32_t arg2) {
int accumulator;
int position;
if ((arg0 == 0)) {
return 0xffffffff;
}
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0xffffffff;
}
accumulator = (unsigned long)((unsigned int)(arg2));
if (((unsigned long)((unsigned int)(arg1)) != 0)) {
/* unrecovered indirect jump through *(long *)((0x3e60 + ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(((long)arg0)))) & 3))) * 8))) */
}
return accumulator;
}