summaryrefslogtreecommitdiff
path: root/src/wasm-linker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-linker.cpp')
-rw-r--r--src/wasm-linker.cpp51
1 files changed, 40 insertions, 11 deletions
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp
index aa098c2e7..1aba37b1b 100644
--- a/src/wasm-linker.cpp
+++ b/src/wasm-linker.cpp
@@ -51,19 +51,23 @@ void Linker::placeStackPointer(Address stackAllocation) {
}
}
+void Linker::ensureImport(Name target, std::string signature) {
+ if (!out.wasm.checkImport(target)) {
+ auto import = new Import;
+ import->name = import->base = target;
+ import->module = ENV;
+ import->type = ensureFunctionType(signature, &out.wasm);
+ out.wasm.addImport(import);
+ }
+}
+
void Linker::layout() {
// Convert calls to undefined functions to call_imports
for (const auto& f : out.undefinedFunctionCalls) {
Name target = f.first;
if (!out.symbolInfo.undefinedFunctions.count(target)) continue;
// Create an import for the target if necessary.
- if (!out.wasm.checkImport(target)) {
- auto import = new Import;
- import->name = import->base = target;
- import->module = ENV;
- import->type = ensureFunctionType(getSig(*f.second.begin()), &out.wasm);
- out.wasm.addImport(import);
- }
+ ensureImport(target, getSig(*f.second.begin()));
// Change each call. The target is the same since it's still the name.
// Delete and re-allocate the Expression as CallImport to avoid undefined
// behavior.
@@ -138,9 +142,17 @@ void Linker::layout() {
// function address
name = out.resolveAlias(name);
if (!out.wasm.checkFunction(name)) {
- std::cerr << "Unknown symbol: " << name << '\n';
- if (!ignoreUnknownSymbols) Fatal() << "undefined reference\n";
- *(relocation->data) = 0;
+ if (FunctionType* f = out.getExternType(name)) {
+ // 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 = generateImportThunk(name, f);
+ ensureFunctionIndex(thunk->name);
+ *(relocation->data) = functionIndexes[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;
@@ -362,9 +374,26 @@ void Linker::makeDynCallThunks() {
for (unsigned i = 0; i < funcType->params.size(); ++i) {
args.push_back(wasmBuilder.makeGetLocal(i + 1, funcType->params[i]));
}
- Expression* call = wasmBuilder.makeCallIndirect(funcType, fptr, std::move(args));
+ Expression* call = wasmBuilder.makeCallIndirect(funcType, fptr, args);
f->body = call;
out.wasm.addFunction(f);
exportFunction(f->name, true);
}
}
+
+Function* Linker::generateImportThunk(Name name, const FunctionType* funcType) {
+ wasm::Builder wasmBuilder(out.wasm);
+ std::vector<NameType> params;
+ Index p = 0;
+ for (const auto& ty : funcType->params) params.emplace_back(std::to_string(p++), ty);
+ Function *f = wasmBuilder.makeFunction(std::string("__importThunk_") + name.c_str(), std::move(params), funcType->result, {});
+ std::vector<Expression*> args;
+ for (Index i = 0; i < funcType->params.size(); ++i) {
+ args.push_back(wasmBuilder.makeGetLocal(i, funcType->params[i]));
+ }
+ Expression* call = wasmBuilder.makeCallImport(name, args);
+ f->body = call;
+ out.wasm.addFunction(f);
+ ensureImport(name, getSig(funcType));
+ return f;
+}