[WebAssembly] Refactor synthetic sections and relocation processing. NFC.
Major refactor to better match the structure of the ELF linker.
- Split out relocation processing into scanRelocations
- Split out synthetic sections into their own classes.
Differential Revision: https://reviews.llvm.org/D61811
llvm-svn: 361233
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index f27c9ba..eb567ec 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -13,7 +13,9 @@
#include "InputGlobal.h"
#include "OutputSections.h"
#include "OutputSegment.h"
+#include "Relocations.h"
#include "SymbolTable.h"
+#include "SyntheticSections.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@@ -29,7 +31,6 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LEB128.h"
-#include "llvm/Support/Path.h"
#include <cstdarg>
#include <map>
@@ -42,18 +43,9 @@
using namespace lld::wasm;
static constexpr int StackAlignment = 16;
-static constexpr const char *FunctionTableName = "__indirect_function_table";
-const char *lld::wasm::DefaultModule = "env";
namespace {
-// An init entry to be written to either the synthetic init func or the
-// linking metadata.
-struct WasmInitEntry {
- const FunctionSymbol *Sym;
- uint32_t Priority;
-};
-
// The writer writes a SymbolTable result to a file.
class Writer {
public:
@@ -62,81 +54,40 @@
private:
void openFile();
- uint32_t lookupType(const WasmSignature &Sig);
- uint32_t registerType(const WasmSignature &Sig);
-
void createApplyRelocationsFunction();
void createCallCtorsFunction();
- void calculateInitFunctions();
- void processRelocations(InputChunk *Chunk);
void assignIndexes();
- void calculateTargetFeatures();
+ void populateSymtab();
+ void populateProducers();
+ void populateTargetFeatures();
+ void calculateInitFunctions();
void calculateImports();
void calculateExports();
void calculateCustomSections();
- void assignSymtab();
void calculateTypes();
void createOutputSegments();
void layoutMemory();
void createHeader();
- void createSections();
- SyntheticSection *createSyntheticSection(uint32_t Type, StringRef Name = "");
- // Builtin sections
- void createTypeSection();
- void createFunctionSection();
- void createTableSection();
- void createGlobalSection();
- void createEventSection();
- void createExportSection();
- void createImportSection();
- void createMemorySection();
- void createElemSection();
- void createDataCountSection();
- void createCodeSection();
- void createDataSection();
+ void addSection(OutputSection *Sec);
+
+ void addSections();
void createCustomSections();
+ void createSyntheticSections();
+ void finalizeSections();
// Custom sections
- void createDylinkSection();
void createRelocSections();
- void createLinkingSection();
- void createNameSection();
- void createProducersSection();
- void createTargetFeaturesSection();
void writeHeader();
void writeSections();
uint64_t FileSize = 0;
uint32_t TableBase = 0;
- uint32_t NumMemoryPages = 0;
- uint32_t MaxMemoryPages = 0;
- // Memory size and aligment. Written to the "dylink" section
- // when build with -shared or -pie.
- uint32_t MemAlign = 0;
- uint32_t MemSize = 0;
- std::vector<const WasmSignature *> Types;
- DenseMap<WasmSignature, int32_t> TypeIndices;
- std::vector<const Symbol *> ImportedSymbols;
- std::vector<const Symbol *> GOTSymbols;
- unsigned NumImportedFunctions = 0;
- unsigned NumImportedGlobals = 0;
- unsigned NumImportedEvents = 0;
- std::vector<WasmExport> Exports;
- std::vector<const DefinedData *> DefinedFakeGlobals;
- std::vector<InputGlobal *> InputGlobals;
- std::vector<InputFunction *> InputFunctions;
- std::vector<InputEvent *> InputEvents;
- std::vector<const FunctionSymbol *> IndirectFunctions;
- std::vector<const Symbol *> SymtabEntries;
std::vector<WasmInitEntry> InitFunctions;
-
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
- llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
- llvm::SmallSet<std::string, 8> TargetFeatures;
// Elements that are used to construct the final output
std::string Header;
@@ -150,210 +101,6 @@
} // anonymous namespace
-void Writer::createImportSection() {
- uint32_t NumImports = ImportedSymbols.size() + GOTSymbols.size();
- if (Config->ImportMemory)
- ++NumImports;
- if (Config->ImportTable)
- ++NumImports;
-
- if (NumImports == 0)
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_IMPORT);
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, NumImports, "import count");
-
- if (Config->ImportMemory) {
- WasmImport Import;
- Import.Module = DefaultModule;
- Import.Field = "memory";
- Import.Kind = WASM_EXTERNAL_MEMORY;
- Import.Memory.Flags = 0;
- Import.Memory.Initial = NumMemoryPages;
- if (MaxMemoryPages != 0 || Config->SharedMemory) {
- Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
- Import.Memory.Maximum = MaxMemoryPages;
- }
- if (Config->SharedMemory)
- Import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
- writeImport(OS, Import);
- }
-
- if (Config->ImportTable) {
- uint32_t TableSize = TableBase + IndirectFunctions.size();
- WasmImport Import;
- Import.Module = DefaultModule;
- Import.Field = FunctionTableName;
- Import.Kind = WASM_EXTERNAL_TABLE;
- Import.Table.ElemType = WASM_TYPE_FUNCREF;
- Import.Table.Limits = {0, TableSize, 0};
- writeImport(OS, Import);
- }
-
- for (const Symbol *Sym : ImportedSymbols) {
- WasmImport Import;
- if (auto *F = dyn_cast<UndefinedFunction>(Sym)) {
- Import.Field = F->ImportName;
- Import.Module = F->ImportModule;
- } else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) {
- Import.Field = G->ImportName;
- Import.Module = G->ImportModule;
- } else {
- Import.Field = Sym->getName();
- Import.Module = DefaultModule;
- }
-
- if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
- Import.Kind = WASM_EXTERNAL_FUNCTION;
- Import.SigIndex = lookupType(*FunctionSym->Signature);
- } else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
- Import.Kind = WASM_EXTERNAL_GLOBAL;
- Import.Global = *GlobalSym->getGlobalType();
- } else {
- auto *EventSym = cast<EventSymbol>(Sym);
- Import.Kind = WASM_EXTERNAL_EVENT;
- Import.Event.Attribute = EventSym->getEventType()->Attribute;
- Import.Event.SigIndex = lookupType(*EventSym->Signature);
- }
- writeImport(OS, Import);
- }
-
- for (const Symbol *Sym : GOTSymbols) {
- WasmImport Import;
- Import.Kind = WASM_EXTERNAL_GLOBAL;
- Import.Global = {WASM_TYPE_I32, true};
- if (isa<DataSymbol>(Sym))
- Import.Module = "GOT.mem";
- else
- Import.Module = "GOT.func";
- Import.Field = Sym->getName();
- writeImport(OS, Import);
- }
-}
-
-void Writer::createTypeSection() {
- if (!Types.size())
- return;
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_TYPE);
- raw_ostream &OS = Section->getStream();
- writeUleb128(OS, Types.size(), "type count");
- for (const WasmSignature *Sig : Types)
- writeSig(OS, *Sig);
-}
-
-void Writer::createFunctionSection() {
- if (InputFunctions.empty())
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION);
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, InputFunctions.size(), "function count");
- for (const InputFunction *Func : InputFunctions)
- writeUleb128(OS, lookupType(Func->Signature), "sig index");
-}
-
-void Writer::createMemorySection() {
- if (Config->ImportMemory)
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY);
- raw_ostream &OS = Section->getStream();
-
- bool HasMax = MaxMemoryPages != 0 || Config->SharedMemory;
- writeUleb128(OS, 1, "memory count");
- unsigned Flags = 0;
- if (HasMax)
- Flags |= WASM_LIMITS_FLAG_HAS_MAX;
- if (Config->SharedMemory)
- Flags |= WASM_LIMITS_FLAG_IS_SHARED;
- writeUleb128(OS, Flags, "memory limits flags");
- writeUleb128(OS, NumMemoryPages, "initial pages");
- if (HasMax)
- writeUleb128(OS, MaxMemoryPages, "max pages");
-}
-
-void Writer::createGlobalSection() {
- unsigned NumGlobals = InputGlobals.size() + DefinedFakeGlobals.size();
- if (NumGlobals == 0)
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL);
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, NumGlobals, "global count");
- for (const InputGlobal *G : InputGlobals)
- writeGlobal(OS, G->Global);
- for (const DefinedData *Sym : DefinedFakeGlobals) {
- WasmGlobal Global;
- Global.Type = {WASM_TYPE_I32, false};
- Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
- writeGlobal(OS, Global);
- }
-}
-
-// The event section contains a list of declared wasm events associated with the
-// module. Currently the only supported event kind is exceptions. A single event
-// entry represents a single event with an event tag. All C++ exceptions are
-// represented by a single event. An event entry in this section contains
-// information on what kind of event it is (e.g. exception) and the type of
-// values contained in a single event object. (In wasm, an event can contain
-// multiple values of primitive types. But for C++ exceptions, we just throw a
-// pointer which is an i32 value (for wasm32 architecture), so the signature of
-// C++ exception is (i32)->(void), because all event types are assumed to have
-// void return type to share WasmSignature with functions.)
-void Writer::createEventSection() {
- unsigned NumEvents = InputEvents.size();
- if (NumEvents == 0)
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_EVENT);
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, NumEvents, "event count");
- for (InputEvent *E : InputEvents) {
- E->Event.Type.SigIndex = lookupType(E->Signature);
- writeEvent(OS, E->Event);
- }
-}
-
-void Writer::createTableSection() {
- if (Config->ImportTable)
- return;
-
- // Always output a table section (or table import), even if there are no
- // indirect calls. There are two reasons for this:
- // 1. For executables it is useful to have an empty table slot at 0
- // which can be filled with a null function call handler.
- // 2. If we don't do this, any program that contains a call_indirect but
- // no address-taken function will fail at validation time since it is
- // a validation error to include a call_indirect instruction if there
- // is not table.
- uint32_t TableSize = TableBase + IndirectFunctions.size();
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE);
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, 1, "table count");
- WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
- writeTableType(OS, WasmTable{WASM_TYPE_FUNCREF, Limits});
-}
-
-void Writer::createExportSection() {
- if (!Exports.size())
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT);
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, Exports.size(), "export count");
- for (const WasmExport &Export : Exports)
- writeExport(OS, Export);
-}
-
void Writer::calculateCustomSections() {
log("calculateCustomSections");
bool StripDebug = Config->StripDebug || Config->StripAll;
@@ -377,75 +124,18 @@
log("createCustomSections");
for (auto &Pair : CustomSectionMapping) {
StringRef Name = Pair.first();
-
- auto P = CustomSectionSymbols.find(Name);
- if (P != CustomSectionSymbols.end()) {
- uint32_t SectionIndex = OutputSections.size();
- P->second->setOutputSectionIndex(SectionIndex);
- }
-
LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
- OutputSections.push_back(make<CustomSection>(Name, Pair.second));
+
+ OutputSection *Sec = make<CustomSection>(Name, Pair.second);
+ if (Config->Relocatable) {
+ auto *Sym = make<OutputSectionSymbol>(Sec);
+ Out.LinkingSec->addToSymtab(Sym);
+ Sec->SectionSym = Sym;
+ }
+ addSection(Sec);
}
}
-void Writer::createElemSection() {
- if (IndirectFunctions.empty())
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_ELEM);
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, 1, "segment count");
- writeUleb128(OS, 0, "table index");
- WasmInitExpr InitExpr;
- if (Config->Pic) {
- InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
- InitExpr.Value.Global = WasmSym::TableBase->getGlobalIndex();
- } else {
- InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- InitExpr.Value.Int32 = TableBase;
- }
- writeInitExpr(OS, InitExpr);
- writeUleb128(OS, IndirectFunctions.size(), "elem count");
-
- uint32_t TableIndex = TableBase;
- for (const FunctionSymbol *Sym : IndirectFunctions) {
- assert(Sym->getTableIndex() == TableIndex);
- writeUleb128(OS, Sym->getFunctionIndex(), "function index");
- ++TableIndex;
- }
-}
-
-void Writer::createDataCountSection() {
- if (!Segments.size() || !TargetFeatures.count("bulk-memory"))
- return;
-
- log("createDataCountSection");
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_DATACOUNT);
- raw_ostream &OS = Section->getStream();
- writeUleb128(OS, Segments.size(), "data count");
-}
-
-void Writer::createCodeSection() {
- if (InputFunctions.empty())
- return;
-
- log("createCodeSection");
-
- auto Section = make<CodeSection>(InputFunctions);
- OutputSections.push_back(Section);
-}
-
-void Writer::createDataSection() {
- if (!Segments.size())
- return;
-
- log("createDataSection");
- auto Section = make<DataSection>(Segments);
- OutputSections.push_back(Section);
-}
-
// Create relocations sections in the final output.
// These are only created when relocatable output is requested.
void Writer::createRelocSections() {
@@ -453,293 +143,33 @@
// Don't use iterator here since we are adding to OutputSection
size_t OrigSize = OutputSections.size();
for (size_t I = 0; I < OrigSize; I++) {
- OutputSection *OSec = OutputSections[I];
- uint32_t Count = OSec->numRelocations();
+ LLVM_DEBUG(dbgs() << "check section " << I << "\n");
+ OutputSection *Sec = OutputSections[I];
+
+ // Count the number of needed sections.
+ uint32_t Count = Sec->numRelocations();
if (!Count)
continue;
StringRef Name;
- if (OSec->Type == WASM_SEC_DATA)
+ if (Sec->Type == WASM_SEC_DATA)
Name = "reloc.DATA";
- else if (OSec->Type == WASM_SEC_CODE)
+ else if (Sec->Type == WASM_SEC_CODE)
Name = "reloc.CODE";
- else if (OSec->Type == WASM_SEC_CUSTOM)
- Name = Saver.save("reloc." + OSec->Name);
+ else if (Sec->Type == WASM_SEC_CUSTOM)
+ Name = Saver.save("reloc." + Sec->Name);
else
llvm_unreachable(
"relocations only supported for code, data, or custom sections");
- OutputSections.push_back(make<RelocSection>(Name, OSec, I));
+ addSection(make<RelocSection>(Name, Sec));
}
}
-static uint32_t getWasmFlags(const Symbol *Sym) {
- uint32_t Flags = 0;
- if (Sym->isLocal())
- Flags |= WASM_SYMBOL_BINDING_LOCAL;
- if (Sym->isWeak())
- Flags |= WASM_SYMBOL_BINDING_WEAK;
- if (Sym->isHidden())
- Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
- if (Sym->isUndefined())
- Flags |= WASM_SYMBOL_UNDEFINED;
- if (auto *F = dyn_cast<UndefinedFunction>(Sym)) {
- if (F->getName() != F->ImportName)
- Flags |= WASM_SYMBOL_EXPLICIT_NAME;
- } else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) {
- if (G->getName() != G->ImportName)
- Flags |= WASM_SYMBOL_EXPLICIT_NAME;
- }
- return Flags;
-}
-
-// Some synthetic sections (e.g. "name" and "linking") have subsections.
-// Just like the synthetic sections themselves these need to be created before
-// they can be written out (since they are preceded by their length). This
-// class is used to create subsections and then write them into the stream
-// of the parent section.
-class SubSection {
-public:
- explicit SubSection(uint32_t Type) : Type(Type) {}
-
- void writeTo(raw_ostream &To) {
- OS.flush();
- writeUleb128(To, Type, "subsection type");
- writeUleb128(To, Body.size(), "subsection size");
- To.write(Body.data(), Body.size());
- }
-
-private:
- uint32_t Type;
- std::string Body;
-
-public:
- raw_string_ostream OS{Body};
-};
-
-// Create the custom "dylink" section containing information for the dynamic
-// linker.
-// See
-// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
-void Writer::createDylinkSection() {
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "dylink");
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, MemSize, "MemSize");
- writeUleb128(OS, MemAlign, "MemAlign");
- writeUleb128(OS, IndirectFunctions.size(), "TableSize");
- writeUleb128(OS, 0, "TableAlign");
- writeUleb128(OS, Symtab->SharedFiles.size(), "Needed");
- for (auto *SO : Symtab->SharedFiles)
- writeStr(OS, llvm::sys::path::filename(SO->getName()), "so name");
-}
-
-// Create the custom "linking" section containing linker metadata.
-// This is only created when relocatable output is requested.
-void Writer::createLinkingSection() {
- SyntheticSection *Section =
- createSyntheticSection(WASM_SEC_CUSTOM, "linking");
- raw_ostream &OS = Section->getStream();
-
- writeUleb128(OS, WasmMetadataVersion, "Version");
-
- if (!SymtabEntries.empty()) {
- SubSection Sub(WASM_SYMBOL_TABLE);
- writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols");
-
- for (const Symbol *Sym : SymtabEntries) {
- assert(Sym->isDefined() || Sym->isUndefined());
- WasmSymbolType Kind = Sym->getWasmType();
- uint32_t Flags = getWasmFlags(Sym);
-
- writeU8(Sub.OS, Kind, "sym kind");
- writeUleb128(Sub.OS, Flags, "sym flags");
-
- if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
- writeUleb128(Sub.OS, F->getFunctionIndex(), "index");
- if (Sym->isDefined() ||
- (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
- writeStr(Sub.OS, Sym->getName(), "sym name");
- } else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {
- writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
- if (Sym->isDefined() ||
- (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
- writeStr(Sub.OS, Sym->getName(), "sym name");
- } else if (auto *E = dyn_cast<EventSymbol>(Sym)) {
- writeUleb128(Sub.OS, E->getEventIndex(), "index");
- if (Sym->isDefined() ||
- (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
- writeStr(Sub.OS, Sym->getName(), "sym name");
- } else if (isa<DataSymbol>(Sym)) {
- writeStr(Sub.OS, Sym->getName(), "sym name");
- if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
- writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
- writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(),
- "data offset");
- writeUleb128(Sub.OS, DataSym->getSize(), "data size");
- }
- } else {
- auto *S = cast<SectionSymbol>(Sym);
- writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index");
- }
- }
-
- Sub.writeTo(OS);
- }
-
- if (Segments.size()) {
- SubSection Sub(WASM_SEGMENT_INFO);
- writeUleb128(Sub.OS, Segments.size(), "num data segments");
- for (const OutputSegment *S : Segments) {
- writeStr(Sub.OS, S->Name, "segment name");
- writeUleb128(Sub.OS, S->Alignment, "alignment");
- writeUleb128(Sub.OS, 0, "flags");
- }
- Sub.writeTo(OS);
- }
-
- if (!InitFunctions.empty()) {
- SubSection Sub(WASM_INIT_FUNCS);
- writeUleb128(Sub.OS, InitFunctions.size(), "num init functions");
- for (const WasmInitEntry &F : InitFunctions) {
- writeUleb128(Sub.OS, F.Priority, "priority");
- writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index");
- }
- Sub.writeTo(OS);
- }
-
- struct ComdatEntry {
- unsigned Kind;
- uint32_t Index;
- };
- std::map<StringRef, std::vector<ComdatEntry>> Comdats;
-
- for (const InputFunction *F : InputFunctions) {
- StringRef Comdat = F->getComdatName();
- if (!Comdat.empty())
- Comdats[Comdat].emplace_back(
- ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()});
- }
- for (uint32_t I = 0; I < Segments.size(); ++I) {
- const auto &InputSegments = Segments[I]->InputSegments;
- if (InputSegments.empty())
- continue;
- StringRef Comdat = InputSegments[0]->getComdatName();
-#ifndef NDEBUG
- for (const InputSegment *IS : InputSegments)
- assert(IS->getComdatName() == Comdat);
-#endif
- if (!Comdat.empty())
- Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I});
- }
-
- if (!Comdats.empty()) {
- SubSection Sub(WASM_COMDAT_INFO);
- writeUleb128(Sub.OS, Comdats.size(), "num comdats");
- for (const auto &C : Comdats) {
- writeStr(Sub.OS, C.first, "comdat name");
- writeUleb128(Sub.OS, 0, "comdat flags"); // flags for future use
- writeUleb128(Sub.OS, C.second.size(), "num entries");
- for (const ComdatEntry &Entry : C.second) {
- writeU8(Sub.OS, Entry.Kind, "entry kind");
- writeUleb128(Sub.OS, Entry.Index, "entry index");
- }
- }
- Sub.writeTo(OS);
- }
-}
-
-// Create the custom "name" section containing debug symbol names.
-void Writer::createNameSection() {
- unsigned NumNames = NumImportedFunctions;
- for (const InputFunction *F : InputFunctions)
- if (!F->getName().empty() || !F->getDebugName().empty())
- ++NumNames;
-
- if (NumNames == 0)
- return;
-
- SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name");
-
- SubSection Sub(WASM_NAMES_FUNCTION);
- writeUleb128(Sub.OS, NumNames, "name count");
-
- // Names must appear in function index order. As it happens ImportedSymbols
- // and InputFunctions are numbered in order with imported functions coming
- // first.
- for (const Symbol *S : ImportedSymbols) {
- if (auto *F = dyn_cast<FunctionSymbol>(S)) {
- writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
- writeStr(Sub.OS, toString(*S), "symbol name");
- }
- }
- for (const InputFunction *F : InputFunctions) {
- if (!F->getName().empty()) {
- writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
- if (!F->getDebugName().empty()) {
- writeStr(Sub.OS, F->getDebugName(), "symbol name");
- } else {
- writeStr(Sub.OS, maybeDemangleSymbol(F->getName()), "symbol name");
- }
- }
- }
-
- Sub.writeTo(Section->getStream());
-}
-
-void Writer::createProducersSection() {
- SmallVector<std::pair<std::string, std::string>, 8> Languages;
- SmallVector<std::pair<std::string, std::string>, 8> Tools;
- SmallVector<std::pair<std::string, std::string>, 8> SDKs;
+void Writer::populateProducers() {
for (ObjFile *File : Symtab->ObjectFiles) {
const WasmProducerInfo &Info = File->getWasmObj()->getProducerInfo();
- for (auto &Producers : {std::make_pair(&Info.Languages, &Languages),
- std::make_pair(&Info.Tools, &Tools),
- std::make_pair(&Info.SDKs, &SDKs)})
- for (auto &Producer : *Producers.first)
- if (Producers.second->end() ==
- llvm::find_if(*Producers.second,
- [&](std::pair<std::string, std::string> Seen) {
- return Seen.first == Producer.first;
- }))
- Producers.second->push_back(Producer);
- }
- int FieldCount =
- int(!Languages.empty()) + int(!Tools.empty()) + int(!SDKs.empty());
- if (FieldCount == 0)
- return;
- SyntheticSection *Section =
- createSyntheticSection(WASM_SEC_CUSTOM, "producers");
- auto &OS = Section->getStream();
- writeUleb128(OS, FieldCount, "field count");
- for (auto &Field :
- {std::make_pair("language", Languages),
- std::make_pair("processed-by", Tools), std::make_pair("sdk", SDKs)}) {
- if (Field.second.empty())
- continue;
- writeStr(OS, Field.first, "field name");
- writeUleb128(OS, Field.second.size(), "number of entries");
- for (auto &Entry : Field.second) {
- writeStr(OS, Entry.first, "producer name");
- writeStr(OS, Entry.second, "producer version");
- }
- }
-}
-
-void Writer::createTargetFeaturesSection() {
- if (TargetFeatures.empty())
- return;
-
- SmallVector<std::string, 8> Emitted(TargetFeatures.begin(),
- TargetFeatures.end());
- llvm::sort(Emitted);
- SyntheticSection *Section =
- createSyntheticSection(WASM_SEC_CUSTOM, "target_features");
- auto &OS = Section->getStream();
- writeUleb128(OS, Emitted.size(), "feature count");
- for (auto &Feature : Emitted) {
- writeU8(OS, WASM_FEATURE_PREFIX_USED, "feature used prefix");
- writeStr(OS, Feature, "feature name");
+ Out.ProducersSec->addInfo(Info);
}
}
@@ -749,7 +179,10 @@
void Writer::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
- parallelForEach(OutputSections, [Buf](OutputSection *S) { S->writeTo(Buf); });
+ parallelForEach(OutputSections, [Buf](OutputSection *S) {
+ assert(S->isNeeded());
+ S->writeTo(Buf);
+ });
}
// Fix the memory layout of the output binary. This assigns memory offsets
@@ -766,8 +199,6 @@
// rather than overwriting global data, but also increases code size since all
// static data loads and stores requires larger offsets.
void Writer::layoutMemory() {
- createOutputSegments();
-
uint32_t MemoryPtr = 0;
auto PlaceStack = [&]() {
@@ -798,9 +229,9 @@
if (WasmSym::DsoHandle)
WasmSym::DsoHandle->setVirtualAddress(DataStart);
- MemAlign = 0;
+ Out.DylinkSec->MemAlign = 0;
for (OutputSegment *Seg : Segments) {
- MemAlign = std::max(MemAlign, Seg->Alignment);
+ Out.DylinkSec->MemAlign = std::max(Out.DylinkSec->MemAlign, Seg->Alignment);
MemoryPtr = alignTo(MemoryPtr, 1ULL << Seg->Alignment);
Seg->StartVA = MemoryPtr;
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name,
@@ -815,7 +246,7 @@
log("mem: static data = " + Twine(MemoryPtr - DataStart));
if (Config->Shared) {
- MemSize = MemoryPtr;
+ Out.DylinkSec->MemSize = MemoryPtr;
return;
}
@@ -838,9 +269,10 @@
else
MemoryPtr = Config->InitialMemory;
}
- MemSize = MemoryPtr;
- NumMemoryPages = alignTo(MemoryPtr, WasmPageSize) / WasmPageSize;
- log("mem: total pages = " + Twine(NumMemoryPages));
+ Out.DylinkSec->MemSize = MemoryPtr;
+ Out.MemorySec->NumMemoryPages =
+ alignTo(MemoryPtr, WasmPageSize) / WasmPageSize;
+ log("mem: total pages = " + Twine(Out.MemorySec->NumMemoryPages));
// Check max if explicitly supplied or required by shared memory
if (Config->MaxMemory != 0 || Config->SharedMemory) {
@@ -848,51 +280,48 @@
error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
if (MemoryPtr > Config->MaxMemory)
error("maximum memory too small, " + Twine(MemoryPtr) + " bytes needed");
- MaxMemoryPages = Config->MaxMemory / WasmPageSize;
- log("mem: max pages = " + Twine(MaxMemoryPages));
+ Out.MemorySec->MaxMemoryPages = Config->MaxMemory / WasmPageSize;
+ log("mem: max pages = " + Twine(Out.MemorySec->MaxMemoryPages));
}
}
-SyntheticSection *Writer::createSyntheticSection(uint32_t Type,
- StringRef Name) {
- auto Sec = make<SyntheticSection>(Type, Name);
- log("createSection: " + toString(*Sec));
+void Writer::addSection(OutputSection *Sec) {
+ if (!Sec->isNeeded())
+ return;
+ log("addSection: " + toString(*Sec));
+ Sec->SectionIndex = OutputSections.size();
OutputSections.push_back(Sec);
- return Sec;
}
-void Writer::createSections() {
- // Known sections
- if (Config->Pic)
- createDylinkSection();
- createTypeSection();
- createImportSection();
- createFunctionSection();
- createTableSection();
- createMemorySection();
- createGlobalSection();
- createEventSection();
- createExportSection();
- createElemSection();
- createDataCountSection();
- createCodeSection();
- createDataSection();
+void Writer::addSections() {
+ addSection(Out.DylinkSec);
+ addSection(Out.TypeSec);
+ addSection(Out.ImportSec);
+ addSection(Out.FunctionSec);
+ addSection(Out.TableSec);
+ addSection(Out.MemorySec);
+ addSection(Out.GlobalSec);
+ addSection(Out.EventSec);
+ addSection(Out.ExportSec);
+ addSection(Out.ElemSec);
+ addSection(Out.DataCountSec);
+
+ addSection(make<CodeSection>(Out.FunctionSec->InputFunctions));
+ addSection(make<DataSection>(Segments));
+
createCustomSections();
- // Custom sections
+ addSection(Out.LinkingSec);
if (Config->Relocatable) {
- createLinkingSection();
createRelocSections();
}
- if (!Config->StripDebug && !Config->StripAll)
- createNameSection();
+ addSection(Out.NameSec);
+ addSection(Out.ProducersSec);
+ addSection(Out.TargetFeaturesSec);
+}
- if (!Config->StripAll) {
- createProducersSection();
- createTargetFeaturesSection();
- }
-
+void Writer::finalizeSections() {
for (OutputSection *S : OutputSections) {
S->setOffset(FileSize);
S->finalizeContents();
@@ -900,7 +329,7 @@
}
}
-void Writer::calculateTargetFeatures() {
+void Writer::populateTargetFeatures() {
SmallSet<std::string, 8> Used;
SmallSet<std::string, 8> Required;
SmallSet<std::string, 8> Disallowed;
@@ -910,7 +339,7 @@
if (!InferFeatures) {
for (auto &Feature : Config->Features.getValue())
- TargetFeatures.insert(Feature);
+ Out.TargetFeaturesSec->Features.insert(Feature);
// No need to read or check features
if (!Config->CheckFeatures)
return;
@@ -938,9 +367,9 @@
}
if (InferFeatures)
- TargetFeatures.insert(Used.begin(), Used.end());
+ Out.TargetFeaturesSec->Features.insert(Used.begin(), Used.end());
- if (TargetFeatures.count("atomics") && !Config->SharedMemory)
+ if (Out.TargetFeaturesSec->Features.count("atomics") && !Config->SharedMemory)
error("'atomics' feature is used, so --shared-memory must be used");
if (!Config->CheckFeatures)
@@ -953,7 +382,7 @@
// Validate that used features are allowed in output
if (!InferFeatures) {
for (auto &Feature : Used) {
- if (!TargetFeatures.count(Feature))
+ if (!Out.TargetFeaturesSec->Features.count(Feature))
error(Twine("Target feature '") + Feature + "' is not allowed.");
}
}
@@ -993,13 +422,7 @@
continue;
LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
- ImportedSymbols.emplace_back(Sym);
- if (auto *F = dyn_cast<FunctionSymbol>(Sym))
- F->setFunctionIndex(NumImportedFunctions++);
- else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
- G->setGlobalIndex(NumImportedGlobals++);
- else
- cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
+ Out.ImportSec->addImport(Sym);
}
}
@@ -1008,12 +431,15 @@
return;
if (!Config->Relocatable && !Config->ImportMemory)
- Exports.push_back(WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
+ Out.ExportSec->Exports.push_back(
+ WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
if (!Config->Relocatable && Config->ExportTable)
- Exports.push_back(WasmExport{FunctionTableName, WASM_EXTERNAL_TABLE, 0});
+ Out.ExportSec->Exports.push_back(
+ WasmExport{FunctionTableName, WASM_EXTERNAL_TABLE, 0});
- unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
+ unsigned FakeGlobalIndex =
+ Out.ImportSec->NumImportedGlobals + Out.GlobalSec->InputGlobals.size();
for (Symbol *Sym : Symtab->getSymbols()) {
if (!Sym->isExported())
@@ -1039,78 +465,31 @@
Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()};
} else {
auto *D = cast<DefinedData>(Sym);
- DefinedFakeGlobals.emplace_back(D);
+ Out.GlobalSec->DefinedFakeGlobals.emplace_back(D);
Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++};
}
LLVM_DEBUG(dbgs() << "Export: " << Name << "\n");
- Exports.push_back(Export);
+ Out.ExportSec->Exports.push_back(Export);
}
}
-void Writer::assignSymtab() {
+void Writer::populateSymtab() {
if (!Config->Relocatable)
return;
- StringMap<uint32_t> SectionSymbolIndices;
-
- unsigned SymbolIndex = SymtabEntries.size();
-
- auto AddSymbol = [&](Symbol *Sym) {
- if (auto *S = dyn_cast<SectionSymbol>(Sym)) {
- StringRef Name = S->getName();
- if (CustomSectionMapping.count(Name) == 0)
- return;
-
- auto SSI = SectionSymbolIndices.find(Name);
- if (SSI != SectionSymbolIndices.end()) {
- Sym->setOutputSymbolIndex(SSI->second);
- return;
- }
-
- SectionSymbolIndices[Name] = SymbolIndex;
- CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym);
-
- Sym->markLive();
- }
-
- // (Since this is relocatable output, GC is not performed so symbols must
- // be live.)
- assert(Sym->isLive());
- Sym->setOutputSymbolIndex(SymbolIndex++);
- SymtabEntries.emplace_back(Sym);
- };
-
for (Symbol *Sym : Symtab->getSymbols())
if (Sym->IsUsedInRegularObj)
- AddSymbol(Sym);
+ Out.LinkingSec->addToSymtab(Sym);
for (ObjFile *File : Symtab->ObjectFiles) {
LLVM_DEBUG(dbgs() << "Local symtab entries: " << File->getName() << "\n");
for (Symbol *Sym : File->getSymbols())
- if (Sym->isLocal())
- AddSymbol(Sym);
+ if (Sym->isLocal() && !isa<SectionSymbol>(Sym))
+ Out.LinkingSec->addToSymtab(Sym);
}
}
-uint32_t Writer::lookupType(const WasmSignature &Sig) {
- auto It = TypeIndices.find(Sig);
- if (It == TypeIndices.end()) {
- error("type not found: " + toString(Sig));
- return 0;
- }
- return It->second;
-}
-
-uint32_t Writer::registerType(const WasmSignature &Sig) {
- auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
- if (Pair.second) {
- LLVM_DEBUG(dbgs() << "type " << toString(Sig) << "\n");
- Types.push_back(&Sig);
- }
- return Pair.first->second;
-}
-
void Writer::calculateTypes() {
// The output type section is the union of the following sets:
// 1. Any signature used in the TYPE relocation
@@ -1123,162 +502,62 @@
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
for (uint32_t I = 0; I < Types.size(); I++)
if (File->TypeIsUsed[I])
- File->TypeMap[I] = registerType(Types[I]);
+ File->TypeMap[I] = Out.TypeSec->registerType(Types[I]);
}
- for (const Symbol *Sym : ImportedSymbols) {
+ for (const Symbol *Sym : Out.ImportSec->ImportedSymbols) {
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
- registerType(*F->Signature);
+ Out.TypeSec->registerType(*F->Signature);
else if (auto *E = dyn_cast<EventSymbol>(Sym))
- registerType(*E->Signature);
+ Out.TypeSec->registerType(*E->Signature);
}
- for (const InputFunction *F : InputFunctions)
- registerType(F->Signature);
+ for (const InputFunction *F : Out.FunctionSec->InputFunctions)
+ Out.TypeSec->registerType(F->Signature);
- for (const InputEvent *E : InputEvents)
- registerType(E->Signature);
+ for (const InputEvent *E : Out.EventSec->InputEvents)
+ Out.TypeSec->registerType(E->Signature);
}
-static bool requiresGOTAccess(const Symbol* Sym) {
- return Config->Pic && !Sym->isHidden() && !Sym->isLocal();
-}
-
-void Writer::processRelocations(InputChunk *Chunk) {
- if (!Chunk->Live)
- return;
- ObjFile *File = Chunk->File;
- ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
- for (const WasmRelocation &Reloc : Chunk->getRelocations()) {
- if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) {
- // Mark target type as live
- File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
- File->TypeIsUsed[Reloc.Index] = true;
- continue;
- }
-
- // Other relocation types all have a corresponding symbol
- auto *Sym = File->getSymbols()[Reloc.Index];
- switch (Reloc.Type) {
- case R_WASM_TABLE_INDEX_I32:
- case R_WASM_TABLE_INDEX_SLEB:
- case R_WASM_TABLE_INDEX_REL_SLEB: {
- auto *F = cast<FunctionSymbol>(Sym);
- if (F->hasTableIndex() || !F->hasFunctionIndex() || requiresGOTAccess(F))
- break;
- F->setTableIndex(TableBase + IndirectFunctions.size());
- IndirectFunctions.emplace_back(F);
- break;
- }
- case R_WASM_TYPE_INDEX_LEB:
- break;
- case R_WASM_GLOBAL_INDEX_LEB:
- if (!isa<GlobalSymbol>(Sym) && !Sym->isInGOT()) {
- Sym->setGOTIndex(NumImportedGlobals++);
- GOTSymbols.push_back(Sym);
- }
- break;
- case R_WASM_MEMORY_ADDR_SLEB:
- case R_WASM_MEMORY_ADDR_LEB:
- case R_WASM_MEMORY_ADDR_REL_SLEB:
- if (!Config->Relocatable) {
- if (Sym->isUndefined() && !Sym->isWeak()) {
- error(toString(File) + ": cannot resolve relocation of type " +
- relocTypeToString(Reloc.Type) +
- " against undefined (non-weak) data symbol: " + toString(*Sym));
- }
- }
- break;
- }
-
- if (Config->Pic) {
- switch (Reloc.Type) {
- case R_WASM_TABLE_INDEX_SLEB:
- case R_WASM_MEMORY_ADDR_SLEB:
- case R_WASM_MEMORY_ADDR_LEB:
- // Certain relocation types can't be used when building PIC output, since
- // they would require absolute symbol addresses at link time.
- error(toString(File) + ": relocation " +
- relocTypeToString(Reloc.Type) + " cannot be used againt symbol " +
- toString(*Sym) + "; recompile with -fPIC");
- break;
- case R_WASM_TABLE_INDEX_I32:
- case R_WASM_MEMORY_ADDR_I32:
- // These relocation types are only present in the data section and
- // will be converted into code by `generateRelocationCode`. This code
- // requires the symbols to have GOT entires.
- if (requiresGOTAccess(Sym) && !Sym->isInGOT()) {
- Sym->setGOTIndex(NumImportedGlobals++);
- GOTSymbols.push_back(Sym);
- }
- break;
- }
- }
+static void scanRelocations() {
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ LLVM_DEBUG(dbgs() << "scanRelocations: " << File->getName() << "\n");
+ for (InputChunk *Chunk : File->Functions)
+ scanRelocations(Chunk);
+ for (InputChunk *Chunk : File->Segments)
+ scanRelocations(Chunk);
+ for (auto &P : File->CustomSections)
+ scanRelocations(P);
}
}
void Writer::assignIndexes() {
- assert(InputFunctions.empty());
- uint32_t FunctionIndex = NumImportedFunctions;
- auto AddDefinedFunction = [&](InputFunction *Func) {
- if (!Func->Live)
- return;
- InputFunctions.emplace_back(Func);
- Func->setFunctionIndex(FunctionIndex++);
- };
+ assert(Out.FunctionSec->InputFunctions.empty());
for (InputFunction *Func : Symtab->SyntheticFunctions)
- AddDefinedFunction(Func);
+ Out.FunctionSec->addFunction(Func);
for (ObjFile *File : Symtab->ObjectFiles) {
LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
for (InputFunction *Func : File->Functions)
- AddDefinedFunction(Func);
+ Out.FunctionSec->addFunction(Func);
}
- for (ObjFile *File : Symtab->ObjectFiles) {
- LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
- for (InputChunk *Chunk : File->Functions)
- processRelocations(Chunk);
- for (InputChunk *Chunk : File->Segments)
- processRelocations(Chunk);
- for (auto &P : File->CustomSections)
- processRelocations(P);
- }
-
- assert(InputGlobals.empty());
- uint32_t GlobalIndex = NumImportedGlobals;
- auto AddDefinedGlobal = [&](InputGlobal *Global) {
- if (Global->Live) {
- LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
- Global->setGlobalIndex(GlobalIndex++);
- InputGlobals.push_back(Global);
- }
- };
+ scanRelocations();
for (InputGlobal *Global : Symtab->SyntheticGlobals)
- AddDefinedGlobal(Global);
+ Out.GlobalSec->addGlobal(Global);
for (ObjFile *File : Symtab->ObjectFiles) {
LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
for (InputGlobal *Global : File->Globals)
- AddDefinedGlobal(Global);
+ Out.GlobalSec->addGlobal(Global);
}
- assert(InputEvents.empty());
- uint32_t EventIndex = NumImportedEvents;
- auto AddDefinedEvent = [&](InputEvent *Event) {
- if (Event->Live) {
- LLVM_DEBUG(dbgs() << "AddDefinedEvent: " << EventIndex << "\n");
- Event->setEventIndex(EventIndex++);
- InputEvents.push_back(Event);
- }
- };
-
for (ObjFile *File : Symtab->ObjectFiles) {
LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n");
for (InputEvent *Event : File->Events)
- AddDefinedEvent(Event);
+ Out.EventSec->addEvent(Event);
}
}
@@ -1408,6 +687,24 @@
});
}
+void Writer::createSyntheticSections() {
+ Out.DylinkSec = make<DylinkSection>();
+ Out.TypeSec = make<TypeSection>();
+ Out.ImportSec = make<ImportSection>();
+ Out.FunctionSec = make<FunctionSection>();
+ Out.TableSec = make<TableSection>();
+ Out.MemorySec = make<MemorySection>();
+ Out.GlobalSec = make<GlobalSection>();
+ Out.EventSec = make<EventSection>();
+ Out.ExportSec = make<ExportSection>();
+ Out.ElemSec = make<ElemSection>(TableBase);
+ Out.DataCountSec = make<DataCountSection>(Segments.size());
+ Out.LinkingSec = make<LinkingSection>(InitFunctions, Segments);
+ Out.NameSec = make<NameSection>();
+ Out.ProducersSec = make<ProducersSection>();
+ Out.TargetFeaturesSec = make<TargetFeaturesSection>();
+}
+
void Writer::run() {
if (Config->Relocatable || Config->Pic)
Config->GlobalBase = 0;
@@ -1417,8 +714,14 @@
if (!Config->Pic)
TableBase = 1;
- log("-- calculateTargetFeatures");
- calculateTargetFeatures();
+ log("-- createOutputSegments");
+ createOutputSegments();
+ log("-- createSyntheticSections");
+ createSyntheticSections();
+ log("-- populateProducers");
+ populateProducers();
+ log("-- populateTargetFeatures");
+ populateTargetFeatures();
log("-- calculateImports");
calculateImports();
log("-- assignIndexes");
@@ -1438,23 +741,25 @@
calculateExports();
log("-- calculateCustomSections");
calculateCustomSections();
- log("-- assignSymtab");
- assignSymtab();
+ log("-- populateSymtab");
+ populateSymtab();
+ log("-- addSections");
+ addSections();
if (errorHandler().Verbose) {
- log("Defined Functions: " + Twine(InputFunctions.size()));
- log("Defined Globals : " + Twine(InputGlobals.size()));
- log("Defined Events : " + Twine(InputEvents.size()));
- log("Function Imports : " + Twine(NumImportedFunctions));
- log("Global Imports : " + Twine(NumImportedGlobals));
- log("Event Imports : " + Twine(NumImportedEvents));
+ log("Defined Functions: " + Twine(Out.FunctionSec->InputFunctions.size()));
+ log("Defined Globals : " + Twine(Out.GlobalSec->InputGlobals.size()));
+ log("Defined Events : " + Twine(Out.EventSec->InputEvents.size()));
+ log("Function Imports : " + Twine(Out.ImportSec->NumImportedFunctions));
+ log("Global Imports : " + Twine(Out.ImportSec->NumImportedGlobals));
+ log("Event Imports : " + Twine(Out.ImportSec->NumImportedEvents));
for (ObjFile *File : Symtab->ObjectFiles)
File->dumpInfo();
}
createHeader();
- log("-- createSections");
- createSections();
+ log("-- finalizeSections");
+ finalizeSections();
log("-- openFile");
openFile();