Fixture 167
rust trait objects
Rust · 6 functions · 2 lanes · 1 of 12 function-lanes behave identically
2 of 2 lanes have a function that returns a different result after decompilation: rustc-O0 (0/6), rustc-O2 (1/6).
// 167_rust_trait_objects.rs
//
// Rust dynamic dispatch through `&dyn Trait`. A trait object is a FAT POINTER:
// two machine words, (data pointer, vtable pointer). Unlike a C++ object, the
// vtable pointer is NOT stored in the object — it travels alongside it in the
// reference, so a `&dyn Op` passed by value occupies two registers and a
// `&[&dyn Op]` is an array of 16-byte pairs.
//
// The recovery signals:
// * a virtual call is `call [rax + 8*k]` where rax is the SECOND half of a
// pair the callee never loaded from the object;
// * the Rust vtable layout is [drop_in_place, size, align, method0, method1,
// ...], so the first user method sits at offset 24 on x86-64, not 0;
// * unsizing a `&Concrete` to a `&dyn Op` is a pure compile-time act: it
// materialises a pointer to a static vtable with no runtime work, so the
// only evidence is a relocation into .data.rel.ro;
// * `Box<dyn Op>` adds drop glue reached through vtable slot 0.
//
// Exposure: every driver is `#[no_mangle] pub extern "C" fn` over plain i32/u32
// scalars and caller-owned `*mut i32` buffers. Selectors are taken modulo the
// number of impls, counts are masked to <= 16, pointers are null-checked, and
// every arithmetic operation is `wrapping_*`. No input the harness can pass can
// panic or index out of bounds.
//
// Deterministic: the trait objects point at `static` instances or at freshly
// boxed values whose contents are a pure function of the arguments; no address
// is ever observed.
/// The object-safe trait. Two methods, so vtable slot ORDER matters: a
/// decompiler that swaps them produces a plausible-looking wrong answer.
trait Op {
fn apply(&self, x: i32) -> i32;
fn tag(&self) -> i32;
}
struct AddK {
k: i32,
}
struct MulK {
k: i32,
}
struct Clamp {
lo: i32,
hi: i32,
}
struct Affine {
a: i32,
b: i32,
}
impl Op for AddK {
fn apply(&self, x: i32) -> i32 {
x.wrapping_add(self.k)
}
fn tag(&self) -> i32 {
11
}
}
impl Op for MulK {
fn apply(&self, x: i32) -> i32 {
x.wrapping_mul(self.k)
}
fn tag(&self) -> i32 {
22
}
}
impl Op for Clamp {
fn apply(&self, x: i32) -> i32 {
if x < self.lo {
self.lo
} else if x > self.hi {
self.hi
} else {
x
}
}
fn tag(&self) -> i32 {
33
}
}
impl Op for Affine {
fn apply(&self, x: i32) -> i32 {
x.wrapping_mul(self.a).wrapping_add(self.b)
}
fn tag(&self) -> i32 {
44
}
}
static ADD7: AddK = AddK { k: 7 };
static MUL3: MulK = MulK { k: 3 };
static CLAMP: Clamp = Clamp { lo: -100, hi: 100 };
static AFFINE: Affine = Affine { a: 5, b: -9 };
/// Unsizing coercion site: four `&'static Concrete` values become
/// `&'static dyn Op` fat pointers, each pairing the same data pointer with a
/// different static vtable.
#[inline(never)]
fn choose(sel: u32) -> &'static dyn Op {
match sel & 3 {
0 => &ADD7,
1 => &MUL3,
2 => &CLAMP,
_ => &AFFINE,
}
}
/// One dynamic call through a fat pointer. `sel` is masked, so every input
/// selects a valid impl.
#[no_mangle]
pub extern "C" fn rust_dyn_apply(sel: u32, x: i32) -> i32 {
choose(sel).apply(x)
}
/// Both vtable slots on the same object, so slot ordering is observable: a
/// decompiler that reads slot 3 where slot 4 belongs returns the other method's
/// value.
#[no_mangle]
pub extern "C" fn rust_dyn_two_slots(sel: u32, x: i32) -> i32 {
let op = choose(sel);
op.apply(x).wrapping_mul(100).wrapping_add(op.tag())
}
/// A fat pointer crossing a function boundary as an ARGUMENT: `op` arrives in
/// two registers and neither half is loaded from memory.
#[inline(never)]
fn twice(op: &dyn Op, x: i32) -> i32 {
op.apply(op.apply(x))
}
#[no_mangle]
pub extern "C" fn rust_dyn_pass_fat(sel: u32, x: i32) -> i32 {
twice(choose(sel), x)
}
/// A pipeline over an array of trait objects: the loop indexes 16-byte pairs,
/// reloading a different vtable each iteration, so the call target genuinely
/// varies at runtime and cannot be devirtualized.
#[no_mangle]
pub extern "C" fn rust_dyn_pipeline(x: i32, mask: u32) -> i32 {
let ops: [&dyn Op; 4] = [&ADD7, &MUL3, &CLAMP, &AFFINE];
let mut acc = x;
for (i, op) in ops.iter().enumerate() {
if mask & (1u32 << i) != 0 {
acc = op.apply(acc);
}
}
acc
}
/// Heap trait object. `Box<dyn Op>` is the same fat pointer, but dropping it
/// goes through vtable slot 0 (`drop_in_place`) plus the size/align slots, which
/// is the shape a decompiler most often mistakes for a data field.
#[inline(never)]
fn boxed(sel: u32, k: i32) -> Box<dyn Op> {
match sel & 3 {
0 => Box::new(AddK { k }),
1 => Box::new(MulK { k }),
2 => Box::new(Clamp {
lo: -(k.wrapping_abs() & 0xff),
hi: k.wrapping_abs() & 0xff,
}),
_ => Box::new(Affine {
a: k,
b: k.wrapping_neg(),
}),
}
}
/// The box is created, called through, and dropped inside the wrapper; only the
/// computed i32 escapes, so no address is ever observable.
#[no_mangle]
pub extern "C" fn rust_dyn_boxed(sel: u32, k: i32, x: i32) -> i32 {
let op = boxed(sel, k);
let r = op.apply(x).wrapping_add(op.tag());
// `op` drops here: vtable slot 0 then the deallocation.
r
}
/// Write one dynamic-dispatch result per element into a caller-owned buffer, so
/// the per-impl behaviour is visible as a buffer diff rather than a single
/// return value.
///
/// `out` is null-checked and `n` is clamped to the harness's 16-element buffer.
#[no_mangle]
pub extern "C" fn rust_dyn_fill(out: *mut i32, n: u32, x: i32) -> i32 {
if out.is_null() {
return -1;
}
let len = if n > 16 { 16 } else { n } as usize;
// SAFETY: the caller owns at least 16 i32s at `out`; `len <= 16`.
let dst: &mut [i32] = unsafe { core::slice::from_raw_parts_mut(out, len) };
let mut sum: i32 = 0;
for (i, slot) in dst.iter_mut().enumerate() {
let op = choose(i as u32);
let v = op.apply(x.wrapping_add(i as i32)).wrapping_add(op.tag());
*slot = v;
sum = sum.wrapping_add(v);
}
sum
} 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.
rustc -O0
0/6rust_dyn_apply fail 10 lines
// glaurung: rust_dyn_apply @ 0x7ff0
long rust_dyn_apply(unsigned int arg0, unsigned int arg1) {
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
long ret;
long var0;
long var2;
var0 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
ret = ((long (*)(long, unsigned int))(*(long *)((var2 + 0x18))))(var0, arg1);
return ret;
} rust_dyn_boxed fail 31 lines
// glaurung: rust_dyn_boxed @ 0x8590
__attribute__((no_stack_protector)) unsigned int rust_dyn_boxed(unsigned int arg0, int arg1, long * arg2) {
extern __attribute__((noreturn)) long _Unwind_Resume(long);
extern long _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(unsigned int, int);
extern void _ZN4core3ptr80drop_in_place_LT_alloc__boxed__Box_LT_dyn_u20_167_rust_trait_objects__Op_GT__GT_17h3cbb2df48a91365bE(char *);
int local_4;
unsigned char local_40[8];
int local_44;
int local_4c;
int local_50;
int local_8;
int local_c;
long stack_1;
long var0;
long var19;
long var4;
long var8;
var0 = _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(arg0, arg1);
*(long *)(&local_40[0]) = var0;
var4 = ((long (*)(long, long))(*(long *)(((long)arg2 + 0x18))))(*(long *)(&local_40[0]), (unsigned long)((unsigned int)((long)arg2)));
local_44 = var4;
var8 = ((long (*)(long))(*(long *)(((long)arg2 + 0x20))))(*(long *)(&local_40[0]));
local_4c = var8;
local_8 = local_44;
local_4 = local_4c;
local_50 = ((unsigned int)(local_44) + (unsigned int)(local_4c));
local_c = local_50;
_ZN4core3ptr80drop_in_place_LT_alloc__boxed__Box_LT_dyn_u20_167_rust_trait_objects__Op_GT__GT_17h3cbb2df48a91365bE((char *)(&local_40[0]));
return (unsigned int)(local_50);
var19 = _Unwind_Resume(stack_1);
} rust_dyn_fill fail 98 lines
// glaurung: rust_dyn_fill @ 0x8650
__attribute__((no_stack_protector)) unsigned int rust_dyn_fill(char * arg0, unsigned int arg1, long * arg2) {
extern long _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h7608ef65c26f9b4bE(char *);
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
extern int _ZN4core3ptr7mut_ptr31__LT_impl_u20__BP_mut_u20_T_GT_7is_null17h1d166d76aab99a9eE(char *);
extern long * _ZN4core4iter6traits8iterator8Iterator9enumerate17hc2d855ee0ebdea14E(long *);
extern long _ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_8iter_mut17hd603a13a84836734E(long);
extern long _ZN4core5slice3raw18from_raw_parts_mut17h7e6428c598b7c73fE(char *, long);
extern long * _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h0a17a1addf51cbb9E(long *);
int local_10;
unsigned char local_108[24];
int local_14;
int local_18;
int local_1c;
long local_28;
long local_30;
long local_38;
int local_4;
long local_40;
long local_50;
long local_58;
unsigned char local_a8[64];
int local_c;
unsigned char local_c0[24];
int local_c4;
int local_c8;
long local_e8;
int local_ec;
int var0;
long var10;
long * var13;
long * var16;
long var23;
long var24;
long var26;
long var31;
long var32;
long var33;
long var37;
long var39;
long var41;
long var42;
int var46;
long var6;
var0 = _ZN4core3ptr7mut_ptr31__LT_impl_u20__BP_mut_u20_T_GT_7is_null17h1d166d76aab99a9eE(arg0);
if (((unsigned long)((unsigned char)((var0 & 1))) != 0)) {
return (unsigned int)(-1);
} else {
local_c8 = (((unsigned long)(16) < (unsigned long)(arg1)) ? 16 : (unsigned long)(arg1));
local_58 = (unsigned int)(local_c8);
var6 = ((long (*)(char *))_ZN4core5slice3raw18from_raw_parts_mut17h7e6428c598b7c73fE)(arg0);
local_50 = var6;
local_c4 = 0;
var10 = ((long (*)(void))_ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_8iter_mut17hd603a13a84836734E)();
var13 = _ZN4core4iter6traits8iterator8Iterator9enumerate17hc2d855ee0ebdea14E((long *)(&local_a8[0]));
var16 = _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h0a17a1addf51cbb9E((long *)(&local_c0[0]));
*(long *)((&local_a8[0] + 24)) = *(long *)(&local_c0[0]);
*(long *)((&local_a8[0] + 32)) = *(long *)((&local_c0[0] + 8));
*(long *)((&local_a8[0] + 40)) = *(long *)((&local_c0[0] + 16));
var23 = (long)arg2;
while (1) {
var24 = _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h7608ef65c26f9b4bE((char *)((&local_a8[0] + 24)));
*(long *)((&local_a8[0] + 56)) = var23;
*(long *)((&local_a8[0] + 48)) = var24;
var26 = *(long *)((&local_a8[0] + 56));
if ((((var26 == 0) ? 0 : 1) == 0)) {
break;
}
var31 = *(long *)((&local_a8[0] + 48));
*(long *)(&local_108[0]) = var31;
local_40 = var31;
var32 = *(long *)((&local_a8[0] + 56));
local_e8 = var32;
local_38 = var32;
var33 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE((unsigned long)((unsigned int)(var31)));
var37 = *(long *)(&local_108[0]);
*(long *)((&local_108[0] + 8)) = var33;
*(long *)((&local_108[0] + 16)) = var26;
local_30 = var33;
local_28 = var26;
local_4 = var37;
var39 = ((long (*)(void))(*(long *)((var26 + 0x18))))();
var41 = *(long *)((&local_108[0] + 16));
local_ec = var39;
var42 = ((long (*)(long))(*(long *)((var41 + 0x20))))(*(long *)((&local_108[0] + 8)));
var23 = (unsigned long)((unsigned int)(var42));
local_10 = local_ec;
local_c = var42;
var46 = ((unsigned int)(local_ec) + (unsigned int)(var42));
local_1c = var46;
*(int *)((local_e8)) = var46;
local_18 = local_c4;
local_14 = var46;
local_c4 = ((unsigned int)(local_c4) + (unsigned int)(var46));
}
return (unsigned int)(local_c4);
}
} rust_dyn_pass_fat fail 11 lines
// glaurung: rust_dyn_pass_fat @ 0x80d0
long rust_dyn_pass_fat(unsigned int arg0, int arg1) {
extern long _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(long, long *);
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
long ret;
long var0;
long var3;
var0 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
ret = _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(var0, (long *)(var3));
return ret;
} rust_dyn_pipeline fail 76 lines
// glaurung: rust_dyn_pipeline @ 0x8100
__attribute__((no_stack_protector)) unsigned int rust_dyn_pipeline(int arg0, unsigned int arg1) {
extern long _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h5d49829560f42720E(char *);
extern long * _ZN4core4iter6traits8iterator8Iterator9enumerate17h20dcc5431a417106E(long *);
extern long _ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_4iter17h7f8eae9626c086e2E(long);
extern long _ZN4core9panicking5panic17hf516d800ede7db8cE(const char *, int, long);
extern long * _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h60cdd159fea15aa3E(long *);
long local_10;
unsigned char local_58[64];
unsigned char local_70[24];
int local_74;
long local_8;
long local_80;
long local_88;
long local_90;
long local_98;
long local_a0;
long local_a8;
long local_b0;
unsigned char local_b8[8];
long local_c8;
long local_d0;
long * var12;
long * var15;
long var22;
long var23;
long var24;
long var31;
long var32;
long var44;
long var48;
long var9;
*(long *)(&local_b8[0]) = (long)((long)(0x4607c));
local_b0 = 0x565d8;
local_a8 = (long)(0x46080);
local_a0 = 0x56600;
local_98 = (long)(0x46084);
local_90 = 0x56628;
local_88 = (long)(0x4608c);
local_80 = 0x56650;
local_74 = arg0;
var9 = _ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_4iter17h7f8eae9626c086e2E((long)(&local_b8[0]));
var12 = _ZN4core4iter6traits8iterator8Iterator9enumerate17h20dcc5431a417106E((long *)(&local_58[0]));
var15 = _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h60cdd159fea15aa3E((long *)(&local_70[0]));
*(long *)((&local_58[0] + 24)) = *(long *)(&local_70[0]);
*(long *)((&local_58[0] + 32)) = *(long *)((&local_70[0] + 8));
*(long *)((&local_58[0] + 40)) = *(long *)((&local_70[0] + 16));
var22 = var23;
L_81d5: ;
var24 = _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h5d49829560f42720E((char *)((&local_58[0] + 24)));
*(long *)((&local_58[0] + 56)) = var22;
*(long *)((&local_58[0] + 48)) = var24;
if ((((*(long *)((&local_58[0] + 56)) == 0) ? 0 : 1) == 0)) {
// x86-64 epilogue: tear down frame
return (unsigned int)(local_74);
}
var31 = *(long *)((&local_58[0] + 48));
local_d0 = var31;
local_10 = var31;
var32 = *(long *)((&local_58[0] + 56));
local_c8 = var32;
local_8 = var32;
if (((unsigned long)(var31) < (unsigned long)(32))) {
var22 = (unsigned long)((unsigned int)((1 << ((unsigned long)((unsigned int)((local_d0 & 31))) & 31))));
if (((unsigned long)((unsigned int)((arg1 & (unsigned long)((unsigned int)(var22))))) == 0)) {
goto L_81d5;
}
goto L_8292;
}
var44 = _ZN4core9panicking5panic17hf516d800ede7db8cE((const char *)("attempt to shift left with overflow"), 35, 0x56678);
/* asm: ud2 */
L_8292: ;
var48 = ((long (*)(long, long))(*(long *)((*(long *)((local_c8 + 0x8)) + 24))))(*(long *)(local_c8), (unsigned long)((unsigned int)(local_74)));
local_74 = var48;
goto L_81d5;
} rust_dyn_two_slots fail 30 lines
// glaurung: rust_dyn_two_slots @ 0x8020
unsigned int rust_dyn_two_slots(unsigned int arg0, unsigned int arg1) {
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
int local_10;
long local_18;
long local_20;
int local_2c;
long local_38;
int local_4;
long local_40;
int local_8;
int local_c;
long var0;
long var4;
long var5;
long var9;
var0 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
local_40 = var0;
local_38 = var4;
local_20 = var0;
local_18 = var4;
var5 = ((long (*)(void))(*(long *)((var4 + 0x18))))();
local_8 = var5;
local_4 = 100;
local_2c = (var5 * 100);
var9 = ((long (*)(long))(*(long *)((local_38 + 0x20))))(local_40);
local_10 = local_2c;
local_c = var9;
return (unsigned int)(((unsigned long)((unsigned int)(local_2c)) + (unsigned long)((unsigned int)(var9))));
} rustc -O2
1/6rust_dyn_apply fail 8 lines
// glaurung: rust_dyn_apply @ 0x7120
long rust_dyn_apply(unsigned int arg0, unsigned int arg1) {
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
long var1;
long var4;
var1 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
/* unrecovered indirect jump through *(long *)((var4 + 0x18)) */
} rust_dyn_boxed fail 32 lines
// glaurung: rust_dyn_boxed @ 0x72f0
static unsigned char glaurung_global_57c70[16] __attribute__((aligned(16)));
unsigned int rust_dyn_boxed(unsigned int arg0, int arg1, long * arg2) {
extern long _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(unsigned int, int);
extern unsigned char glaurung_global_57c70[16];
long local_30;
long var0;
long var1;
long var10;
long var11;
long var15;
long var3;
long var4;
long var5;
long var7;
long var8;
var0 = (unsigned long)((unsigned int)((long)arg2));
var1 = _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(arg0, arg1);
var3 = var1;
var4 = (long)arg2;
local_30 = var1;
var5 = ((long (*)(long, long))(*(long *)(((long)arg2 + 0x18))))(var1, (unsigned long)((unsigned int)(var0)));
var7 = (unsigned long)((unsigned int)(var5));
var8 = ((long (*)(long))(*(long *)((var4 + 0x20))))(var3);
var10 = (unsigned long)((unsigned int)(var8));
var11 = ((long (*)(long))(*(long *)((var4))))(var3);
if ((*(long *)((var4 + 0x8)) != 0)) {
var15 = ((long (*)(long))(*(long *)(&glaurung_global_57c70[0])))(var3);
}
// x86-64 epilogue: tear down frame
return (unsigned int)((var10 + var7));
} rust_dyn_fill fail 43 lines
// glaurung: rust_dyn_fill @ 0x7390
unsigned int rust_dyn_fill(char * arg0, unsigned int arg1, long * arg2) {
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
long local_40;
long var12;
long var13;
long var15;
long var17;
long var18;
long var20;
long var22;
long var23;
int var26;
long var3;
long var9;
if ((arg0 == 0)) {
return 0xffffffff;
} else {
var3 = (((unsigned long)(arg1) < (unsigned long)(16)) ? arg1 : 16);
if (((unsigned long)((unsigned int)(var3)) == 0)) {
return 0;
} else {
local_40 = (long)((unsigned int)((long)arg2));
var9 = 0;
var12 = 0;
var13 = (var3 << 2);
do {
var15 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE((unsigned long)((unsigned int)(var9)));
var17 = var15;
var18 = (long)arg2;
var20 = ((long (*)(long, long))(*(long *)(((long)arg2 + 0x18))))(var15, (unsigned long)((unsigned int)((local_40 + var9))));
var22 = (unsigned long)((unsigned int)(var20));
var23 = ((long (*)(long))(*(long *)((var18 + 0x20))))(var17);
var26 = (var23 + var22);
*(int *)(((long)arg0 + var9 * 4)) = var26;
var12 = (unsigned long)((unsigned int)((var12 + (unsigned long)((unsigned int)(var26)))));
var9 = (var9 + 1);
var13 = (var13 - 4);
} while ((var13 != 0));
return (unsigned int)(var12);
}
}
} rust_dyn_pass_fat fail 13 lines
// glaurung: rust_dyn_pass_fat @ 0x71a0
long rust_dyn_pass_fat(unsigned int arg0, int arg1) {
extern long _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(long, long, long);
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
long ret;
long var0;
long var1;
long var3;
var0 = (unsigned long)((unsigned int)(arg1));
var1 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
ret = _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(var1, var3, (unsigned long)((unsigned int)(var0)));
return ret;
} rust_dyn_pipeline pass 13 lines
// glaurung: rust_dyn_pipeline @ 0x71c0
unsigned int rust_dyn_pipeline(long arg0, long arg1) {
long var1;
int var3;
int var5;
var1 = (((unsigned long)((unsigned char)((arg1 & 1))) == 0) ? arg0 : (unsigned long)((unsigned int)((arg0 + 7))));
var3 = (((unsigned long)((unsigned char)((arg1 & 2))) == 0) ? var1 : (unsigned long)((unsigned int)((var1 + (var1 * 2)))));
if (((unsigned long)((unsigned char)((arg1 & 4))) != 0)) {
var5 = (((long)((int)(var3)) < 100) ? var3 : 100);
var3 = ((-99 <= (long)((int)(var5))) ? var5 : 0xffffff9c);
}
return (((unsigned long)((unsigned char)((arg1 & 8))) == 0) ? var3 : (unsigned long)((unsigned int)(((var3 + (var3 * 4)) - 9))));
} rust_dyn_two_slots fail 21 lines
// glaurung: rust_dyn_two_slots @ 0x7140
unsigned int rust_dyn_two_slots(unsigned int arg0, unsigned int arg1) {
extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
long var0;
long var1;
long var3;
long var4;
long var5;
long var6;
int var8;
long var9;
var0 = (unsigned long)(arg1);
var1 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
var3 = var1;
var4 = var5;
var6 = ((long (*)(long, long))(*(long *)((var5 + 0x18))))(var1, (unsigned long)((unsigned int)(var0)));
var8 = (var6 * 100);
var9 = ((long (*)(long))(*(long *)((var4 + 0x20))))(var3);
// x86-64 epilogue: tear down frame
return (unsigned int)((var9 + var8));
}