diff options
Diffstat (limited to 'src/wasm-linker.h')
-rw-r--r-- | src/wasm-linker.h | 168 |
1 files changed, 98 insertions, 70 deletions
diff --git a/src/wasm-linker.h b/src/wasm-linker.h index 9065c4b3e..023cf198c 100644 --- a/src/wasm-linker.h +++ b/src/wasm-linker.h @@ -29,7 +29,9 @@ namespace wasm { -class Linker { +// An "object file" for linking. Contains a wasm module, plus the associated +// information needed for linking/layout. +class LinkerObject { public: struct Relocation { enum Kind { kData, kFunction }; @@ -43,50 +45,7 @@ class Linker { kind(kind), data(data), symbol(symbol), addend(addend) {} }; - Linker(Module& wasm, size_t globalBase, size_t stackAllocation, - size_t userInitialMemory, size_t userMaxMemory, - bool ignoreUnknownSymbols, Name startFunction, - bool debug) : - wasm(wasm), - ignoreUnknownSymbols(ignoreUnknownSymbols), - startFunction(startFunction), - globalBase(globalBase), - nextStatic(globalBase), - userInitialMemory(userInitialMemory), - userMaxMemory(userMaxMemory), - stackAllocation(stackAllocation), - debug(debug) { - if (userMaxMemory && userMaxMemory < userInitialMemory) { - Fatal() << "Specified max memory " << userMaxMemory << - " is < specified initial memory " << userInitialMemory; - } - if (roundUpToPageSize(userMaxMemory) != userMaxMemory) { - Fatal() << "Specified max memory " << userMaxMemory << - " is not a multiple of 64k"; - } - if (roundUpToPageSize(userInitialMemory) != userInitialMemory) { - Fatal() << "Specified initial memory " << userInitialMemory << - " is not a multiple of 64k"; - } - // Don't allow anything to be allocated at address 0 - if (globalBase == 0) nextStatic = 1; - // Place the stack pointer at the bottom of the linear memory, to keep its - // address small (and thus with a small encoding). - placeStackPointer(stackAllocation); - // Allocate __dso_handle. For asm.js, emscripten provides this in JS, but - // wasm modules can't import data objects. Its value is 0 for the main - // executable, which is all we have with static linking. In the future this - // can go in a crtbegin or similar file. - addStatic(4, 4, "__dso_handle"); - } - - // Allocate a static variable and return its address in linear memory - size_t allocateStatic(size_t allocSize, size_t alignment, Name name) { - size_t address = alignAddr(nextStatic, alignment); - staticAddresses[name] = address; - nextStatic = address + allocSize; - return address; - } + LinkerObject() {} // Allocate a static object void addStatic(size_t allocSize, size_t alignment, Name name) { @@ -98,7 +57,7 @@ class Linker { } void addRelocation(Relocation::Kind kind, uint32_t* target, Name name, int addend) { - relocations.emplace_back(make_unique<Relocation>(kind, target, name, addend)); + relocations.emplace_back(new Relocation(kind, target, name, addend)); } Relocation* getCurrentRelocation() { return relocations.back().get(); @@ -132,14 +91,13 @@ class Linker { assert(implementedFunctions.count(name)); } - // Allocate the user stack, set up the initial memory size of the module, lay - // out the linear memory, process the relocations, and set up the indirect - // function table. - void layout(); + bool isEmpty() { + return wasm.functions.empty(); + } - // Support for emscripten integration: generates dyncall thunks, emits - // metadata for asmConsts, staticBump and initializer functions. - void emscriptenGlue(std::ostream& o); + friend class Linker; + + Module wasm; private: struct StaticObject { @@ -150,6 +108,87 @@ class Linker { allocSize(allocSize), alignment(alignment), name(name) {} }; + std::vector<Name> globls; + + std::vector<StaticObject> staticObjects; + std::vector<std::unique_ptr<Relocation>> relocations; + + std::set<Name> implementedFunctions; + std::unordered_map<cashew::IString, Name> aliasedFunctions; + + std::map<Name, size_t> segments; // name => segment index (in wasm module) + + std::vector<Name> initializerFunctions; + + LinkerObject(const LinkerObject&) = delete; + LinkerObject& operator=(const LinkerObject&) = delete; + +}; + +// Class which performs some linker-like functionality; namely taking an object +// file with relocations, laying out the linear memory and segments, and +// applying the relocations, resulting in an executable wasm module. +class Linker { + public: + Linker(size_t globalBase, size_t stackAllocation, + size_t userInitialMemory, size_t userMaxMemory, + bool ignoreUnknownSymbols, Name startFunction, + bool debug) : + ignoreUnknownSymbols(ignoreUnknownSymbols), + startFunction(startFunction), + globalBase(globalBase), + nextStatic(globalBase), + userInitialMemory(userInitialMemory), + userMaxMemory(userMaxMemory), + stackAllocation(stackAllocation), + debug(debug) { + if (userMaxMemory && userMaxMemory < userInitialMemory) { + Fatal() << "Specified max memory " << userMaxMemory << + " is < specified initial memory " << userInitialMemory; + } + if (roundUpToPageSize(userMaxMemory) != userMaxMemory) { + Fatal() << "Specified max memory " << userMaxMemory << + " is not a multiple of 64k"; + } + if (roundUpToPageSize(userInitialMemory) != userInitialMemory) { + Fatal() << "Specified initial memory " << userInitialMemory << + " is not a multiple of 64k"; + } + // Don't allow anything to be allocated at address 0 + if (globalBase == 0) nextStatic = 1; + + // Place the stack pointer at the bottom of the linear memory, to keep its + // address small (and thus with a small encoding). + placeStackPointer(stackAllocation); + // Allocate __dso_handle. For asm.js, emscripten provides this in JS, but + // wasm modules can't import data objects. Its value is 0 for the main + // executable, which is all we have with static linking. In the future this + // can go in a crtbegin or similar file. + out.addStatic(4, 4, "__dso_handle"); + } + + // Return a reference to the LinkerObject for the main executable. If empty, + // it can be passed to an S2WasmBuilder and constructed. + LinkerObject& getOutput() { return out; } + + // Allocate the user stack, set up the initial memory size of the module, lay + // out the linear memory, process the relocations, and set up the indirect + // function table. + void layout(); + + // Support for emscripten integration: generates dyncall thunks, emits + // metadata for asmConsts, staticBump and initializer functions. + void emscriptenGlue(std::ostream& o); + + private: + // Allocate a static variable and return its address in linear memory + size_t allocateStatic(size_t allocSize, size_t alignment, Name name) { + size_t address = alignAddr(nextStatic, alignment); + staticAddresses[name] = address; + nextStatic = address + allocSize; + return address; + } + // Allocate space for a stack pointer and (if stackAllocation > 0) set up a // relocation for it to point to the top of the stack. void placeStackPointer(size_t stackAllocation); @@ -175,21 +214,21 @@ class Linker { } void exportFunction(Name name, bool must_export) { - if (!wasm.checkFunction(name)) { + if (!out.wasm.checkFunction(name)) { assert(!must_export); return; } - if (wasm.checkExport(name)) return; // Already exported - auto exp = wasm.allocator.alloc<Export>(); + if (out.wasm.checkExport(name)) return; // Already exported + auto exp = out.wasm.allocator.alloc<Export>(); exp->name = exp->value = name; - wasm.addExport(exp); + out.wasm.addExport(exp); } + // The output module (linked executable) + LinkerObject out; - Module& wasm; bool ignoreUnknownSymbols; Name startFunction; - std::vector<Name> globls; // where globals can start to be statically allocated, i.e., the data segment size_t globalBase; @@ -200,21 +239,10 @@ class Linker { size_t stackAllocation; bool debug; - std::vector<StaticObject> staticObjects; std::unordered_map<cashew::IString, int32_t> staticAddresses; // name => address - - std::vector<std::unique_ptr<Relocation>> relocations; - - std::set<Name> implementedFunctions; - std::unordered_map<cashew::IString, Name> aliasedFunctions; - - std::map<Name, size_t> segments; // name => segment index (in wasm module) std::unordered_map<size_t, size_t> segmentsByAddress; // address => segment index - std::unordered_map<cashew::IString, size_t> functionIndexes; - std::vector<Name> initializerFunctions; - }; |