diff options
author | Wouter van Oortmerssen <aardappel@gmail.com> | 2020-01-16 08:40:47 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-16 08:40:47 -0800 |
commit | 0fdf72711e23116750f1aff34cae57f0d5c55125 (patch) | |
tree | 2cf8d0d1f62bb306383a143e9691cde27e5ea8d9 | |
parent | 256f868194bafc3ea32b981c51dd657151a04ae7 (diff) | |
download | wabt-0fdf72711e23116750f1aff34cae57f0d5c55125.tar.gz wabt-0fdf72711e23116750f1aff34cae57f0d5c55125.tar.bz2 wabt-0fdf72711e23116750f1aff34cae57f0d5c55125.zip |
wasm-decompile: absolute accesses refer to data segments (#1302)
This makes them easier to look up than the large integer
constants LLVM output is full of.
-rw-r--r-- | src/decompiler-ls.h | 8 | ||||
-rw-r--r-- | src/decompiler.cc | 36 | ||||
-rw-r--r-- | test/decompile/basic.txt | 2 | ||||
-rw-r--r-- | test/decompile/loadstore.txt | 9 |
4 files changed, 48 insertions, 7 deletions
diff --git a/src/decompiler-ls.h b/src/decompiler-ls.h index 80ec2654..3f59d6ce 100644 --- a/src/decompiler-ls.h +++ b/src/decompiler-ls.h @@ -78,7 +78,7 @@ struct LoadStoreTracking { }; struct LSVar { - std::map<uint32_t, LSAccess> accesses; + std::map<uint64_t, LSAccess> accesses; bool struct_layout = true; Type same_type = Type::Any; Address same_align = kInvalidAddress; @@ -119,7 +119,7 @@ struct LoadStoreTracking { } } - void LoadStore(uint32_t offset, Opcode opc, Type type, Address align, + void LoadStore(uint64_t offset, Opcode opc, Type type, Address align, const Node& addr_exp) { auto byte_size = opc.GetMemorySize(); type = GetMemoryType(type, opc); @@ -178,7 +178,7 @@ struct LoadStoreTracking { var.second.struct_layout = false; continue; } - uint32_t cur_offset = 0; + uint64_t cur_offset = 0; uint32_t idx = 0; for (auto& access : var.second.accesses) { access.second.idx = idx++; @@ -234,7 +234,7 @@ struct LoadStoreTracking { return ""; } - std::string GenAccess(uint32_t offset, const Node& addr_exp) const { + std::string GenAccess(uint64_t offset, const Node& addr_exp) const { auto name = AddrExpName(addr_exp); if (name.empty()) { return ""; diff --git a/src/decompiler.cc b/src/decompiler.cc index db71bf42..a0f710c4 100644 --- a/src/decompiler.cc +++ b/src/decompiler.cc @@ -224,7 +224,16 @@ struct Decompiler { return cat(name, ":", struc.empty() ? GetDecompTypeName(t) : struc); } - void LoadStore(Value &val, const Node& addr_exp, uint32_t offset, + bool ConstIntVal(const Expr* e, uint64_t &dest) { + dest = 0; + if (!e || e->type() != ExprType::Const) return false; + auto& c = cast<ConstExpr>(e)->const_; + if (c.type != Type::I32 && c.type != Type::I64) return false; + dest = c.type == Type::I32 ? c.u32 : c.u64; + return true; + } + + void LoadStore(Value &val, const Node& addr_exp, uint64_t offset, Opcode opc, Address align, Type op_type) { bool append_type = true; auto access = lst.GenAccess(offset, addr_exp); @@ -240,6 +249,30 @@ struct Decompiler { return; } } + // Detect absolute addressing, which we try to turn into references to the + // data section when possible. + uint64_t abs_base; + if (ConstIntVal(addr_exp.e, abs_base)) { + // We don't care what part of the absolute address was stored where, + // 1[0] and 0[1] are the same. + abs_base += offset; + // FIXME: make this less expensive with a binary search or whatever. + for (auto dat : mc.module.data_segments) { + uint64_t dat_base; + if (dat->offset.size() == 1 && + ConstIntVal(&dat->offset.front(), dat_base) && + abs_base >= dat_base && + abs_base < dat_base + dat->data.size()) { + // We are inside the range of this data segment! + // Turn expression into data_name[index] + val = Value { { dat->name }, Precedence::Atomic }; + // The new offset is from the start of the data segment, instead of + // whatever it was.. this may be a different value from both the + // original const and offset! + offset = abs_base - dat_base; + } + } + } // Do the load/store as a generalized indexing operation. // The offset is divisible by the alignment in 99.99% of // cases, but the spec doesn't guarantee it, so we must @@ -697,7 +730,6 @@ struct Decompiler { // Data. for (auto dat : mc.module.data_segments) { - s += cat("data ", dat->name, "(offset: ", InitExp(dat->offset), ") = "); auto ds = BinaryToString(dat->data); if (ds.size() > target_exp_width / 2) { diff --git a/test/decompile/basic.txt b/test/decompile/basic.txt index e7a4c9db..7d6088ea 100644 --- a/test/decompile/basic.txt +++ b/test/decompile/basic.txt @@ -132,7 +132,7 @@ export function f(a:int, b:int):int { var c:long = 8L; var d:float = 6.0f; var e:double = 7.0; - if (e < 10.0) { 1[1]:int = 2[3]:int@1 + 5 } + if (e < 10.0) { d_a[5@4]:int = d_a[5]:int@1 + 5 } f(a + g_b, 9); loop L_b { if (if (0) { 1 } else { 2 }) goto B_c; diff --git a/test/decompile/loadstore.txt b/test/decompile/loadstore.txt index ce3cc89f..65334cec 100644 --- a/test/decompile/loadstore.txt +++ b/test/decompile/loadstore.txt @@ -3,6 +3,8 @@ (module (memory $m1 1) + (data 0 (offset (i32.const 10)) "Hello, World!\n\00") + (func $f (param i32 i32) (result) (local i32 i32 i32 i32 i32 i32) ;; Test regular accesses that become a struct. get_local 0 @@ -95,6 +97,10 @@ i32.add i32.load offset=4 i32.store offset=4 + ;; Test naming of absolute addresses referring to data sections. + i32.const 16 + i32.load8_u offset=1 ;; Refers to the 'W' + drop ) (export "f" (func $f)) ) @@ -102,6 +108,8 @@ (;; STDOUT ;;; memory M_a(initial: 1, max: 0); +data d_a(offset: 10) = "Hello, World!\0a\00"; + export function f(a:{ a:float, b:float }, b:{ a:ushort, b:long }) { var c:{ a:float, b:float } var d:{ a:ushort, b:long } @@ -121,6 +129,7 @@ export function f(a:{ a:float, b:float }, b:{ a:ushort, b:long }) { a[b]:int = a[b]:int; a[b + 1]:int = a[b + 1]:int; (a + (b << 3))[1]:int = a[b + 1]:int; + d_a[7]:ubyte; } ;;; STDOUT ;;) |