diff options
-rw-r--r-- | src/wasm-linker.cpp | 54 | ||||
-rw-r--r-- | src/wasm-linker.h | 11 | ||||
-rw-r--r-- | test/dot_s/alias.wast | 7 | ||||
-rw-r--r-- | test/dot_s/basics.wast | 8 | ||||
-rw-r--r-- | test/dot_s/bcp-1.wast | 15 | ||||
-rw-r--r-- | test/dot_s/dyncall.wast | 8 | ||||
-rw-r--r-- | test/dot_s/indidx.s | 8 | ||||
-rw-r--r-- | test/dot_s/indidx.wast | 8 | ||||
-rw-r--r-- | test/dot_s/indirect-import.wast | 19 | ||||
-rw-r--r-- | test/wasm_backend/indirect_call_only.txt | 4 |
10 files changed, 98 insertions, 44 deletions
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp index 3ff90cc0a..45615fd59 100644 --- a/src/wasm-linker.cpp +++ b/src/wasm-linker.cpp @@ -39,7 +39,7 @@ void Linker::placeStackPointer(Address stackAllocation) { std::vector<char> raw; raw.resize(pointerSize); out.addRelocation(LinkerObject::Relocation::kData, (uint32_t*)&raw[0], ".stack", stackAllocation); - assert(out.wasm.memory.segments.size() == 0); + assert(out.wasm.memory.segments.empty()); out.addSegment("__stack_pointer", raw); } } @@ -112,6 +112,9 @@ void Linker::layout() { for (Name name : out.globls) exportFunction(name, false); for (Name name : out.initializerFunctions) exportFunction(name, true); + // Pad the indirect function table with a dummy function + makeDummyFunction(); + // Pre-assign the function indexes for (auto& pair : out.indirectIndexes) { if (functionIndexes.count(pair.first) != 0 || @@ -132,17 +135,6 @@ void Linker::layout() { out.wasm.table.names.push_back(P.second); } - auto ensureFunctionIndex = [this](Name name) { - if (functionIndexes.count(name) == 0) { - functionIndexes[name] = out.wasm.table.names.size(); - functionNames[functionIndexes[name]] = name; - out.wasm.table.names.push_back(name); - if (debug) { - std::cerr << "function index: " << name << ": " - << functionIndexes[name] << '\n'; - } - } - }; for (auto& relocation : out.relocations) { // TODO: Handle weak symbols properly, instead of always taking the weak definition. auto *alias = out.getAlias(relocation->symbol, relocation->kind); @@ -167,16 +159,14 @@ void Linker::layout() { // Address of an imported function is taken, but imports do not have addresses in wasm. // Generate a thunk to forward to the call_import. Function* thunk = getImportThunk(name, f); - ensureFunctionIndex(thunk->name); - *(relocation->data) = functionIndexes[thunk->name] + relocation->addend; + *(relocation->data) = getFunctionIndex(thunk->name) + relocation->addend; } else { std::cerr << "Unknown symbol: " << name << '\n'; if (!ignoreUnknownSymbols) Fatal() << "undefined reference\n"; *(relocation->data) = 0; } } else { - ensureFunctionIndex(name); - *(relocation->data) = functionIndexes[name] + relocation->addend; + *(relocation->data) = getFunctionIndex(name) + relocation->addend; } } } @@ -379,6 +369,18 @@ void Linker::emscriptenGlue(std::ostream& o) { o << " }\n"; } +Index Linker::getFunctionIndex(Name name) { + if (!functionIndexes.count(name)) { + functionIndexes[name] = out.wasm.table.names.size(); + out.wasm.table.names.push_back(name); + if (debug) { + std::cerr << "function index: " << name << ": " + << functionIndexes[name] << '\n'; + } + } + return functionIndexes[name]; +} + bool hasI64ResultOrParam(FunctionType* ft) { if (ft->result == i64) return true; for (auto ty : ft->params) { @@ -387,10 +389,30 @@ bool hasI64ResultOrParam(FunctionType* ft) { return false; } +void Linker::makeDummyFunction() { + assert(out.wasm.table.names.empty()); + bool create = false; + // Check if there are address-taken functions + for (auto& relocation : out.relocations) { + if (relocation->kind == LinkerObject::Relocation::kFunction) { + create = true; + break; + } + } + if (!create) return; + wasm::Builder wasmBuilder(out.wasm); + Expression *unreachable = wasmBuilder.makeUnreachable(); + Function *dummy = wasmBuilder.makeFunction(Name(dummyFunction), {}, WasmType::none, {}, unreachable); + out.wasm.addFunction(dummy); + getFunctionIndex(dummy->name); +} + void Linker::makeDynCallThunks() { std::unordered_set<std::string> sigs; wasm::Builder wasmBuilder(out.wasm); for (const auto& indirectFunc : out.wasm.table.names) { + // Skip generating thunks for the dummy function + if (indirectFunc == dummyFunction) continue; std::string sig(getSig(out.wasm.getFunction(indirectFunc))); auto* funcType = ensureFunctionType(sig, &out.wasm); if (hasI64ResultOrParam(funcType)) continue; // Can't export i64s on the web. diff --git a/src/wasm-linker.h b/src/wasm-linker.h index 701585190..3f1e8c7ac 100644 --- a/src/wasm-linker.h +++ b/src/wasm-linker.h @@ -252,6 +252,9 @@ class Linker { // Returns false if an error occurred. bool linkArchive(Archive& archive); + // Name of the dummy function to prevent erroneous nullptr comparisons. + static constexpr const char* dummyFunction = "__wasm_nullptr"; + private: // Allocate a static variable and return its address in linear memory Address allocateStatic(Address allocSize, Address alignment, Name name) { @@ -279,6 +282,14 @@ class Linker { void ensureImport(Name target, std::string signature); + // Retrieves (and assigns) an entry index in the indirect function table for + // a given function. + Index getFunctionIndex(Name name); + + // Adds a dummy function in the indirect table at slot 0 to prevent NULL + // pointer miscomparisons. + void makeDummyFunction(); + // Create thunks for use with emscripten Runtime.dynCall. Creates one for each // signature in the indirect function table. void makeDynCallThunks(); diff --git a/test/dot_s/alias.wast b/test/dot_s/alias.wast index 6221a2232..5744f8e8a 100644 --- a/test/dot_s/alias.wast +++ b/test/dot_s/alias.wast @@ -7,7 +7,7 @@ (export "__exit" $__exit) (export "__needs_exit" $__needs_exit) (export "dynCall_v" $dynCall_v) - (table $__exit) + (table $__wasm_nullptr $__exit) (func $__exit (type $FUNCSIG$v) (return (i32.add @@ -23,9 +23,12 @@ (func $__needs_exit (result i32) (call $__exit) (return - (i32.const 0) + (i32.const 1) ) ) + (func $__wasm_nullptr (type $FUNCSIG$v) + (unreachable) + ) (func $dynCall_v (param $fptr i32) (call_indirect $FUNCSIG$v (get_local $fptr) diff --git a/test/dot_s/basics.wast b/test/dot_s/basics.wast index 0e6d4078b..b93bcd5cc 100644 --- a/test/dot_s/basics.wast +++ b/test/dot_s/basics.wast @@ -6,11 +6,12 @@ ) (export "memory" memory) (type $FUNCSIG$vi (func (param i32))) + (type $FUNCSIG$v (func)) (type $FUNCSIG$iii (func (param i32 i32) (result i32))) (import $puts "env" "puts" (param i32)) (export "main" $main) (export "dynCall_iii" $dynCall_iii) - (table $main) + (table $__wasm_nullptr $main) (func $main (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) (call_import $puts (i32.const 16) @@ -86,10 +87,13 @@ (i32.const -12) ) ) - (i32.const 0) + (i32.const 1) ) (get_local $0) ) + (func $__wasm_nullptr (type $FUNCSIG$v) + (unreachable) + ) (func $dynCall_iii (param $fptr i32) (param $0 i32) (param $1 i32) (result i32) (call_indirect $FUNCSIG$iii (get_local $fptr) diff --git a/test/dot_s/bcp-1.wast b/test/dot_s/bcp-1.wast index 0525be438..fcbe3b81e 100644 --- a/test/dot_s/bcp-1.wast +++ b/test/dot_s/bcp-1.wast @@ -1,10 +1,10 @@ (module (memory 1 - (segment 16 "\00\00\00\00\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00") - (segment 40 "\06\00\00\00\07\00\00\00\08\00\00\00") - (segment 52 "\t\00\00\00\n\00\00\00") - (segment 60 "\0b\00\00\00\0c\00\00\00\0d\00\00\00") - (segment 72 "\0e\00\00\00\0f\00\00\00\10\00\00\00") + (segment 16 "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00\06\00\00\00") + (segment 40 "\07\00\00\00\08\00\00\00\t\00\00\00") + (segment 52 "\n\00\00\00\0b\00\00\00") + (segment 60 "\0c\00\00\00\0d\00\00\00\0e\00\00\00") + (segment 72 "\0f\00\00\00\10\00\00\00\11\00\00\00") (segment 96 "hi\00") (segment 100 "\00\00\00\00") ) @@ -35,7 +35,7 @@ (export "main" $main) (export "dynCall_i" $dynCall_i) (export "dynCall_ii" $dynCall_ii) - (table $bad0 $bad1 $bad5 $bad7 $bad8 $bad10 $bad2 $bad3 $bad6 $bad4 $bad9 $good0 $good1 $good2 $opt0 $opt1 $opt2) + (table $__wasm_nullptr $bad0 $bad1 $bad5 $bad7 $bad8 $bad10 $bad2 $bad3 $bad6 $bad4 $bad9 $good0 $good1 $good2 $opt0 $opt1 $opt2) (func $bad0 (type $FUNCSIG$i) (result i32) (return (i32.const 0) @@ -307,6 +307,9 @@ (call_import $abort) (unreachable) ) + (func $__wasm_nullptr (type $FUNCSIG$v) + (unreachable) + ) (func $dynCall_i (param $fptr i32) (result i32) (call_indirect $FUNCSIG$i (get_local $fptr) diff --git a/test/dot_s/dyncall.wast b/test/dot_s/dyncall.wast index b0521de84..e284c838d 100644 --- a/test/dot_s/dyncall.wast +++ b/test/dot_s/dyncall.wast @@ -1,6 +1,7 @@ (module (memory 1) (export "memory" memory) + (type $FUNCSIG$v (func)) (type $FUNCSIG$i (func (result i32))) (type $FUNCSIG$if (func (param f32) (result i32))) (type $FUNCSIG$vd (func (param f64))) @@ -14,7 +15,7 @@ (export "dynCall_i" $dynCall_i) (export "dynCall_if" $dynCall_if) (export "dynCall_vd" $dynCall_vd) - (table $i $i_f $vd $ffjjdi $vd2) + (table $__wasm_nullptr $i $i_f $vd $ffjjdi $vd2) (func $i (type $FUNCSIG$i) (result i32) (i32.const 0) ) @@ -29,13 +30,16 @@ (func $vd2 (type $FUNCSIG$vd) (param $0 f64) ) (func $main (result i32) - (i32.const 0) (i32.const 1) (i32.const 2) (i32.const 3) (i32.const 4) + (i32.const 5) (i32.const 0) ) + (func $__wasm_nullptr (type $FUNCSIG$v) + (unreachable) + ) (func $dynCall_i (param $fptr i32) (result i32) (call_indirect $FUNCSIG$i (get_local $fptr) diff --git a/test/dot_s/indidx.s b/test/dot_s/indidx.s index 4ebd28af1..68d8f5b77 100644 --- a/test/dot_s/indidx.s +++ b/test/dot_s/indidx.s @@ -2,7 +2,7 @@ .file "cfi-wasm.bs.bc" .type a,@function a: # @a - .indidx 3 + .indidx 4 .result i32 # BB#0: # %entry i32.const $push0=, 0 @@ -13,7 +13,7 @@ a: # @a .type b,@function b: # @b - .indidx 1 + .indidx 2 .result i32 # BB#0: # %entry i32.const $push0=, 1 @@ -24,7 +24,7 @@ b: # @b .type c,@function c: # @c - .indidx 0 + .indidx 1 .result i32 # BB#0: # %entry i32.const $push0=, 2 @@ -35,7 +35,7 @@ c: # @c .type d,@function d: # @d - .indidx 2 + .indidx 3 .result i32 # BB#0: # %entry i32.const $push0=, 3 diff --git a/test/dot_s/indidx.wast b/test/dot_s/indidx.wast index 7d0a56f66..2a5224d00 100644 --- a/test/dot_s/indidx.wast +++ b/test/dot_s/indidx.wast @@ -1,13 +1,14 @@ (module (memory 1 - (segment 16 "\03\00\00\00\01\00\00\00\00\00\00\00\02\00\00\00") + (segment 16 "\04\00\00\00\02\00\00\00\01\00\00\00\03\00\00\00") ) (export "memory" memory) (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$v (func)) (import $getchar "env" "getchar" (result i32)) (export "main" $main) (export "dynCall_i" $dynCall_i) - (table $c $b $d $a) + (table $__wasm_nullptr $c $b $d $a) (func $a (type $FUNCSIG$i) (result i32) (i32.const 0) ) @@ -48,6 +49,9 @@ (unreachable) (unreachable) ) + (func $__wasm_nullptr (type $FUNCSIG$v) + (unreachable) + ) (func $dynCall_i (param $fptr i32) (result i32) (call_indirect $FUNCSIG$i (get_local $fptr) diff --git a/test/dot_s/indirect-import.wast b/test/dot_s/indirect-import.wast index 21378eefa..22821a4e0 100644 --- a/test/dot_s/indirect-import.wast +++ b/test/dot_s/indirect-import.wast @@ -17,7 +17,7 @@ (export "dynCall_fd" $dynCall_fd) (export "dynCall_v" $dynCall_v) (export "dynCall_vi" $dynCall_vi) - (table $__importThunk_extern_fd $__importThunk_extern_vj $__importThunk_extern_v $__importThunk_extern_ijidf $__importThunk_extern_struct $__importThunk_extern_sret) + (table $__wasm_nullptr $__importThunk_extern_fd $__importThunk_extern_vj $__importThunk_extern_v $__importThunk_extern_ijidf $__importThunk_extern_struct $__importThunk_extern_sret) (func $bar (result i32) (local $0 i32) (local $1 i32) @@ -33,23 +33,23 @@ ) ) ) - (i32.const 0) + (i32.const 1) ) (i32.store offset=24 (get_local $0) - (i32.const 1) + (i32.const 2) ) (call_import $extern_vj (i64.const 1) ) (i32.store offset=20 (get_local $0) - (i32.const 2) + (i32.const 3) ) (call_import $extern_v) (i32.store offset=16 (get_local $0) - (i32.const 3) + (i32.const 4) ) (call_import $extern_ijidf (i64.const 1) @@ -59,11 +59,11 @@ ) (i32.store offset=12 (get_local $0) - (i32.const 4) + (i32.const 5) ) (i32.store offset=8 (get_local $0) - (i32.const 5) + (i32.const 6) ) (set_local $1 (i32.load offset=28 @@ -80,7 +80,10 @@ (get_local $1) ) (func $baz (result i32) - (i32.const 2) + (i32.const 3) + ) + (func $__wasm_nullptr (type $FUNCSIG$v) + (unreachable) ) (func $__importThunk_extern_fd (type $FUNCSIG$fd) (param $0 f64) (result f32) (call_import $extern_fd diff --git a/test/wasm_backend/indirect_call_only.txt b/test/wasm_backend/indirect_call_only.txt index 8e10834ad..0927c1885 100644 --- a/test/wasm_backend/indirect_call_only.txt +++ b/test/wasm_backend/indirect_call_only.txt @@ -1,6 +1,6 @@ print: argc : 1 -print: addr of something : 0 -print: addr of more : 1 +print: addr of something : 1 +print: addr of more : 2 print: i : 0 print: something : 12 print: i : 1 |