summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm-linker.cpp54
-rw-r--r--src/wasm-linker.h11
-rw-r--r--test/dot_s/alias.wast7
-rw-r--r--test/dot_s/basics.wast8
-rw-r--r--test/dot_s/bcp-1.wast15
-rw-r--r--test/dot_s/dyncall.wast8
-rw-r--r--test/dot_s/indidx.s8
-rw-r--r--test/dot_s/indidx.wast8
-rw-r--r--test/dot_s/indirect-import.wast19
-rw-r--r--test/wasm_backend/indirect_call_only.txt4
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