summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDominic Chen <d.c.ddcc@gmail.com>2016-08-03 15:26:00 -0700
committerDerek Schuff <dschuff@chromium.org>2016-08-03 15:26:00 -0700
commite45b9a772f2e25cca99fcff9e0decaf7580a3236 (patch)
treeca394191468d0485f01e51c56730ec1734ca2271 /src
parent959bc7638aebb27fcdf7079daf0d0cafe845f56a (diff)
downloadbinaryen-e45b9a772f2e25cca99fcff9e0decaf7580a3236.tar.gz
binaryen-e45b9a772f2e25cca99fcff9e0decaf7580a3236.tar.bz2
binaryen-e45b9a772f2e25cca99fcff9e0decaf7580a3236.zip
Create a dummy function to prevent NULL miscomparisons, if necessary (#658)
Resolves WebAssembly/spec#312
Diffstat (limited to 'src')
-rw-r--r--src/wasm-linker.cpp54
-rw-r--r--src/wasm-linker.h11
2 files changed, 49 insertions, 16 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();