Fixture 161
packed struct layout
C · 5 functions · 4 lanes · 18 of 20 function-lanes behave identically
2 of 4 lanes have a function that returns a different result after decompilation: clang-O2 (4/5), gcc-O2 (4/5).
__attribute__((packed)) wire records: the same four members declared twice, once with natural alignment and once packed. The natural struct is 12 bytes (kind @0, 3 bytes of padding, seq @4, port @8, ttl @10, 1 byte of tail padding); the packed struct is 8 bytes with seq @1 and port @5 -- both of them unaligned. Nothing in the C source says "1" and "5"; the attribute does, and every offset in the emitted code is a resolved constant.
Why this stresses a decompiler: after lowering, the two layouts are just different immediate displacements off a base register, and a packed 4-byte load at displacement 1 looks exactly like a natural one at displacement 4. A decompiler that re-types the buffer with a *plausible* aggregate rather than the actual one produces C that compiles, type-checks, reads well, and decodes a different byte range -- a shift of the whole record by three bytes, structurally invisible and behaviorally fatal. The size/offset probes here pin the layout as an observable, and encode/decode pin that the packed member accesses really do straddle the alignment boundaries.
UB notes: the wire bytes are moved through an unsigned char * view of a whole struct object (character-type access aliases everything, C11 6.5p7), never by casting a byte buffer to a struct pointer, and never by taking the address of a packed member (which is both a diagnostic and a misaligned pointer). Every packed byte is covered by a member, so no indeterminate padding is ever read.
/* 161_packed_struct_layout.c
*
* `__attribute__((packed))` wire records: the same four members declared twice,
* once with natural alignment and once packed. The natural struct is 12 bytes
* (kind @0, 3 bytes of padding, seq @4, port @8, ttl @10, 1 byte of tail
* padding); the packed struct is 8 bytes with seq @1 and port @5 -- both of them
* unaligned. Nothing in the C source says "1" and "5"; the attribute does, and
* every offset in the emitted code is a resolved constant.
*
* Why this stresses a decompiler: after lowering, the two layouts are just
* different immediate displacements off a base register, and a packed 4-byte
* load at displacement 1 looks exactly like a natural one at displacement 4.
* A decompiler that re-types the buffer with a *plausible* aggregate rather
* than the actual one produces C that compiles, type-checks, reads well, and
* decodes a different byte range -- a shift of the whole record by three bytes,
* structurally invisible and behaviorally fatal. The size/offset probes here
* pin the layout as an observable, and encode/decode pin that the packed member
* accesses really do straddle the alignment boundaries.
*
* UB notes: the wire bytes are moved through an `unsigned char *` view of a
* whole struct object (character-type access aliases everything, C11 6.5p7),
* never by casting a byte buffer to a struct pointer, and never by taking the
* address of a packed member (which is both a diagnostic and a misaligned
* pointer). Every packed byte is covered by a member, so no indeterminate
* padding is ever read.
*/
#include <stddef.h>
#include <stdint.h>
#define PK161_WIRE_BYTES 8
#define PK161_MAX_BUF 16
/* Host-natural layout: the compiler is free to insert padding. */
struct pk161_natural {
uint8_t kind;
uint32_t seq;
uint16_t port;
uint8_t ttl;
};
/* The wire layout: no padding anywhere, so seq and port are unaligned. */
struct pk161_wire {
uint8_t kind; /* offset 0 */
uint32_t seq; /* offset 1 -- unaligned 4-byte member */
uint16_t port; /* offset 5 -- unaligned 2-byte member */
uint8_t ttl; /* offset 7 */
} __attribute__((packed));
_Static_assert(sizeof(struct pk161_wire) == PK161_WIRE_BYTES,
"packed wire record must be exactly 8 bytes");
_Static_assert(sizeof(struct pk161_natural) > sizeof(struct pk161_wire),
"the natural layout must be the padded one");
/* Clamp any caller-supplied length into [0, PK161_MAX_BUF] before it is used in
* arithmetic, so a hostile INT_MIN can never overflow a subtraction. */
static int32_t pk161_clamp(int32_t n) {
if (n < 0) {
return 0;
}
if (n > PK161_MAX_BUF) {
return PK161_MAX_BUF;
}
return n;
}
/* sizeof(natural) - sizeof(packed): the padding the attribute removes. */
__attribute__((noinline)) int32_t pk161_layout_delta(void) {
return (int32_t)(sizeof(struct pk161_natural) - sizeof(struct pk161_wire));
}
/* Every member offset in both layouts. Cases 0..3 are the natural struct,
* 4..7 the packed one; the pairwise difference IS the specification. */
__attribute__((noinline)) int32_t pk161_member_offset(int32_t which) {
switch (which & 7) {
case 0:
return (int32_t)offsetof(struct pk161_natural, kind);
case 1:
return (int32_t)offsetof(struct pk161_natural, seq);
case 2:
return (int32_t)offsetof(struct pk161_natural, port);
case 3:
return (int32_t)offsetof(struct pk161_natural, ttl);
case 4:
return (int32_t)offsetof(struct pk161_wire, kind);
case 5:
return (int32_t)offsetof(struct pk161_wire, seq);
case 6:
return (int32_t)offsetof(struct pk161_wire, port);
default:
return (int32_t)offsetof(struct pk161_wire, ttl);
}
}
/* Fill a packed record member-by-member (the stores land at 0/1/5/7), then emit
* its 8 bytes to the caller's buffer. Returns the byte sum, or a negative code.
*/
__attribute__((noinline)) int32_t
pk161_encode(uint8_t *out, int32_t out_len, uint32_t seq, int32_t kind) {
struct pk161_wire record = {0, 0, 0, 0};
const unsigned char *raw;
int32_t limit = pk161_clamp(out_len);
int32_t sum = 0;
int32_t i;
if (out == NULL) {
return -1;
}
if (limit < PK161_WIRE_BYTES) {
return -2;
}
record.kind = (uint8_t)((uint32_t)kind & 0xFFu);
record.seq = seq;
record.port = (uint16_t)(((uint32_t)kind >> 8) & 0xFFFFu);
record.ttl = (uint8_t)((seq >> 24) & 0xFFu);
raw = (const unsigned char *)&record;
for (i = 0; i < PK161_WIRE_BYTES; i++) {
out[i] = (uint8_t)raw[i];
sum += (int32_t)raw[i];
}
return sum;
}
/* Refill a packed record from wire bytes, then read one member back. The read
* of `seq` is a 4-byte access at offset 1. Returns 0xFFFFFFFF on rejection;
* no member of this record can legitimately produce that value except `seq`,
* which is documented as ambiguous. */
__attribute__((noinline)) uint32_t
pk161_read_field(const uint8_t *in, int32_t in_len, int32_t which) {
struct pk161_wire record = {0, 0, 0, 0};
unsigned char *raw;
int32_t limit = pk161_clamp(in_len);
int32_t i;
if (in == NULL) {
return 0xFFFFFFFFu;
}
if (limit < PK161_WIRE_BYTES) {
return 0xFFFFFFFFu;
}
raw = (unsigned char *)&record;
for (i = 0; i < PK161_WIRE_BYTES; i++) {
raw[i] = (unsigned char)in[i];
}
switch (which & 3) {
case 0:
return (uint32_t)record.kind;
case 1:
return record.seq; /* unaligned load at wire offset 1 */
case 2:
return (uint32_t)record.port; /* unaligned load at wire offset 5 */
default:
return (uint32_t)record.ttl;
}
}
/* Encode into a local frame and decode straight back: the roundtrip only holds
* if both directions agree on offsets 1 and 5. */
__attribute__((noinline)) int32_t
pk161_roundtrip(uint32_t seq, int32_t kind) {
uint8_t frame[PK161_MAX_BUF];
int32_t rc;
int32_t i;
for (i = 0; i < PK161_MAX_BUF; i++) {
frame[i] = 0;
}
rc = pk161_encode(frame, PK161_WIRE_BYTES, seq, kind);
if (rc < 0) {
return rc;
}
if (pk161_read_field(frame, PK161_WIRE_BYTES, 1) != seq) {
return -3;
}
if (pk161_read_field(frame, PK161_WIRE_BYTES, 2) !=
(((uint32_t)kind >> 8) & 0xFFFFu)) {
return -4;
}
return rc;
} 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/5pk161_encode pass 36 lines
// glaurung: pk161_encode @ 0x1150
int32_t pk161_encode(uint8_t * arg0, int32_t arg1, uint32_t arg2, int32_t arg3) {
int i;
int sum;
long local_10;
long local_8;
long rbp;
long ret;
long var1;
long var13;
int var17;
int var18;
int var19;
int var40;
long var9;
if ((arg0 == 0)) {
return 0xffffffff;
}
ret = 0xfffffffe;
if ((8 <= (long)(arg1))) {
local_8 = rbp;
local_10 = var1;
var9 = (unsigned long)((unsigned int)(((unsigned int)(arg2) >> 24)));
var13 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg3)) >> 16)));
*(signed char *)(((long)arg0)) = arg3;
var17 = (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned int)(arg2) >> 16))) & 255)));
var18 = (unsigned int)((unsigned char)((arg2 & 255)));
var19 = (unsigned int)((unsigned char)((((unsigned int)(arg2) >> 8) & 255)));
*(int *)(((long)arg0 + 0x1)) = ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((var19 << 8))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((var17 << 16))) | (unsigned long)((unsigned int)((arg2 & -0x1000000LL))))))))) | var18);
var40 = (unsigned int)((unsigned char)((((unsigned int)(arg3) >> 8) & 255)));
*(short *)(((long)arg0 + 0x5)) = ((unsigned long)((unsigned int)((var13 << 8))) | var40);
*(signed char *)(((long)arg0 + 0x7)) = var9;
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)((unsigned char)((var13 & 255))) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)((unsigned char)((arg3 & 255))) + var18))) + var19))) + var17))) + var9))) + var40)))))) + var9)));
}
return ret;
} pk161_layout_delta pass 4 lines
// glaurung: pk161_layout_delta @ 0x1120
int32_t pk161_layout_delta(void) {
return 4;
} pk161_member_offset pass 11 lines
// glaurung: pk161_member_offset @ 0x1130
int32_t pk161_member_offset(int32_t arg0) {
long ret;
long var1;
var1 = (unsigned long)((unsigned int)((arg0 & 7)));
ret = 7;
if (((unsigned long)((unsigned int)(var1)) != 7)) {
ret = (unsigned long)((unsigned int)((((unsigned long)((unsigned int)(var1)) == 0) ? 0 : (((unsigned long)((unsigned int)(var1)) == 1) ? 4 : (((unsigned long)((unsigned int)(var1)) == 2) ? 8 : (((unsigned long)((unsigned int)(var1)) == 3) ? 10 : (((unsigned long)((unsigned int)(var1)) == 4) ? 0 : (((unsigned long)((unsigned int)(var1)) == 5) ? 1 : (((unsigned long)((unsigned int)(var1)) == 6) ? 5 : *(int *)((0x2000 + ((unsigned long)((unsigned int)(var1)) * 4))))))))))));
}
return ret;
} pk161_read_field pass 23 lines
// glaurung: pk161_read_field @ 0x11d0
uint32_t pk161_read_field(const uint8_t * arg0, int32_t arg1, int32_t arg2) {
long ret;
long var1;
ret = 0xffffffff;
if ((arg0 == 0)) {
return ret;
}
if (((long)(arg1) < 8)) {
return ret;
}
var1 = (unsigned long)((unsigned int)((arg2 & 3)));
if (((unsigned long)((unsigned int)(var1)) == 2)) {
return (unsigned int)((unsigned short)(*(short *)(((long)arg0 + 0x5))));
}
if (((unsigned long)((unsigned int)(var1)) == 1)) {
return (unsigned int)(*(int *)(((long)arg0 + 0x1)));
}
if (((unsigned long)((unsigned int)(var1)) == 0)) {
return (unsigned int)((unsigned char)(*(char *)(((long)arg0))));
}
return (unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x7))));
} pk161_roundtrip fail 36 lines
// glaurung: pk161_roundtrip @ 0x1210
__attribute__((no_stack_protector)) int32_t pk161_roundtrip(uint32_t arg0, int32_t arg1) {
extern int pk161_encode(char *, int, unsigned int, int);
extern unsigned int pk161_read_field(char *, int, int);
int rc;
int i;
unsigned char local_28[40];
long ret;
long rsp;
long var0;
long var1;
unsigned int var11;
unsigned int var15;
int var7;
// x86-64 prologue: save callee registers, frame 24 bytes
rsp = (rsp - 16);
var0 = (unsigned long)((unsigned int)(arg1));
var1 = (unsigned long)(arg0);
*(int *)(&local_28[0]) = 0;
*(int *)((&local_28[0] + 4)) = 0;
*(int *)((&local_28[0] + 8)) = 0;
*(int *)((&local_28[0] + 12)) = 0;
var7 = pk161_encode((char *)(rsp), 8, arg0, (unsigned long)((unsigned int)(arg1)));
rc = (unsigned long)((unsigned int)(var7));
if (((long)((int)(var7)) < 0)) {
return (unsigned int)(rc);
}
var11 = pk161_read_field((char *)(rsp), 8, 1);
ret = 0xfffffffd;
if ((var11 == (unsigned long)((unsigned int)(var1)))) {
var15 = pk161_read_field((char *)(rsp), 8, 2);
ret = ((var15 == (unsigned long)((unsigned int)((unsigned short)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) >> 8))) & 0xffff))))) ? rc : 0xfffffffc);
}
// x86-64 epilogue: restore callee registers
return ret;
} gcc -O2
4/5pk161_encode pass 49 lines
// glaurung: pk161_encode @ 0x1190
int32_t pk161_encode(uint8_t * arg0, int32_t arg1, uint32_t arg2, int32_t arg3) {
extern __attribute__((noreturn)) void __stack_chk_fail(void);
int i;
int sum;
long local_10;
unsigned char local_18[8];
long var17;
long var20;
long var4;
long var6;
int var8;
local_10 = (long)(0x28);
var4 = 0;
*(int *)((&local_18[0] + 1)) = 0;
*(short *)((&local_18[0] + 5)) = 0;
*(signed char *)((&local_18[0] + 7)) = 0;
if ((arg0 == 0)) {
var6 = 0xffffffff;
} else {
if ((((unsigned long)((unsigned int)(arg1)) == 7) | ((long)(arg1) < 7))) {
var6 = 0xfffffffe;
} else {
*(signed char *)(&local_18[0]) = arg3;
var8 = (unsigned int)((unsigned char)((arg3 & 255)));
*(int *)((&local_18[0] + 1)) = arg2;
*(short *)((&local_18[0] + 5)) = ((unsigned long)((unsigned int)(arg3)) >> 8);
*(signed char *)((&local_18[0] + 7)) = ((unsigned int)(arg2) >> 24);
var17 = 0;
i = var4;
while (1) {
*(signed char *)(((long)arg0 + i)) = var8;
i = (i + 1);
sum = (var17 + var8);
var20 = (unsigned long)((unsigned int)(sum));
var6 = (unsigned long)((unsigned int)(sum));
if ((i == 8)) {
break;
}
var8 = (unsigned int)((unsigned char)(*(char *)((&local_18[0] + i))));
var17 = var20;
}
}
}
if ((local_10 != 0x28)) {
__stack_chk_fail();
}
return (unsigned int)(var6);
} pk161_layout_delta pass 4 lines
// glaurung: pk161_layout_delta @ 0x1160
int32_t pk161_layout_delta(void) {
return 4;
} pk161_member_offset pass 9 lines
// glaurung: pk161_member_offset @ 0x1170
int32_t pk161_member_offset(int32_t arg0) {
long ret;
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7)));
if (((unsigned long)((unsigned int)(ret)) != 7)) {
ret = (unsigned long)((unsigned int)(((ret == 0) ? 0 : ((ret == 1) ? 4 : ((ret == 2) ? 8 : ((ret == 3) ? 10 : ((ret == 4) ? 0 : ((ret == 5) ? 1 : ((ret == 6) ? 5 : *(int *)((0x2000 + (ret * 4))))))))))));
}
return ret;
} pk161_read_field pass 20 lines
// glaurung: pk161_read_field @ 0x1240
uint32_t pk161_read_field(const uint8_t * arg0, int32_t arg1, int32_t arg2) {
long var1;
long var2;
if ((arg0 == 0)) {
return 0xffffffff;
}
if ((((unsigned long)((unsigned int)(arg1)) == 7) | ((long)(arg1) < 7))) {
return 0xffffffff;
}
var1 = (unsigned long)((unsigned int)((arg2 & 3)));
var2 = *(long *)(((long)arg0));
if (((unsigned long)((unsigned int)(var1)) == 1)) {
return ((unsigned long)(var2) >> 8);
}
if (((unsigned long)((unsigned int)(var1)) == 2)) {
return (unsigned int)((unsigned short)((((unsigned long)(var2) >> 40) & 0xffff)));
}
return (((unsigned long)((unsigned int)(var1)) == 0) ? (unsigned int)((unsigned char)((var2 & 255))) : ((unsigned long)(var2) >> 56));
} pk161_roundtrip fail 52 lines
// glaurung: pk161_roundtrip @ 0x12a0
__attribute__((no_stack_protector)) int32_t pk161_roundtrip(uint32_t arg0, int32_t arg1) {
extern int pk161_encode(char *, int, unsigned int, int);
extern unsigned int pk161_read_field(char *, int, int);
int i;
int rc;
long rbp;
long rsp;
long stack_2;
unsigned char stack_5[16];
int var13;
long var15;
long var16;
unsigned int var17;
long var22;
unsigned int var23;
long var7;
long var8;
rsp = (rsp - 8);
rsp = (rsp - 8);
var7 = (unsigned long)(arg0);
rsp = (rsp - 8);
stack_2 = rbp;
rsp = (rsp - 8);
var8 = (unsigned long)((unsigned int)(arg1));
rsp = (rsp - 40);
// stack canary: save guard to %stack_4
rbp = rsp;
*(int *)(&stack_5[0]) = 0;
*(int *)((&stack_5[0] + 4)) = 0;
*(int *)((&stack_5[0] + 8)) = 0;
*(int *)((&stack_5[0] + 12)) = 0;
var13 = ((int (*)(char *))pk161_encode)((char *)(rsp));
var15 = (unsigned long)((unsigned int)(var13));
var16 = (unsigned long)((unsigned int)(var13));
if ((0 <= (long)((int)(var13)))) {
var17 = pk161_read_field((char *)(rbp), 8, 1);
if ((var17 != (unsigned long)((unsigned int)(var7)))) {
var16 = 0xfffffffd;
} else {
var22 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var8)) >> 8)));
var23 = pk161_read_field((char *)(rbp), 8, 2);
var16 = ((var23 != (unsigned long)((unsigned int)((unsigned short)((var22 & 0xffff))))) ? 0xfffffffc : var15);
}
}
// stack-canary check
rsp = (rsp + 40);
rsp = (rsp + 8);
rbp = stack_2;
// x86-64 epilogue: tear down frame
return (unsigned int)(var16);
} clang -O0
5/5pk161_encode pass 35 lines
// glaurung: pk161_encode @ 0x11d0
__attribute__((no_stack_protector)) int32_t pk161_encode(uint8_t * arg0, int32_t arg1, uint32_t arg2, int32_t arg3) {
extern void * memset(void *, int, __SIZE_TYPE__);
extern int pk161_clamp(int);
int limit;
int sum;
char * raw;
int i;
unsigned char local_28[8];
void * var1;
int var3;
// x86-64 prologue: save rbp, frame 64 bytes
var1 = memset((void *)(&local_28[0]), 0, (__SIZE_TYPE__)(8));
var3 = pk161_clamp((unsigned long)((unsigned int)(arg1)));
limit = var3;
sum = 0;
if ((arg0 != 0)) {
if ((8 <= (long)(limit))) {
*(signed char *)(&local_28[0]) = arg3;
*(int *)((&local_28[0] + 1)) = arg2;
*(short *)((&local_28[0] + 5)) = ((unsigned long)((unsigned int)(arg3)) >> 8);
*(signed char *)((&local_28[0] + 7)) = ((unsigned int)(arg2) >> 24);
raw = (char *)&local_28[0];
for (i = 0; ((long)(i) < 8); i++) {
arg0[i] = raw[i];
sum = ((unsigned int)((unsigned char)(raw[i])) + sum);
}
return (unsigned int)(sum);
} else {
return (unsigned int)(-2);
}
} else {
return (unsigned int)(-1);
}
} pk161_layout_delta pass 6 lines
// glaurung: pk161_layout_delta @ 0x1130
int32_t pk161_layout_delta(void) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return 4;
} pk161_member_offset pass 37 lines
// glaurung: pk161_member_offset @ 0x1140
int32_t pk161_member_offset(int32_t arg0) {
long local_10;
int local_4;
long var2;
// x86-64 prologue: save rbp
var2 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7)));
local_10 = var2;
if (((((unsigned long)((unsigned long)((unsigned int)(var2))) < (unsigned long)(6)) | ((unsigned long)((unsigned int)((var2 - 6))) == 0)) == 0)) {
return 7;
}
switch (local_10) {
case 0:
local_4 = 0;
break;
case 1:
local_4 = 4;
break;
case 2:
local_4 = 8;
break;
case 3:
local_4 = 10;
break;
case 4:
local_4 = 0;
break;
case 5:
local_4 = 1;
break;
case 6:
local_4 = 5;
break;
}
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} pk161_read_field pass 44 lines
// glaurung: pk161_read_field @ 0x1300
__attribute__((no_stack_protector)) uint32_t pk161_read_field(const uint8_t * arg0, int32_t arg1, int32_t arg2) {
extern void * memset(void *, int, __SIZE_TYPE__);
extern int pk161_clamp(int);
int limit;
char * raw;
int i;
unsigned char local_20[8];
int local_34;
void * var1;
int var16;
int var3;
// x86-64 prologue: save rbp, frame 64 bytes
var1 = memset((void *)(&local_20[0]), 0, (__SIZE_TYPE__)(8));
var3 = pk161_clamp((unsigned long)((unsigned int)(arg1)));
limit = var3;
if ((arg0 != 0)) {
if ((8 <= (long)(limit))) {
raw = (char *)&local_20[0];
for (i = 0; ((long)(i) < 8); i++) {
raw[i] = arg0[i];
}
var16 = ((unsigned int)(arg2) & 3);
local_34 = var16;
if (((unsigned long)((unsigned int)(var16)) == 0)) {
return (unsigned int)((unsigned char)(*(char *)(&local_20[0])));
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_34)) - 1))) == 0)) {
return (unsigned int)(*(int *)((&local_20[0] + 1)));
} else {
if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_34)) - 2))) == 0)) {
return (unsigned int)((unsigned short)(*(short *)((&local_20[0] + 5))));
} else {
return (unsigned int)((unsigned char)(*(char *)((&local_20[0] + 7))));
}
}
}
} else {
return (unsigned int)(-1);
}
} else {
return (unsigned int)(-1);
}
} pk161_roundtrip pass 32 lines
// glaurung: pk161_roundtrip @ 0x1400
__attribute__((no_stack_protector)) int32_t pk161_roundtrip(uint32_t arg0, int32_t arg1) {
extern int pk161_encode(char *, int, unsigned int, int);
extern unsigned int pk161_read_field(char *, int, int);
int i;
int rc;
unsigned char local_20[16];
int var4;
unsigned int var6;
unsigned int var8;
// x86-64 prologue: save rbp, frame 48 bytes
for (i = 0; ((long)(i) < 16); i++) {
*(signed char *)((&local_20[0] + (long)(i))) = 0;
}
var4 = pk161_encode((char *)(&local_20[0]), 8, arg0, (unsigned long)((unsigned int)(arg1)));
rc = var4;
if ((0 <= (long)(rc))) {
var6 = pk161_read_field((char *)(&local_20[0]), 8, 1);
if ((var6 == arg0)) {
var8 = pk161_read_field((char *)(&local_20[0]), 8, 2);
if ((var8 == (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 8))) & 0xffff))))) {
return (unsigned int)(rc);
} else {
return (unsigned int)(-4);
}
} else {
return (unsigned int)(-3);
}
} else {
return (unsigned int)(rc);
}
} gcc -O0
5/5pk161_encode pass 45 lines
// glaurung: pk161_encode @ 0x1203
int32_t pk161_encode(uint8_t * arg0, int32_t arg1, uint32_t arg2, int32_t arg3) {
extern __attribute__((noreturn)) void __stack_chk_fail(void);
extern int pk161_clamp(int);
int limit;
int sum;
char * raw;
int i;
unsigned char local_10[8];
long local_8;
long ret;
int var4;
// x86-64 prologue: save rbp, frame 80 bytes
local_8 = (long)(0x28);
*(signed char *)(&local_10[0]) = 0;
*(int *)((&local_10[0] + 1)) = 0;
*(short *)((&local_10[0] + 5)) = 0;
*(signed char *)((&local_10[0] + 7)) = 0;
var4 = pk161_clamp((unsigned long)((unsigned int)(arg1)));
limit = var4;
sum = 0;
if ((arg0 != 0)) {
if (((((unsigned long)((unsigned int)(limit)) == 7) | ((long)(limit) < 7)) == 0)) {
*(signed char *)(&local_10[0]) = arg3;
*(int *)((&local_10[0] + 1)) = arg2;
*(short *)((&local_10[0] + 5)) = ((unsigned long)((unsigned int)(arg3)) >> 8);
*(signed char *)((&local_10[0] + 7)) = ((unsigned int)(arg2) >> 24);
raw = (char *)&local_10[0];
for (i = 0; ((((unsigned long)((unsigned int)(i)) == 7) | ((long)(i) < 7)) != 0); i++) {
arg0[i] = raw[i];
sum = (sum + (unsigned int)((unsigned char)(((unsigned int)((unsigned char)(raw[i])) & 255))));
}
ret = (unsigned long)((unsigned int)(sum));
} else {
ret = 0xfffffffe;
}
} else {
ret = 0xffffffff;
}
if ((local_8 != 0x28)) {
__stack_chk_fail();
}
// x86-64 epilogue: restore rbp
return ret;
} pk161_layout_delta pass 6 lines
// glaurung: pk161_layout_delta @ 0x1183
int32_t pk161_layout_delta(void) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return 4;
} pk161_member_offset pass 23 lines
// glaurung: pk161_member_offset @ 0x1192
int32_t pk161_member_offset(int32_t arg0) {
// x86-64 prologue: save rbp
switch ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 7)))) {
case 0:
return 0;
case 1:
return 4;
case 2:
return 8;
case 3:
return 10;
case 4:
return 0;
case 5:
return 1;
case 6:
return 5;
default:
return 7;
}
// x86-64 epilogue: restore rbp
} pk161_read_field pass 57 lines
// glaurung: pk161_read_field @ 0x12f7
uint32_t pk161_read_field(const uint8_t * arg0, int32_t arg1, int32_t arg2) {
extern __attribute__((noreturn)) void __stack_chk_fail(void);
extern int pk161_clamp(int);
int limit;
char * raw;
int i;
unsigned char local_10[8];
long local_8;
long ret;
long var18;
int var4;
// x86-64 prologue: save rbp, frame 48 bytes
local_8 = (long)(0x28);
*(signed char *)(&local_10[0]) = 0;
*(int *)((&local_10[0] + 1)) = 0;
*(short *)((&local_10[0] + 5)) = 0;
*(signed char *)((&local_10[0] + 7)) = 0;
var4 = pk161_clamp((unsigned long)((unsigned int)(arg1)));
limit = var4;
if ((arg0 != 0)) {
if (((((unsigned long)((unsigned int)(limit)) == 7) | ((long)(limit) < 7)) == 0)) {
raw = (char *)&local_10[0];
for (i = 0; ((((unsigned long)((unsigned int)(i)) == 7) | ((long)(i) < 7)) != 0); i++) {
raw[i] = arg0[i];
}
var18 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) & 3)));
if (((unsigned long)((unsigned int)(var18)) == 2)) {
ret = (unsigned int)((unsigned short)(((unsigned int)((unsigned short)(*(short *)((&local_10[0] + 5)))) & 0xffff)));
} else {
if (((((unsigned long)((unsigned int)(var18)) == 2) | ((long)((int)(var18)) < 2)) == 0)) {
L_13c8: ;
ret = (unsigned int)((unsigned char)(((unsigned int)((unsigned char)(*(char *)((&local_10[0] + 7)))) & 255)));
} else {
if (((unsigned long)((unsigned int)(var18)) == 0)) {
ret = (unsigned int)((unsigned char)(((unsigned int)((unsigned char)(*(char *)(&local_10[0]))) & 255)));
} else {
if (((unsigned long)((unsigned int)(var18)) == 1)) {
ret = (unsigned long)((unsigned int)(*(int *)((&local_10[0] + 1))));
} else {
goto L_13c8;
}
}
}
}
} else {
ret = 0xffffffff;
}
} else {
ret = 0xffffffff;
}
if ((local_8 != 0x28)) {
__stack_chk_fail();
}
// x86-64 epilogue: restore rbp
return ret;
} pk161_roundtrip pass 37 lines
// glaurung: pk161_roundtrip @ 0x13e5
int32_t pk161_roundtrip(uint32_t arg0, int32_t arg1) {
extern __attribute__((noreturn)) void __stack_chk_fail(void);
extern int pk161_encode(char *, int, unsigned int, int);
extern unsigned int pk161_read_field(char *, int, int);
int i;
int rc;
unsigned char local_20[16];
long local_8;
long ret;
unsigned int var12;
int var6;
unsigned int var9;
// x86-64 prologue: save rbp, frame 64 bytes
local_8 = (long)(0x28);
for (i = 0; ((((unsigned long)((unsigned int)(i)) == 15) | ((long)(i) < 15)) != 0); i++) {
*(signed char *)((&local_20[0] + (long)(i))) = 0;
}
var6 = pk161_encode((char *)(&local_20[0]), 8, arg0, (unsigned long)((unsigned int)(arg1)));
rc = var6;
if ((0 <= (long)(rc))) {
var9 = pk161_read_field((char *)(&local_20[0]), 8, 1);
if ((arg0 == var9)) {
var12 = pk161_read_field((char *)(&local_20[0]), 8, 2);
ret = ((var12 == (unsigned long)((unsigned int)((unsigned short)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) >> 8))) & 0xffff))))) ? (unsigned long)((unsigned int)(rc)) : 0xfffffffc);
} else {
ret = 0xfffffffd;
}
} else {
ret = (unsigned long)((unsigned int)(rc));
}
if ((local_8 != 0x28)) {
__stack_chk_fail();
}
// x86-64 epilogue: restore rbp
return ret;
}