[WebAssembly] Create synthetic __wasm_call_ctors function
This change create a new synthetic function in the final
output binary which calls the static constructors in sequence.
See: https://github.com/WebAssembly/tool-conventions/issues/25
Differential Revision: https://reviews.llvm.org/D41893
llvm-svn: 322388
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 0dc6be9..8bb4bfb 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -9,6 +9,7 @@
#include "Writer.h"
+#include "llvm/ADT/DenseSet.h"
#include "Config.h"
#include "InputChunks.h"
#include "OutputSections.h"
@@ -70,6 +71,8 @@
uint32_t lookupType(const WasmSignature &Sig);
uint32_t registerType(const WasmSignature &Sig);
+ void createCtorFunction();
+ void calculateInitFunctions();
void assignIndexes();
void calculateImports();
void calculateOffsets();
@@ -114,12 +117,15 @@
std::vector<const Symbol *> DefinedGlobals;
std::vector<InputFunction *> DefinedFunctions;
std::vector<const Symbol *> IndirectFunctions;
+ std::vector<WasmInitFunc> InitFunctions;
// Elements that are used to construct the final output
std::string Header;
std::vector<OutputSection *> OutputSections;
std::unique_ptr<FileOutputBuffer> Buffer;
+ std::unique_ptr<SyntheticFunction> CtorFunction;
+ std::string CtorFunctionBody;
std::vector<OutputSegment *> Segments;
llvm::SmallDenseMap<StringRef, OutputSegment *> SegmentMap;
@@ -410,15 +416,6 @@
SubSection.writeToStream(OS);
}
- std::vector<WasmInitFunc> InitFunctions;
- for (ObjFile *File : Symtab->ObjectFiles) {
- const WasmLinkingData &L = File->getWasmObj()->linkingData();
- InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size());
- for (const WasmInitFunc &F : L.InitFunctions)
- InitFunctions.emplace_back(WasmInitFunc{
- F.Priority, File->relocateFunctionIndex(F.FunctionIndex)});
- }
-
if (!InitFunctions.empty()) {
SubSection SubSection(WASM_INIT_FUNCS);
writeUleb128(SubSection.getStream(), InitFunctions.size(),
@@ -437,25 +434,40 @@
// Create an array of all function sorted by function index space
std::vector<const Symbol *> Names;
+ auto AddToNames = [&](Symbol* S) {
+ if (!S->isFunction() || S->WrittenToNameSec)
+ return;
+ // We also need to guard against two different symbols (two different
+ // names) for the same wasm function. While this is possible (aliases)
+ // it is not legal in the "name" section.
+ InputFunction *Function = S->getFunction();
+ if (Function) {
+ if (Function->WrittenToNameSec)
+ return;
+ Function->WrittenToNameSec = true;
+ }
+ S->WrittenToNameSec = true;
+ Names.emplace_back(S);
+ };
+
for (ObjFile *File : Symtab->ObjectFiles) {
Names.reserve(Names.size() + File->getSymbols().size());
+ DEBUG(dbgs() << "adding names from: " << File->getName() << "\n");
for (Symbol *S : File->getSymbols()) {
- if (!S->isFunction() || S->isWeak() || S->WrittenToNameSec)
+ if (S->isWeak())
continue;
- // We also need to guard against two different symbols (two different
- // names) for the same wasm function. While this is possible (aliases)
- // it is not legal in the "name" section.
- InputFunction *Function = S->getFunction();
- if (Function) {
- if (Function->WrittenToNameSec)
- continue;
- Function->WrittenToNameSec = true;
- }
- S->WrittenToNameSec = true;
- Names.emplace_back(S);
+ AddToNames(S);
}
}
+ DEBUG(dbgs() << "adding symtab names\n");
+ for (Symbol *S : Symtab->getSymbols()) {
+ DEBUG(dbgs() << "sym: " << S->getName() << "\n");
+ if (S->getFile())
+ continue;
+ AddToNames(S);
+ }
+
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name");
std::sort(Names.begin(), Names.end(), [](const Symbol *A, const Symbol *B) {
@@ -603,11 +615,15 @@
for (const WasmSignature &Sig : File->getWasmObj()->types())
File->TypeMap.push_back(registerType(Sig));
}
+
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (Sym->isFunction())
+ registerType(Sym->getFunctionType());
}
void Writer::assignIndexes() {
- uint32_t GlobalIndex = ImportedGlobals.size();
- uint32_t FunctionIndex = ImportedFunctions.size();
+ uint32_t GlobalIndex = ImportedGlobals.size() + DefinedGlobals.size();
+ uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size();
if (Config->StackPointerSymbol) {
DefinedGlobals.emplace_back(Config->StackPointerSymbol);
@@ -686,6 +702,57 @@
}
}
+static const int OPCODE_CALL = 0x10;
+static const int OPCODE_END = 0xb;
+
+// Create synthetic "__wasm_call_ctors" function based on ctor functions
+// in input object.
+void Writer::createCtorFunction() {
+ uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size();
+ Config->CtorSymbol->setOutputIndex(FunctionIndex);
+
+ // First write the body bytes to a string.
+ std::string FunctionBody;
+ static WasmSignature Signature = {{}, WASM_TYPE_NORESULT};
+ {
+ raw_string_ostream OS(FunctionBody);
+ writeUleb128(OS, 0, "num locals");
+ for (const WasmInitFunc &F : InitFunctions) {
+ writeU8(OS, OPCODE_CALL, "CALL");
+ writeUleb128(OS, F.FunctionIndex, "function index");
+ }
+ writeU8(OS, OPCODE_END, "END");
+ }
+
+ // Once we know the size of the body we can create the final function body
+ raw_string_ostream OS(CtorFunctionBody);
+ writeUleb128(OS, FunctionBody.size(), "function size");
+ OS.flush();
+ CtorFunctionBody += FunctionBody;
+ CtorFunction =
+ llvm::make_unique<SyntheticFunction>(Signature, CtorFunctionBody);
+ DefinedFunctions.emplace_back(CtorFunction.get());
+}
+
+// Populate InitFunctions vector with init functions from all input objects.
+// This is then used either when creating the output linking section or to
+// synthesize the "__wasm_call_ctors" function.
+void Writer::calculateInitFunctions() {
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ const WasmLinkingData &L = File->getWasmObj()->linkingData();
+ InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size());
+ for (const WasmInitFunc &F : L.InitFunctions)
+ InitFunctions.emplace_back(WasmInitFunc{
+ F.Priority, File->relocateFunctionIndex(F.FunctionIndex)});
+ }
+ // Sort in order of priority (lowest first) so that they are called
+ // in the correct order.
+ std::sort(InitFunctions.begin(), InitFunctions.end(),
+ [](const WasmInitFunc &L, const WasmInitFunc &R) {
+ return L.Priority < R.Priority;
+ });
+}
+
void Writer::run() {
if (!Config->Relocatable)
InitialTableOffset = 1;
@@ -696,6 +763,10 @@
calculateImports();
log("-- assignIndexes");
assignIndexes();
+ log("-- calculateInitFunctions");
+ calculateInitFunctions();
+ if (!Config->Relocatable)
+ createCtorFunction();
if (errorHandler().Verbose) {
log("Defined Functions: " + Twine(DefinedFunctions.size()));