For some context, here is the original C++ function: ```C++ struct Dummy { long i; long j; long k; }; void dummy_function(struct Dummy& dummy, long i, long j, long k) { dummy.i = i; dummy.j = j; dummy.k = k; } ``` Decompiled Ouput: ``` ; Function Attrs: noinline nounwind ssp define void @"dummy_function(Dummy&, long, long, long)"({ i64, i64, i64 }* nocapture %dummy, i64 %i, i64 %j, i64 %k) local_unnamed_addr #0 { %1 = tail call i8* @llvm.returnaddress(i32 0) %2 = ptrtoint i8* %1 to i64 %3 = getelementptr inbounds { i64, i64, i64 }, { i64, i64, i64 }* %dummy, i64 0, i32 0 store i64 %k, i64* %3, align 8 %4 = tail call %struct.Memory* @__remill_function_return(%struct.State* nonnull undef, i64 %2, %struct.Memory* null) #3 ret void } ``` Reference Output: ``` ; Function Attrs: noinline norecurse nounwind ssp uwtable writeonly define void @_Z14dummy_functionR5Dummylll(%struct.Dummy* nocapture dereferenceable(24), i64, i64, i64) local_unnamed_addr #5 !dbg !2476 { call void @llvm.dbg.value(metadata %struct.Dummy* %0, metadata !2486, metadata !DIExpression()), !dbg !2490 call void @llvm.dbg.value(metadata i64 %1, metadata !2487, metadata !DIExpression()), !dbg !2491 call void @llvm.dbg.value(metadata i64 %2, metadata !2488, metadata !DIExpression()), !dbg !2492 call void @llvm.dbg.value(metadata i64 %3, metadata !2489, metadata !DIExpression()), !dbg !2493 %5 = getelementptr inbounds %struct.Dummy, %struct.Dummy* %0, i64 0, i32 0, !dbg !2494 store i64 %1, i64* %5, align 8, !dbg !2495, !tbaa !2496 %6 = getelementptr inbounds %struct.Dummy, %struct.Dummy* %0, i64 0, i32 1, !dbg !2498 store i64 %2, i64* %6, align 8, !dbg !2499, !tbaa !2500 %7 = getelementptr inbounds %struct.Dummy, %struct.Dummy* %0, i64 0, i32 2, !dbg !2501 store i64 %3, i64* %7, align 8, !dbg !2502, !tbaa !2503 ret void, !dbg !2504 } ``` This might be just me but it doesn't look right. In the decompiled case, it seems like we are only assigning the third element of the struct. In fact, there are no references to `%i` and `%j` which makes me wonder. Here is the full command and full json file if you want to reproduce my result: ```bash anvill-decompile-json-9.0 --spec test.json --bc_out test.bc --ir_out test.ll ``` hello.json: ```json= { "arch": "amd64", "functions": [ { "name": "dummy_function(Dummy&, long, long, long)", "address": 0, "parameters": [ { "name": "dummy", "register": "RDI", "type": "*{lll}" }, { "name": "i", "register": "RSI", "type": "l" }, { "name": "j", "register": "RDX", "type": "l" }, { "name": "k", "register": "RCX", "type": "l" } ], "return_stack_pointer": { "offset": 8, "register": "RSP", "type": "l" }, "return_address": { "memory": { "register": "RSP" }, "type": "I" }, "return_values": [] } ], "memory": [ { "address": 0, "data": "554889E54889374889570848894F105DC3", "is_readable": true, "is_executable": true } ], "stack": { "address": 12288, "size": 24576, "start_offset": 4096 }, "os": "macos" } ``` But the good news is that if I use the decompiled bitcode file as input to my bitcode specifier, I get back the same JSON specification file :smile:, so at least that works. But I don't think the lifting is correct in this case. The opcodes for the function are in the data section of the json at line 46. Here is the binja disassembly for convenience: ``` dummy_function: 100000cd0 55 push rbp {__saved_rbp} 100000cd1 4889e5 mov rbp, rsp {__saved_rbp} 100000cd4 488937 mov qword [rdi], rsi 100000cd7 48895708 mov qword [rdi+0x8], rdx 100000cdb 48894f10 mov qword [rdi+0x10], rcx 100000cdf 5d pop rbp {__saved_rbp} 100000ce0 c3 retn {__return_addr} ``` P.S. I used bad values for the "stack" element on line 51, not sure if that matters or not. It seemed to me like it didn't matter so I used the values from the example. --- Output from remill-lift: ``` ; ModuleID = 'lifted_code' source_filename = "lifted_code" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx-macho" %struct.State = type { %struct.ArchState, [32 x %union.VectorReg], %struct.ArithFlags, %union.anon, %struct.Segments, %struct.AddressSpace, %struct.GPR, %struct.X87Stack, %struct.MMX, %struct.FPUStatusFlags, %union.anon, %union.FPU, %struct.SegmentCaches } %struct.ArchState = type { i32, i32, %union.anon } %union.VectorReg = type { %union.vec512_t } %union.vec512_t = type { %struct.uint64v8_t } %struct.uint64v8_t = type { [8 x i64] } %struct.ArithFlags = type { i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8 } %struct.Segments = type { i16, %union.SegmentSelector, i16, %union.SegmentSelector, i16, %union.SegmentSelector, i16, %union.SegmentSelector, i16, %union.SegmentSelector, i16, %union.SegmentSelector } %union.SegmentSelector = type { i16 } %struct.AddressSpace = type { i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg } %struct.Reg = type { %union.anon } %struct.GPR = type { i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg, i64, %struct.Reg } %struct.X87Stack = type { [8 x %struct.anon.3] } %struct.anon.3 = type { i64, double } %struct.MMX = type { [8 x %struct.anon.4] } %struct.anon.4 = type { i64, %union.vec64_t } %union.vec64_t = type { %struct.uint64v1_t } %struct.uint64v1_t = type { [1 x i64] } %struct.FPUStatusFlags = type { i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, [4 x i8] } %union.anon = type { i64 } %union.FPU = type { %struct.anon.13 } %struct.anon.13 = type { %struct.FpuFXSAVE, [96 x i8] } %struct.FpuFXSAVE = type { %union.SegmentSelector, %union.SegmentSelector, %union.FPUAbridgedTagWord, i8, i16, i32, %union.SegmentSelector, i16, i32, %union.SegmentSelector, i16, %union.FPUControlStatus, %union.FPUControlStatus, [8 x %struct.FPUStackElem], [16 x %union.vec128_t] } %union.FPUAbridgedTagWord = type { i8 } %union.FPUControlStatus = type { i32 } %struct.FPUStackElem = type { %union.anon.11, [6 x i8] } %union.anon.11 = type { %struct.float80_t } %struct.float80_t = type { [10 x i8] } %union.vec128_t = type { %struct.uint128v1_t } %struct.uint128v1_t = type { [1 x i128] } %struct.SegmentCaches = type { %struct.SegmentShadow, %struct.SegmentShadow, %struct.SegmentShadow, %struct.SegmentShadow, %struct.SegmentShadow, %struct.SegmentShadow } %struct.SegmentShadow = type { %union.anon, i32, i32 } %struct.Memory = type opaque ; Function Attrs: noinline nounwind ssp define dso_local %struct.Memory* @sub_0(%struct.State* noalias dereferenceable(3376), i64, %struct.Memory* noalias) local_unnamed_addr #0 { %4 = getelementptr inbounds %struct.State, %struct.State* %0, i64 0, i32 6, i32 5, i32 0, i32 0 %5 = getelementptr inbounds %struct.State, %struct.State* %0, i64 0, i32 6, i32 7, i32 0, i32 0 %6 = getelementptr inbounds %struct.State, %struct.State* %0, i64 0, i32 6, i32 9, i32 0, i32 0 %7 = getelementptr inbounds %struct.State, %struct.State* %0, i64 0, i32 6, i32 11, i32 0, i32 0 %8 = getelementptr inbounds %struct.State, %struct.State* %0, i64 0, i32 6, i32 13, i32 0, i32 0 %9 = getelementptr inbounds %struct.State, %struct.State* %0, i64 0, i32 6, i32 15, i32 0, i32 0 %10 = getelementptr inbounds %struct.State, %struct.State* %0, i64 0, i32 6, i32 33, i32 0, i32 0 %11 = load i64, i64* %9, align 8 %12 = load i64, i64* %8, align 8, !tbaa !0 %13 = add i64 %12, -8 %14 = tail call %struct.Memory* @__remill_write_memory_64(%struct.Memory* %2, i64 %13, i64 %11) #3 %15 = load i64, i64* %7, align 8 %16 = load i64, i64* %6, align 8 %17 = tail call %struct.Memory* @__remill_write_memory_64(%struct.Memory* %14, i64 %15, i64 %16) #3 %18 = add i64 %15, 8 %19 = load i64, i64* %5, align 8 %20 = tail call %struct.Memory* @__remill_write_memory_64(%struct.Memory* %17, i64 %18, i64 %19) #3 %21 = add i64 %15, 16 %22 = load i64, i64* %4, align 8 %23 = tail call %struct.Memory* @__remill_write_memory_64(%struct.Memory* %20, i64 %21, i64 %22) #3 %24 = tail call i64 @__remill_read_memory_64(%struct.Memory* %23, i64 %13) #3 store i64 %24, i64* %9, align 8, !tbaa !3 %25 = tail call i64 @__remill_read_memory_64(%struct.Memory* %23, i64 %12) #3 store i64 %25, i64* %10, align 8, !tbaa !3 %26 = add i64 %12, 8 store i64 %26, i64* %8, align 8, !tbaa !3 %27 = tail call %struct.Memory* @__remill_function_return(%struct.State* nonnull %0, i64 %25, %struct.Memory* %23) ret %struct.Memory* %27 } ; Function Attrs: noduplicate noinline nounwind optnone readnone declare %struct.Memory* @__remill_write_memory_64(%struct.Memory*, i64, i64) #1 ; Function Attrs: noduplicate noinline nounwind optnone readnone declare i64 @__remill_read_memory_64(%struct.Memory*, i64) #1 ; Function Attrs: noduplicate noinline nounwind optnone declare %struct.Memory* @__remill_function_return(%struct.State* dereferenceable(3376), i64, %struct.Memory*) #2 attributes #0 = { noinline nounwind ssp "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noduplicate noinline nounwind optnone readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { noduplicate noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nobuiltin nounwind readnone } !0 = !{!1, !1, i64 0} !1 = !{!"omnipotent char", !2, i64 0} !2 = !{!"Simple C++ TBAA"} !3 = !{!4, !4, i64 0} !4 = !{!"long long", !1, i64 0} ```