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}
```