Fixture 204
adjacent dispatch tables
C · 5 functions · 4 lanes · 19 of 20 function-lanes behave identically
One lane has a function that returns a different result after decompilation: clang-O2 (4/5).
Several guard-free switch dispatches in ONE translation unit, so their jump tables land ADJACENT in .rodata.
WHY THIS SHAPE HAS ITS OWN FIXTURE. analysis::jump_table:: discover_jump_tables recovers a table by taking the LONGEST run of section words that decode to executable addresses. That rule has no end marker: when a second table begins immediately after the first, the scan runs straight through the boundary and reports one table of N1 + N2 + ... entries. The over-read entries are table 2's offsets read relative to table 1's base, so they resolve to T_j - 4*N1 — addresses that are still inside .text and therefore still pass in_exec_regions, which is why nothing downstream rejects them.
cfg::discover_function has exactly one defence against that: a dispatch whose index carries no range check is attached SPECULATIVELY (TentativeDispatchEdges::needs_bound_proof), and a whole-CFG must-dataflow fixed point then has to prove a prefix, after which trim_unproven_dispatch_edges deletes the rest. Both halves of that only matter when the over-read actually happens, and it only happens when two tables abut. 148_dispatch_obfuscation has a single permuted switch, so its table is the last thing in its .rodata neighbourhood and the scan stops on its own; measured over the whole corpus at gcc/clang x O0/O1/O2 (1,107 binaries) the bound-proof path fires 8 times and the trim fires ZERO times. This file is the missing input: it makes the tables abut on purpose.
Each selector goes through a byte permutation table, which is what stops the compiler emitting its own cmp key, N; ja default range check — a value loaded from a uint8_t array is already provably in [0, 255] and, after the compiler propagates the table contents, in [0, 7]. That is what makes the dispatch guard-free, and a guard-free dispatch is the only kind that reaches the bound-proof path at all.
The permutations are deliberately not the identity and not monotone, so a recovery that reconstructs the table but drops the mapping produces a well-structured program that computes the wrong case for every selector.
Safety: every index is masked to the map's size before the load, every map entry is less than the number of cases, and all arithmetic runs through uint32_t, so no input can overflow a signed type or read out of bounds.
/* Several guard-free `switch` dispatches in ONE translation unit, so their jump
* tables land ADJACENT in `.rodata`.
*
* WHY THIS SHAPE HAS ITS OWN FIXTURE. `analysis::jump_table::
* discover_jump_tables` recovers a table by taking the LONGEST run of section
* words that decode to executable addresses. That rule has no end marker: when
* a second table begins immediately after the first, the scan runs straight
* through the boundary and reports one table of `N1 + N2 + ...` entries. The
* over-read entries are table 2's offsets read relative to table 1's base, so
* they resolve to `T_j - 4*N1` — addresses that are still inside `.text` and
* therefore still pass `in_exec_regions`, which is why nothing downstream
* rejects them.
*
* `cfg::discover_function` has exactly one defence against that: a dispatch
* whose index carries no range check is attached SPECULATIVELY
* (`TentativeDispatchEdges::needs_bound_proof`), and a whole-CFG must-dataflow
* fixed point then has to prove a prefix, after which
* `trim_unproven_dispatch_edges` deletes the rest. Both halves of that only
* matter when the over-read actually happens, and it only happens when two
* tables abut. `148_dispatch_obfuscation` has a single permuted switch, so its
* table is the last thing in its `.rodata` neighbourhood and the scan stops on
* its own; measured over the whole corpus at gcc/clang x O0/O1/O2 (1,107
* binaries) the bound-proof path fires 8 times and the trim fires ZERO times.
* This file is the missing input: it makes the tables abut on purpose.
*
* Each selector goes through a byte permutation table, which is what stops the
* compiler emitting its own `cmp key, N; ja default` range check — a value
* loaded from a `uint8_t` array is already provably in `[0, 255]` and, after
* the compiler propagates the table contents, in `[0, 7]`. That is what makes
* the dispatch guard-free, and a guard-free dispatch is the only kind that
* reaches the bound-proof path at all.
*
* The permutations are deliberately not the identity and not monotone, so a
* recovery that reconstructs the table but drops the mapping produces a
* well-structured program that computes the wrong case for every selector.
*
* Safety: every index is masked to the map's size before the load, every map
* entry is less than the number of cases, and all arithmetic runs through
* `uint32_t`, so no input can overflow a signed type or read out of bounds.
*/
#include <stdint.h>
#define ADT204_MAP_SIZE 8u
/* Three distinct permutations of 0..7. Distinct so that a decompiler cannot
* satisfy all three switches with one recovered mapping. */
static const uint8_t ADT204_MAP_A[ADT204_MAP_SIZE] = {5, 3, 7, 1, 6, 0, 4, 2};
static const uint8_t ADT204_MAP_B[ADT204_MAP_SIZE] = {2, 6, 0, 4, 1, 7, 3, 5};
static const uint8_t ADT204_MAP_C[ADT204_MAP_SIZE] = {7, 1, 5, 3, 0, 6, 2, 4};
/* First of the three abutting tables. Its scan is the one that runs off the
* end into the other two. */
__attribute__((noinline)) int32_t adt204_switch_a(int32_t selector, int32_t value) {
uint32_t key = ADT204_MAP_A[(uint32_t)selector & (ADT204_MAP_SIZE - 1u)];
uint32_t v = (uint32_t)value;
switch (key) {
case 0u:
return (int32_t)(v + 1u);
case 1u:
return (int32_t)(v * 2u);
case 2u:
return (int32_t)(v ^ 0x5a5au);
case 3u:
return (int32_t)(v >> 1);
case 4u:
return (int32_t)(v - 7u);
case 5u:
return (int32_t)(v & 0xffu);
case 6u:
return (int32_t)(v | 0x100u);
default:
return (int32_t)(0u - v);
}
}
/* Second table. Its entries are what the first table's over-read misreads. */
__attribute__((noinline)) int32_t adt204_switch_b(int32_t selector, int32_t value) {
uint32_t key = ADT204_MAP_B[(uint32_t)selector & (ADT204_MAP_SIZE - 1u)];
uint32_t v = (uint32_t)value;
switch (key) {
case 0u:
return (int32_t)(v + 11u);
case 1u:
return (int32_t)(v * 3u);
case 2u:
return (int32_t)(v ^ 0x1234u);
case 3u:
return (int32_t)(v >> 2);
case 4u:
return (int32_t)(v - 17u);
case 5u:
return (int32_t)(v & 0xfffu);
case 6u:
return (int32_t)(v | 0x200u);
default:
return (int32_t)(1u - v);
}
}
/* Third table, so the over-read has to cross two boundaries rather than one.
* Two boundaries matter: a trim that keeps "everything up to the first
* discontinuity" and a trim that keeps a proven prefix behave identically with
* one boundary and differently with two. */
__attribute__((noinline)) int32_t adt204_switch_c(int32_t selector, int32_t value) {
uint32_t key = ADT204_MAP_C[(uint32_t)selector & (ADT204_MAP_SIZE - 1u)];
uint32_t v = (uint32_t)value;
switch (key) {
case 0u:
return (int32_t)(v + 21u);
case 1u:
return (int32_t)(v * 5u);
case 2u:
return (int32_t)(v ^ 0x4321u);
case 3u:
return (int32_t)(v >> 3);
case 4u:
return (int32_t)(v - 27u);
case 5u:
return (int32_t)(v & 0xffffu);
case 6u:
return (int32_t)(v | 0x400u);
default:
return (int32_t)(2u - v);
}
}
/* Same case bodies as `adt204_switch_a`, but the selector is range-checked in
* the source rather than through a permutation table. Its role is lane
* dependent, and that is the useful part.
*
* At gcc it is the NEGATIVE CONTROL: gcc emits `cmp sel,7; ja default` with the
* dispatch on the fall-through, which is the one edge polarity
* `cfg::ctrl_flow::guard_bound_reaches_fallthrough` models, so the switch
* resolves and a change that breaks this function damaged ordinary guarded
* switches rather than the speculative path it was aimed at.
*
* At clang it is a SECOND POSITIVE, for a different reason than the three
* above: clang reaches the dispatch on the TAKEN edge of a `jb`, and the taken
* edge of a below/below-or-equal branch is not modelled at all — only the
* fall-through of `ja`/`jae` is. Same source, same guard, opposite branch
* polarity, and the bound is lost. That asymmetry is why a dispatch block with
* several `jbe` predecessors (measured in `/usr/bin/3cpio` at 0x2f4bf,
* `/usr/bin/aarch64-linux-gnu-ld.bfd` at 0x18119 and
* `/usr/bin/aarch64-linux-gnu-objdump` at 0x20c21) currently gets its bound
* from ONE predecessor's fall-through and nothing from the others. */
__attribute__((noinline)) int32_t adt204_guarded_control(int32_t selector, int32_t value) {
uint32_t v = (uint32_t)value;
if (selector < 0 || selector > 7) {
return -1;
}
switch ((uint32_t)selector) {
case 0u:
return (int32_t)(v + 1u);
case 1u:
return (int32_t)(v * 2u);
case 2u:
return (int32_t)(v ^ 0x5a5au);
case 3u:
return (int32_t)(v >> 1);
case 4u:
return (int32_t)(v - 7u);
case 5u:
return (int32_t)(v & 0xffu);
case 6u:
return (int32_t)(v | 0x100u);
default:
return (int32_t)(0u - v);
}
}
/* Drives all three abutting dispatches from one selector, so a recovery that
* loses the arms of only the FIRST table (the one the scan over-reads from)
* still produces an observably different result. */
__attribute__((noinline)) int32_t adt204_chained(int32_t selector, int32_t value) {
int32_t a = adt204_switch_a(selector, value);
int32_t b = adt204_switch_b(selector, a);
int32_t c = adt204_switch_c(selector, b);
return (int32_t)((uint32_t)c ^ (uint32_t)a);
} 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 -O2
4/5adt204_chained pass 21 lines
// glaurung: adt204_chained @ 0x1280
int32_t adt204_chained(int32_t arg0, int32_t arg1) {
extern int adt204_switch_a(int, int);
extern int adt204_switch_b(int, int);
extern int adt204_switch_c(int, int);
int a;
int b;
int c;
long var0;
int var1;
int var4;
int var6;
// x86-64 prologue: save callee registers, frame 24 bytes
var0 = (unsigned long)((unsigned int)(arg0));
var1 = adt204_switch_a(arg0, arg1);
a = (unsigned long)((unsigned int)(var1));
var4 = adt204_switch_b((unsigned long)((unsigned int)(var0)), (unsigned long)((unsigned int)(var1)));
var6 = adt204_switch_c((unsigned long)((unsigned int)(var0)), (unsigned long)((unsigned int)(var4)));
// x86-64 epilogue: restore callee registers
return (unsigned int)((var6 ^ a));
} adt204_guarded_control fail 12 lines
// glaurung: adt204_guarded_control @ 0x1230
int32_t adt204_guarded_control(int32_t arg0, int32_t arg1) {
long ret;
ret = 0xffffffff;
if (((unsigned long)(7) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
return ret;
}
if (((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)(7))) {
/* unrecovered indirect jump through ((long)((int)((((unsigned long)((unsigned int)(arg0)) == 0) ? 0xfffff1fa : (((unsigned long)((unsigned int)(arg0)) == 1) ? 0xfffff203 : (((unsigned long)((unsigned int)(arg0)) == 2) ? 0xfffff207 : (((unsigned long)((unsigned int)(arg0)) == 3) ? 0xfffff20f : (((unsigned long)((unsigned int)(arg0)) == 4) ? 0xfffff213 : (((unsigned long)((unsigned int)(arg0)) == 5) ? 0xfffff218 : (((unsigned long)((unsigned int)(arg0)) == 6) ? 0xfffff21d : *(int *)((0x2054 + ((unsigned long)((unsigned int)(arg0)) * 4)))))))))))) + 0x2054) */
}
return (unsigned int)((-arg1));
} adt204_switch_a pass 21 lines
// glaurung: adt204_switch_a @ 0x1130
int32_t adt204_switch_a(int32_t arg0, int32_t arg1) {
switch ((unsigned int)((unsigned char)((((unsigned long)((unsigned int)((arg0 & 7))) == 0) ? 5 : (((unsigned long)((unsigned int)((arg0 & 7))) == 1) ? 3 : (((unsigned long)((unsigned int)((arg0 & 7))) == 2) ? 7 : (((unsigned long)((unsigned int)((arg0 & 7))) == 3) ? 1 : (((unsigned long)((unsigned int)((arg0 & 7))) == 4) ? 6 : (((unsigned long)((unsigned int)((arg0 & 7))) == 5) ? 0 : (((unsigned long)((unsigned int)((arg0 & 7))) == 6) ? 4 : (((unsigned long)((unsigned int)((arg0 & 7))) == 7) ? 2 : *(char *)(((unsigned long)((unsigned int)((arg0 & 7))) + 0x2070))))))))))))) {
case 0:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + 1));
case 1:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + (unsigned long)((unsigned int)(arg1))));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) ^ 0x5a5a));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 1));
case 4:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) - 7));
case 5:
return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(arg1)) & 255)));
case 6:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) | 256));
default:
return (-(unsigned long)((unsigned int)(arg1)));
}
} adt204_switch_b pass 21 lines
// glaurung: adt204_switch_b @ 0x1180
int32_t adt204_switch_b(int32_t arg0, int32_t arg1) {
switch ((unsigned int)((unsigned char)((((unsigned long)((unsigned int)((arg0 & 7))) == 0) ? 2 : (((unsigned long)((unsigned int)((arg0 & 7))) == 1) ? 6 : (((unsigned long)((unsigned int)((arg0 & 7))) == 2) ? 0 : (((unsigned long)((unsigned int)((arg0 & 7))) == 3) ? 4 : (((unsigned long)((unsigned int)((arg0 & 7))) == 4) ? 1 : (((unsigned long)((unsigned int)((arg0 & 7))) == 5) ? 7 : (((unsigned long)((unsigned int)((arg0 & 7))) == 6) ? 3 : (((unsigned long)((unsigned int)((arg0 & 7))) == 7) ? 5 : *(char *)(((unsigned long)((unsigned int)((arg0 & 7))) + 0x2078))))))))))))) {
case 0:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + 11));
case 1:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + ((unsigned long)((unsigned int)(arg1)) * 2)));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) ^ 0x1234));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 2));
case 4:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) - 17));
case 5:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) & 4095));
case 6:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) | 512));
default:
return (unsigned int)((1 - (unsigned long)((unsigned int)(arg1))));
}
} adt204_switch_c pass 21 lines
// glaurung: adt204_switch_c @ 0x11e0
int32_t adt204_switch_c(int32_t arg0, int32_t arg1) {
switch ((unsigned int)((unsigned char)((((unsigned long)((unsigned int)((arg0 & 7))) == 0) ? 7 : (((unsigned long)((unsigned int)((arg0 & 7))) == 1) ? 1 : (((unsigned long)((unsigned int)((arg0 & 7))) == 2) ? 5 : (((unsigned long)((unsigned int)((arg0 & 7))) == 3) ? 3 : (((unsigned long)((unsigned int)((arg0 & 7))) == 4) ? 0 : (((unsigned long)((unsigned int)((arg0 & 7))) == 5) ? 6 : (((unsigned long)((unsigned int)((arg0 & 7))) == 6) ? 2 : (((unsigned long)((unsigned int)((arg0 & 7))) == 7) ? 4 : *(char *)(((unsigned long)((unsigned int)((arg0 & 7))) + 0x2080))))))))))))) {
case 0:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + 21));
case 1:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + ((unsigned long)((unsigned int)(arg1)) * 4)));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) ^ 0x4321));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 3));
case 4:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) - 27));
case 5:
return (unsigned int)((unsigned short)(((unsigned long)((unsigned int)(arg1)) & 0xffff)));
case 6:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) | 1024));
default:
return (unsigned int)((2 - (unsigned long)((unsigned int)(arg1))));
}
} clang -O0
5/5adt204_chained pass 21 lines
// glaurung: adt204_chained @ 0x1440
int32_t adt204_chained(int32_t arg0, int32_t arg1) {
extern int adt204_switch_a(int, int);
extern int adt204_switch_b(int, int);
extern int adt204_switch_c(int, int);
int a;
int b;
int c;
int var0;
int var2;
int var4;
// x86-64 prologue: save rbp, frame 32 bytes
var0 = adt204_switch_a((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)));
a = var0;
var2 = adt204_switch_b((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(a)));
b = var2;
var4 = adt204_switch_c((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(b)));
c = var4;
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(c)) ^ a));
} adt204_guarded_control pass 36 lines
// glaurung: adt204_guarded_control @ 0x1370
int32_t adt204_guarded_control(int32_t arg0, int32_t arg1) {
unsigned int v;
int local_4;
// x86-64 prologue: save rbp
v = arg1;
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);
}
switch ((unsigned int)(arg0)) {
case 0:
return (unsigned int)((v + 1));
case 1:
return (unsigned int)((v << 1));
case 2:
return (unsigned int)((v ^ 0x5a5a));
case 3:
return (unsigned int)(((unsigned int)(v) >> 1));
case 4:
return (unsigned int)((v - 7));
case 5:
return (unsigned int)((v & 255));
case 6:
return (unsigned int)((v | 256));
default:
return (unsigned int)((0 - v));
}
// x86-64 epilogue: restore rbp
} adt204_switch_a pass 27 lines
// glaurung: adt204_switch_a @ 0x1130
int32_t adt204_switch_a(int32_t arg0, int32_t arg1) {
unsigned int key;
unsigned int v;
// x86-64 prologue: save rbp
key = (unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 0) ? 5 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 1) ? 3 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 2) ? 7 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 3) ? 1 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 4) ? 6 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 5) ? 0 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 6) ? 4 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 7) ? 2 : *(char *)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) + 0x2070))))))))));
v = arg1;
switch (key) {
case 0:
return (unsigned int)((v + 1));
case 1:
return (unsigned int)((v << 1));
case 2:
return (unsigned int)((v ^ 0x5a5a));
case 3:
return (unsigned int)(((unsigned int)(v) >> 1));
case 4:
return (unsigned int)((v - 7));
case 5:
return (unsigned int)((v & 255));
case 6:
return (unsigned int)((v | 256));
default:
return (unsigned int)((0 - v));
}
// x86-64 epilogue: restore rbp
} adt204_switch_b pass 27 lines
// glaurung: adt204_switch_b @ 0x11f0
int32_t adt204_switch_b(int32_t arg0, int32_t arg1) {
unsigned int key;
unsigned int v;
// x86-64 prologue: save rbp
key = (unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 0) ? 2 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 1) ? 6 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 2) ? 0 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 3) ? 4 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 4) ? 1 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 5) ? 7 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 6) ? 3 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 7) ? 5 : *(char *)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) + 0x2078))))))))));
v = arg1;
switch (key) {
case 0:
return (unsigned int)((v + 11));
case 1:
return (unsigned int)((v * 3));
case 2:
return (unsigned int)((v ^ 0x1234));
case 3:
return (unsigned int)(((unsigned int)(v) >> 2));
case 4:
return (unsigned int)((v - 17));
case 5:
return (unsigned int)((v & 4095));
case 6:
return (unsigned int)((v | 512));
default:
return (unsigned int)((1 - v));
}
// x86-64 epilogue: restore rbp
} adt204_switch_c pass 27 lines
// glaurung: adt204_switch_c @ 0x12b0
int32_t adt204_switch_c(int32_t arg0, int32_t arg1) {
unsigned int key;
unsigned int v;
// x86-64 prologue: save rbp
key = (unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 0) ? 7 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 1) ? 1 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 2) ? 5 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 3) ? 3 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 4) ? 0 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 5) ? 6 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 6) ? 2 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 7) ? 4 : *(char *)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) + 0x2080))))))))));
v = arg1;
switch (key) {
case 0:
return (unsigned int)((v + 21));
case 1:
return (unsigned int)((v * 5));
case 2:
return (unsigned int)((v ^ 0x4321));
case 3:
return (unsigned int)(((unsigned int)(v) >> 3));
case 4:
return (unsigned int)((v - 27));
case 5:
return (unsigned int)((v & 0xffff));
case 6:
return (unsigned int)((v | 1024));
default:
return (unsigned int)((2 - v));
}
// x86-64 epilogue: restore rbp
} gcc -O0
5/5adt204_chained pass 21 lines
// glaurung: adt204_chained @ 0x13bf
int32_t adt204_chained(int32_t arg0, int32_t arg1) {
extern int adt204_switch_a(int, int);
extern int adt204_switch_b(int, int);
extern int adt204_switch_c(int, int);
int a;
int b;
int c;
int var10;
int var2;
int var6;
// x86-64 prologue: save rbp, frame 32 bytes
var2 = adt204_switch_a((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)));
a = var2;
var6 = adt204_switch_b((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(a)));
b = var6;
var10 = adt204_switch_c((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(b)));
c = var10;
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(a)) ^ (unsigned long)((unsigned int)(c))));
} adt204_guarded_control pass 33 lines
// glaurung: adt204_guarded_control @ 0x132e
int32_t adt204_guarded_control(int32_t arg0, int32_t arg1) {
unsigned int v;
// x86-64 prologue: save rbp
v = arg1;
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;
}
switch ((unsigned long)((unsigned int)(arg0))) {
case 0:
return (unsigned int)((v + 1));
case 1:
return (unsigned int)((v + v));
case 2:
return (unsigned int)((v ^ 0x5a5a));
case 3:
return (unsigned int)(((unsigned int)(v) >> 1));
case 4:
return (unsigned int)((v - 7));
case 5:
return (unsigned int)((unsigned char)((v & 255)));
case 6:
return ((v & -0xff01LL) | ((((((unsigned int)(v) >> 8) & 255) | 1) & 255) << 8));
default:
return (-(unsigned long)(v));
}
// x86-64 epilogue: restore rbp
} adt204_switch_a pass 27 lines
// glaurung: adt204_switch_a @ 0x1159
int32_t adt204_switch_a(int32_t arg0, int32_t arg1) {
unsigned int key;
unsigned int v;
// x86-64 prologue: save rbp
key = (unsigned char)(((unsigned int)((unsigned char)((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 0) ? 5 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 1) ? 3 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 2) ? 7 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 3) ? 1 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 4) ? 6 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 5) ? 0 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 6) ? 4 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 7) ? 2 : *(char *)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) + 0x2000)))))))))))) & 255));
v = arg1;
switch (key) {
case 0:
return (unsigned int)(((unsigned long)(v) + 1));
case 1:
return (unsigned int)(((unsigned long)(v) + (unsigned long)(v)));
case 2:
return (unsigned int)(((unsigned long)(v) ^ 0x5a5a));
case 3:
return (unsigned int)(((unsigned long)(v) >> 1));
case 4:
return (unsigned int)(((unsigned long)(v) - 7));
case 5:
return (unsigned int)((unsigned char)(((unsigned long)(v) & 255)));
case 6:
return (((unsigned long)(v) & -0xff01LL) | ((((((unsigned long)(v) >> 8) & 255) | 1) & 255) << 8));
default:
return (-(unsigned long)(v));
}
// x86-64 epilogue: restore rbp
} adt204_switch_b pass 27 lines
// glaurung: adt204_switch_b @ 0x11ef
int32_t adt204_switch_b(int32_t arg0, int32_t arg1) {
unsigned int key;
unsigned int v;
// x86-64 prologue: save rbp
key = (unsigned char)(((unsigned int)((unsigned char)((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 0) ? 2 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 1) ? 6 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 2) ? 0 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 3) ? 4 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 4) ? 1 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 5) ? 7 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 6) ? 3 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 7) ? 5 : *(char *)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) + 0x2008)))))))))))) & 255));
v = arg1;
switch (key) {
case 0:
return (unsigned int)(((unsigned long)(v) + 11));
case 1:
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(v) + (unsigned long)(v)))) + (unsigned long)(v)));
case 2:
return (unsigned int)(((unsigned long)(v) ^ 0x1234));
case 3:
return (unsigned int)(((unsigned long)(v) >> 2));
case 4:
return (unsigned int)(((unsigned long)(v) - 17));
case 5:
return (unsigned int)(((unsigned long)(v) & 4095));
case 6:
return (((unsigned long)(v) & -0xff01LL) | ((((((unsigned long)(v) >> 8) & 255) | 2) & 255) << 8));
default:
return (unsigned int)((1 - v));
}
// x86-64 epilogue: restore rbp
} adt204_switch_c pass 27 lines
// glaurung: adt204_switch_c @ 0x128f
int32_t adt204_switch_c(int32_t arg0, int32_t arg1) {
unsigned int key;
unsigned int v;
// x86-64 prologue: save rbp
key = (unsigned char)(((unsigned int)((unsigned char)((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 0) ? 7 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 1) ? 1 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 2) ? 5 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 3) ? 3 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 4) ? 0 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 5) ? 6 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 6) ? 2 : (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) == 7) ? 4 : *(char *)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7))) + 0x2010)))))))))))) & 255));
v = arg1;
switch (key) {
case 0:
return (unsigned int)(((unsigned long)(v) + 21));
case 1:
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(v) << 2))) + (unsigned long)(v)));
case 2:
return (unsigned int)(((unsigned long)(v) ^ 0x4321));
case 3:
return (unsigned int)(((unsigned long)(v) >> 3));
case 4:
return (unsigned int)(((unsigned long)(v) - 27));
case 5:
return (unsigned int)((unsigned short)(((unsigned long)(v) & 0xffff)));
case 6:
return (((unsigned long)(v) & -0xff01LL) | ((((((unsigned long)(v) >> 8) & 255) | 4) & 255) << 8));
default:
return (unsigned int)((2 - v));
}
// x86-64 epilogue: restore rbp
} gcc -O2
5/5adt204_chained pass 20 lines
// glaurung: adt204_chained @ 0x1370
int32_t adt204_chained(int32_t arg0, int32_t arg1) {
extern int adt204_switch_a(int, int);
extern int adt204_switch_b(int, int);
extern int adt204_switch_c(int, int);
int a;
int b;
int c;
long var0;
int var1;
int var4;
int var6;
var0 = (unsigned long)((unsigned int)(arg0));
var1 = adt204_switch_a(arg0, arg1);
a = (unsigned long)((unsigned int)(var1));
var4 = adt204_switch_b((unsigned long)((unsigned int)(var0)), (unsigned long)((unsigned int)(var1)));
var6 = adt204_switch_c((unsigned long)((unsigned int)(var0)), (unsigned long)((unsigned int)(var4)));
// x86-64 epilogue: tear down frame
return (unsigned int)((var6 ^ a));
} adt204_guarded_control pass 24 lines
// glaurung: adt204_guarded_control @ 0x12f0
int32_t adt204_guarded_control(int32_t arg0, int32_t arg1) {
if (((unsigned long)(7) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
return 0xffffffff;
}
switch ((unsigned long)((unsigned int)(arg0))) {
case 0:
return (unsigned int)((arg1 + 1));
case 1:
return (unsigned int)((arg1 + arg1));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) ^ 0x5a5a));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 1));
case 4:
return (unsigned int)((arg1 - 7));
case 5:
return (unsigned int)((unsigned char)((arg1 & 255)));
case 6:
return (((unsigned long)((unsigned int)(arg1)) & -0xff01LL) | ((((((unsigned long)((unsigned int)(arg1)) >> 8) & 255) | 1) & 255) << 8));
default:
return (-(unsigned long)((unsigned int)(arg1)));
}
} adt204_switch_a pass 24 lines
// glaurung: adt204_switch_a @ 0x1160
int32_t adt204_switch_a(int32_t arg0, int32_t arg1) {
long var2;
var2 = (unsigned long)((unsigned int)((arg0 & 7)));
if (((unsigned long)(6) < (unsigned long)((unsigned long)((unsigned char)(((var2 == 0) ? 5 : ((var2 == 1) ? 3 : ((var2 == 2) ? 7 : ((var2 == 3) ? 1 : ((var2 == 4) ? 6 : ((var2 == 5) ? 0 : ((var2 == 6) ? 4 : ((var2 == 7) ? 2 : *(char *)((0x2080 + var2))))))))))))))) {
return (-(unsigned long)((unsigned int)(arg1)));
}
switch ((unsigned int)((unsigned char)(((var2 == 0) ? 5 : ((var2 == 1) ? 3 : ((var2 == 2) ? 7 : ((var2 == 3) ? 1 : ((var2 == 4) ? 6 : ((var2 == 5) ? 0 : ((var2 == 6) ? 4 : ((var2 == 7) ? 2 : *(char *)((0x2080 + var2))))))))))))) {
case 0:
return (unsigned int)((arg1 + 1));
case 1:
return (unsigned int)((arg1 + arg1));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) ^ 0x5a5a));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 1));
case 4:
return (unsigned int)((arg1 - 7));
case 5:
return (unsigned int)((unsigned char)((arg1 & 255)));
case 6:
return (((unsigned long)((unsigned int)(arg1)) & -0xff01LL) | ((((((unsigned long)((unsigned int)(arg1)) >> 8) & 255) | 1) & 255) << 8));
}
} adt204_switch_b pass 24 lines
// glaurung: adt204_switch_b @ 0x11e0
int32_t adt204_switch_b(int32_t arg0, int32_t arg1) {
long var2;
var2 = (unsigned long)((unsigned int)((arg0 & 7)));
if (((unsigned long)(6) < (unsigned long)((unsigned long)((unsigned char)(((var2 == 0) ? 2 : ((var2 == 1) ? 6 : ((var2 == 2) ? 0 : ((var2 == 3) ? 4 : ((var2 == 4) ? 1 : ((var2 == 5) ? 7 : ((var2 == 6) ? 3 : ((var2 == 7) ? 5 : *(char *)((0x2078 + var2))))))))))))))) {
return (unsigned int)((1 - arg1));
}
switch ((unsigned int)((unsigned char)(((var2 == 0) ? 2 : ((var2 == 1) ? 6 : ((var2 == 2) ? 0 : ((var2 == 3) ? 4 : ((var2 == 4) ? 1 : ((var2 == 5) ? 7 : ((var2 == 6) ? 3 : ((var2 == 7) ? 5 : *(char *)((0x2078 + var2))))))))))))) {
case 0:
return (unsigned int)((arg1 + 11));
case 1:
return (unsigned int)((arg1 + (arg1 * 2)));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) ^ 0x1234));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 2));
case 4:
return (unsigned int)((arg1 - 17));
case 5:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) & 4095));
case 6:
return (((unsigned long)((unsigned int)(arg1)) & -0xff01LL) | ((((((unsigned long)((unsigned int)(arg1)) >> 8) & 255) | 2) & 255) << 8));
}
} adt204_switch_c pass 24 lines
// glaurung: adt204_switch_c @ 0x1270
int32_t adt204_switch_c(int32_t arg0, int32_t arg1) {
long var2;
var2 = (unsigned long)((unsigned int)((arg0 & 7)));
if (((unsigned long)(6) < (unsigned long)((unsigned long)((unsigned char)(((var2 == 0) ? 7 : ((var2 == 1) ? 1 : ((var2 == 2) ? 5 : ((var2 == 3) ? 3 : ((var2 == 4) ? 0 : ((var2 == 5) ? 6 : ((var2 == 6) ? 2 : ((var2 == 7) ? 4 : *(char *)((0x2070 + var2))))))))))))))) {
return (unsigned int)((2 - arg1));
}
switch ((unsigned int)((unsigned char)(((var2 == 0) ? 7 : ((var2 == 1) ? 1 : ((var2 == 2) ? 5 : ((var2 == 3) ? 3 : ((var2 == 4) ? 0 : ((var2 == 5) ? 6 : ((var2 == 6) ? 2 : ((var2 == 7) ? 4 : *(char *)((0x2070 + var2))))))))))))) {
case 0:
return (unsigned int)((arg1 + 21));
case 1:
return (unsigned int)((arg1 + (arg1 * 4)));
case 2:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) ^ 0x4321));
case 3:
return (unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 3));
case 4:
return (unsigned int)((arg1 - 27));
case 5:
return (unsigned int)((unsigned short)((arg1 & 0xffff)));
case 6:
return (((unsigned long)((unsigned int)(arg1)) & -0xff01LL) | ((((((unsigned long)((unsigned int)(arg1)) >> 8) & 255) | 4) & 255) << 8));
}
}