[lld] r361233 - [WebAssembly] Refactor synthetic sections and relocation processing. NFC.

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Tue May 21 02:13:10 PDT 2019


Author: sbc
Date: Tue May 21 02:13:09 2019
New Revision: 361233

URL: http://llvm.org/viewvc/llvm-project?rev=361233&view=rev
Log:
[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

Added:
    lld/trunk/wasm/Relocations.cpp   (with props)
    lld/trunk/wasm/Relocations.h   (with props)
    lld/trunk/wasm/SyntheticSections.cpp   (with props)
    lld/trunk/wasm/SyntheticSections.h   (with props)
Modified:
    lld/trunk/wasm/CMakeLists.txt
    lld/trunk/wasm/InputChunks.h
    lld/trunk/wasm/InputFiles.cpp
    lld/trunk/wasm/OutputSections.cpp
    lld/trunk/wasm/OutputSections.h
    lld/trunk/wasm/Symbols.cpp
    lld/trunk/wasm/Symbols.h
    lld/trunk/wasm/Writer.cpp
    lld/trunk/wasm/Writer.h

Modified: lld/trunk/wasm/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/CMakeLists.txt?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/CMakeLists.txt (original)
+++ lld/trunk/wasm/CMakeLists.txt Tue May 21 02:13:09 2019
@@ -13,8 +13,10 @@ add_lld_library(lldWasm
   LTO.cpp
   MarkLive.cpp
   OutputSections.cpp
+  Relocations.cpp
   SymbolTable.cpp
   Symbols.cpp
+  SyntheticSections.cpp
   Writer.cpp
   WriterUtils.cpp
 
@@ -35,4 +37,4 @@ add_lld_library(lldWasm
   DEPENDS
   WasmOptionsTableGen
   ${tablegen_deps}
-  )
\ No newline at end of file
+  )

Modified: lld/trunk/wasm/InputChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputChunks.h?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/InputChunks.h (original)
+++ lld/trunk/wasm/InputChunks.h Tue May 21 02:13:09 2019
@@ -31,6 +31,7 @@ namespace wasm {
 
 class ObjFile;
 class OutputSegment;
+class OutputSection;
 
 class InputChunk {
 public:
@@ -207,6 +208,8 @@ public:
   StringRef getDebugName() const override { return StringRef(); }
   uint32_t getComdat() const override { return UINT32_MAX; }
 
+  OutputSection *OutputSec = nullptr;
+
 protected:
   ArrayRef<uint8_t> data() const override { return Section.Content; }
 

Modified: lld/trunk/wasm/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.cpp?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/InputFiles.cpp (original)
+++ lld/trunk/wasm/InputFiles.cpp Tue May 21 02:13:09 2019
@@ -75,7 +75,10 @@ uint32_t ObjFile::calcNewIndex(const Was
     assert(TypeIsUsed[Reloc.Index]);
     return TypeMap[Reloc.Index];
   }
-  return Symbols[Reloc.Index]->getOutputSymbolIndex();
+  const Symbol *Sym = Symbols[Reloc.Index];
+  if (auto *SS = dyn_cast<SectionSymbol>(Sym))
+    Sym = SS->getOutputSectionSymbol();
+  return Sym->getOutputSymbolIndex();
 }
 
 // Relocations can contain addend for combined sections. This function takes a
@@ -395,7 +398,7 @@ Symbol *ObjFile::createDefined(const Was
   case WASM_SYMBOL_TYPE_SECTION: {
     InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex];
     assert(Sym.isBindingLocal());
-    return make<SectionSymbol>(Name, Flags, Section, this);
+    return make<SectionSymbol>(Flags, Section, this);
   }
   case WASM_SYMBOL_TYPE_EVENT: {
     InputEvent *Event =

Modified: lld/trunk/wasm/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSections.cpp?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/OutputSections.cpp (original)
+++ lld/trunk/wasm/OutputSections.cpp Tue May 21 02:13:09 2019
@@ -206,6 +206,7 @@ void CustomSection::finalizeContents() {
 
   for (InputSection *Section : InputSections) {
     Section->OutputOffset = PayloadSize;
+    Section->OutputSec = this;
     PayloadSize += Section->getSize();
   }
 
@@ -241,9 +242,3 @@ void CustomSection::writeRelocations(raw
   for (const InputSection *S : InputSections)
     S->writeRelocations(OS);
 }
-
-void RelocSection::writeBody() {
-  writeUleb128(BodyOutputStream, SectionIndex, "reloc section");
-  writeUleb128(BodyOutputStream, Sec->numRelocations(), "reloc count");
-  Sec->writeRelocations(BodyOutputStream);
-}

Modified: lld/trunk/wasm/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSections.h?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/OutputSections.h (original)
+++ lld/trunk/wasm/OutputSections.h Tue May 21 02:13:09 2019
@@ -38,6 +38,7 @@ public:
     Offset = NewOffset;
   }
   void createHeader(size_t BodySize);
+  virtual bool isNeeded() const { return true; }
   virtual size_t getSize() const = 0;
   virtual void writeTo(uint8_t *Buf) = 0;
   virtual void finalizeContents() = 0;
@@ -46,54 +47,24 @@ public:
 
   std::string Header;
   uint32_t Type;
+  uint32_t SectionIndex = UINT32_MAX;
   std::string Name;
+  OutputSectionSymbol *SectionSym = nullptr;
 
 protected:
   size_t Offset = 0;
 };
 
-class SyntheticSection : public OutputSection {
-public:
-  SyntheticSection(uint32_t Type, std::string Name = "")
-      : OutputSection(Type, Name), BodyOutputStream(Body) {
-    if (!Name.empty())
-      writeStr(BodyOutputStream, Name, "section name");
-  }
-
-  void writeTo(uint8_t *Buf) override {
-    assert(Offset);
-    log("writing " + toString(*this));
-    memcpy(Buf + Offset, Header.data(), Header.size());
-    memcpy(Buf + Offset + Header.size(), Body.data(), Body.size());
-  }
-
-  size_t getSize() const override { return Header.size() + Body.size(); }
-
-  virtual void writeBody() {}
-
-  void finalizeContents() override {
-    writeBody();
-    BodyOutputStream.flush();
-    createHeader(Body.size());
-  }
-
-  raw_ostream &getStream() { return BodyOutputStream; }
-
-  std::string Body;
-
-protected:
-  llvm::raw_string_ostream BodyOutputStream;
-};
-
 class CodeSection : public OutputSection {
 public:
   explicit CodeSection(ArrayRef<InputFunction *> Functions)
       : OutputSection(llvm::wasm::WASM_SEC_CODE), Functions(Functions) {}
 
-  size_t getSize() const override { assert(BodySize); return Header.size() + BodySize; }
+  size_t getSize() const override { return Header.size() + BodySize; }
   void writeTo(uint8_t *Buf) override;
   uint32_t numRelocations() const override;
   void writeRelocations(raw_ostream &OS) const override;
+  bool isNeeded() const override { return Functions.size() > 0; }
   void finalizeContents() override;
 
 protected:
@@ -111,6 +82,7 @@ public:
   void writeTo(uint8_t *Buf) override;
   uint32_t numRelocations() const override;
   void writeRelocations(raw_ostream &OS) const override;
+  bool isNeeded() const override { return Segments.size() > 0; }
   void finalizeContents() override;
 
 protected:
@@ -145,19 +117,6 @@ protected:
   std::string NameData;
 };
 
-class RelocSection : public SyntheticSection {
-public:
-  RelocSection(StringRef Name, OutputSection *Sec, uint32_t SectionIndex)
-      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, Name), Sec(Sec),
-        SectionIndex(SectionIndex) {}
-  void writeBody() override;
-
-protected:
-  OutputSection* Sec;
-  uint32_t SectionIndex;
-};
-
-
 } // namespace wasm
 } // namespace lld
 

Added: lld/trunk/wasm/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Relocations.cpp?rev=361233&view=auto
==============================================================================
--- lld/trunk/wasm/Relocations.cpp (added)
+++ lld/trunk/wasm/Relocations.cpp Tue May 21 02:13:09 2019
@@ -0,0 +1,86 @@
+//===- Relocations.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Relocations.h"
+
+#include "InputChunks.h"
+#include "SyntheticSections.h"
+
+using namespace llvm;
+using namespace llvm::wasm;
+
+using namespace lld;
+using namespace lld::wasm;
+
+static bool requiresGOTAccess(const Symbol *Sym) {
+  return Config->Pic && !Sym->isHidden() && !Sym->isLocal();
+}
+
+void lld::wasm::scanRelocations(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] =
+          Out.TypeSec->registerType(Types[Reloc.Index]);
+      File->TypeIsUsed[Reloc.Index] = true;
+      continue;
+    }
+
+    // Other relocation types all have a corresponding symbol
+    Symbol *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:
+      if (requiresGOTAccess(Sym))
+        break;
+      Out.ElemSec->addEntry(cast<FunctionSymbol>(Sym));
+      break;
+    case R_WASM_GLOBAL_INDEX_LEB:
+      if (!isa<GlobalSymbol>(Sym))
+        Out.ImportSec->addGOTEntry(Sym);
+      break;
+    case R_WASM_MEMORY_ADDR_SLEB:
+    case R_WASM_MEMORY_ADDR_LEB:
+    case R_WASM_MEMORY_ADDR_REL_SLEB:
+      if (!Config->Relocatable && 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))
+          Out.ImportSec->addGOTEntry(Sym);
+        break;
+      }
+    }
+  }
+}

Propchange: lld/trunk/wasm/Relocations.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Relocations.h?rev=361233&view=auto
==============================================================================
--- lld/trunk/wasm/Relocations.h (added)
+++ lld/trunk/wasm/Relocations.h Tue May 21 02:13:09 2019
@@ -0,0 +1,22 @@
+//===- Relocations.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_RELOCATIONS_H
+#define LLD_WASM_RELOCATIONS_H
+
+namespace lld {
+namespace wasm {
+
+class InputChunk;
+
+void scanRelocations(InputChunk *Chunk);
+
+} // namespace wasm
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/Relocations.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Modified: lld/trunk/wasm/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.cpp?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.cpp (original)
+++ lld/trunk/wasm/Symbols.cpp Tue May 21 02:13:09 2019
@@ -12,6 +12,7 @@
 #include "InputEvent.h"
 #include "InputFiles.h"
 #include "InputGlobal.h"
+#include "OutputSections.h"
 #include "OutputSegment.h"
 #include "lld/Common/ErrorHandler.h"
 #include "lld/Common/Strings.h"
@@ -41,7 +42,7 @@ WasmSymbolType Symbol::getWasmType() con
     return WASM_SYMBOL_TYPE_GLOBAL;
   if (isa<EventSymbol>(this))
     return WASM_SYMBOL_TYPE_EVENT;
-  if (isa<SectionSymbol>(this))
+  if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))
     return WASM_SYMBOL_TYPE_SECTION;
   llvm_unreachable("invalid symbol kind");
 }
@@ -262,17 +263,9 @@ DefinedEvent::DefinedEvent(StringRef Nam
                   Event ? &Event->Signature : nullptr),
       Event(Event) {}
 
-uint32_t SectionSymbol::getOutputSectionIndex() const {
-  LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
-  assert(OutputSectionIndex != INVALID_INDEX);
-  return OutputSectionIndex;
-}
-
-void SectionSymbol::setOutputSectionIndex(uint32_t Index) {
-  LLVM_DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index
-                    << "\n");
-  assert(Index != INVALID_INDEX);
-  OutputSectionIndex = Index;
+const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
+  assert(Section->OutputSec && Section->OutputSec->SectionSym);
+  return Section->OutputSec->SectionSym;
 }
 
 void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
@@ -308,6 +301,8 @@ std::string lld::toString(wasm::Symbol::
     return "LazyKind";
   case wasm::Symbol::SectionKind:
     return "SectionKind";
+  case wasm::Symbol::OutputSectionKind:
+    return "OutputSectionKind";
   }
   llvm_unreachable("invalid symbol kind");
 }
@@ -324,3 +319,6 @@ void lld::wasm::printTraceSymbol(Symbol
 
   message(toString(Sym->getFile()) + S + Sym->getName());
 }
+
+const char *lld::wasm::DefaultModule = "env";
+const char *lld::wasm::FunctionTableName = "__indirect_function_table";

Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Tue May 21 02:13:09 2019
@@ -17,6 +17,14 @@
 namespace lld {
 namespace wasm {
 
+// Shared string constants
+
+// The default module name to use for symbol imports.
+extern const char *DefaultModule;
+
+// The name under which to import or export the wasm table.
+extern const char *FunctionTableName;
+
 using llvm::wasm::WasmSymbolType;
 
 class InputFile;
@@ -26,6 +34,7 @@ class InputFunction;
 class InputGlobal;
 class InputEvent;
 class InputSection;
+class OutputSection;
 
 #define INVALID_INDEX UINT32_MAX
 
@@ -38,6 +47,7 @@ public:
     DefinedGlobalKind,
     DefinedEventKind,
     SectionKind,
+    OutputSectionKind,
     UndefinedFunctionKind,
     UndefinedDataKind,
     UndefinedGlobalKind,
@@ -46,11 +56,7 @@ public:
 
   Kind kind() const { return SymbolKind; }
 
-  bool isDefined() const {
-    return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
-           SymbolKind == DefinedGlobalKind || SymbolKind == DefinedEventKind ||
-           SymbolKind == SectionKind;
-  }
+  bool isDefined() const { return !isLazy() && !isUndefined(); }
 
   bool isUndefined() const {
     return SymbolKind == UndefinedFunctionKind ||
@@ -195,21 +201,33 @@ public:
   StringRef ImportModule;
 };
 
+// Section symbols for output sections are different from those for input
+// section.  These are generated by the linker and point the OutputSection
+// rather than an InputSection.
+class OutputSectionSymbol : public Symbol {
+public:
+  OutputSectionSymbol(const OutputSection *S)
+      : Symbol("", OutputSectionKind, llvm::wasm::WASM_SYMBOL_BINDING_LOCAL,
+               nullptr),
+        Section(S) {}
+
+  static bool classof(const Symbol *S) {
+    return S->kind() == OutputSectionKind;
+  }
+
+  const OutputSection *Section;
+};
+
 class SectionSymbol : public Symbol {
 public:
+  SectionSymbol(uint32_t Flags, const InputSection *S, InputFile *F = nullptr)
+      : Symbol("", SectionKind, Flags, F), Section(S) {}
+
   static bool classof(const Symbol *S) { return S->kind() == SectionKind; }
 
-  SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S,
-                InputFile *F = nullptr)
-      : Symbol(Name, SectionKind, Flags, F), Section(S) {}
+  const OutputSectionSymbol *getOutputSectionSymbol() const;
 
   const InputSection *Section;
-
-  uint32_t getOutputSectionIndex() const;
-  void setOutputSectionIndex(uint32_t Index);
-
-protected:
-  uint32_t OutputSectionIndex = INVALID_INDEX;
 };
 
 class DataSymbol : public Symbol {

Added: lld/trunk/wasm/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SyntheticSections.cpp?rev=361233&view=auto
==============================================================================
--- lld/trunk/wasm/SyntheticSections.cpp (added)
+++ lld/trunk/wasm/SyntheticSections.cpp Tue May 21 02:13:09 2019
@@ -0,0 +1,543 @@
+//===- SyntheticSections.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains linker-synthesized sections.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntheticSections.h"
+
+#include "InputChunks.h"
+#include "InputEvent.h"
+#include "InputGlobal.h"
+#include "OutputSegment.h"
+#include "SymbolTable.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::wasm;
+
+using namespace lld;
+using namespace lld::wasm;
+
+OutStruct lld::wasm::Out;
+
+namespace {
+
+// 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};
+};
+
+} // namespace
+
+void DylinkSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  writeUleb128(OS, MemSize, "MemSize");
+  writeUleb128(OS, MemAlign, "MemAlign");
+  writeUleb128(OS, Out.ElemSec->numEntries(), "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");
+}
+
+uint32_t TypeSection::registerType(const WasmSignature &Sig) {
+  auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
+  if (Pair.second) {
+    LLVM_DEBUG(llvm::dbgs() << "type " << toString(Sig) << "\n");
+    Types.push_back(&Sig);
+  }
+  return Pair.first->second;
+}
+
+uint32_t TypeSection::lookupType(const WasmSignature &Sig) {
+  auto It = TypeIndices.find(Sig);
+  if (It == TypeIndices.end()) {
+    error("type not found: " + toString(Sig));
+    return 0;
+  }
+  return It->second;
+}
+
+void TypeSection::writeBody() {
+  writeUleb128(BodyOutputStream, Types.size(), "type count");
+  for (const WasmSignature *Sig : Types)
+    writeSig(BodyOutputStream, *Sig);
+}
+
+uint32_t ImportSection::numImports() const {
+  uint32_t NumImports = ImportedSymbols.size() + GOTSymbols.size();
+  if (Config->ImportMemory)
+    ++NumImports;
+  if (Config->ImportTable)
+    ++NumImports;
+  return NumImports;
+}
+
+void ImportSection::addGOTEntry(Symbol *Sym) {
+  if (Sym->hasGOTIndex())
+    return;
+  Sym->setGOTIndex(NumImportedGlobals++);
+  GOTSymbols.push_back(Sym);
+}
+
+void ImportSection::addImport(Symbol *Sym) {
+  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++);
+}
+
+void ImportSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  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 = Out.MemorySec->NumMemoryPages;
+    if (Out.MemorySec->MaxMemoryPages != 0 || Config->SharedMemory) {
+      Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
+      Import.Memory.Maximum = Out.MemorySec->MaxMemoryPages;
+    }
+    if (Config->SharedMemory)
+      Import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
+    writeImport(OS, Import);
+  }
+
+  if (Config->ImportTable) {
+    uint32_t TableSize = Out.ElemSec->ElemOffset + Out.ElemSec->numEntries();
+    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 = Out.TypeSec->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 = Out.TypeSec->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 FunctionSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  writeUleb128(OS, InputFunctions.size(), "function count");
+  for (const InputFunction *Func : InputFunctions)
+    writeUleb128(OS, Out.TypeSec->lookupType(Func->Signature), "sig index");
+}
+
+void FunctionSection::addFunction(InputFunction *Func) {
+  if (!Func->Live)
+    return;
+  uint32_t FunctionIndex =
+      Out.ImportSec->NumImportedFunctions + InputFunctions.size();
+  InputFunctions.emplace_back(Func);
+  Func->setFunctionIndex(FunctionIndex);
+}
+
+void TableSection::writeBody() {
+  uint32_t TableSize = Out.ElemSec->ElemOffset + Out.ElemSec->numEntries();
+
+  raw_ostream &OS = BodyOutputStream;
+  writeUleb128(OS, 1, "table count");
+  WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
+  writeTableType(OS, WasmTable{WASM_TYPE_FUNCREF, Limits});
+}
+
+void MemorySection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  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 GlobalSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  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);
+  }
+}
+
+void GlobalSection::addGlobal(InputGlobal *Global) {
+  if (!Global->Live)
+    return;
+  uint32_t GlobalIndex =
+      Out.ImportSec->NumImportedGlobals + InputGlobals.size();
+  LLVM_DEBUG(dbgs() << "addGlobal: " << GlobalIndex << "\n");
+  Global->setGlobalIndex(GlobalIndex);
+  Out.GlobalSec->InputGlobals.push_back(Global);
+}
+
+void EventSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  writeUleb128(OS, InputEvents.size(), "event count");
+  for (InputEvent *E : InputEvents) {
+    E->Event.Type.SigIndex = Out.TypeSec->lookupType(E->Signature);
+    writeEvent(OS, E->Event);
+  }
+}
+
+void EventSection::addEvent(InputEvent *Event) {
+  if (!Event->Live)
+    return;
+  uint32_t EventIndex = Out.ImportSec->NumImportedEvents + InputEvents.size();
+  LLVM_DEBUG(dbgs() << "addEvent: " << EventIndex << "\n");
+  Event->setEventIndex(EventIndex);
+  InputEvents.push_back(Event);
+}
+
+void ExportSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  writeUleb128(OS, Exports.size(), "export count");
+  for (const WasmExport &Export : Exports)
+    writeExport(OS, Export);
+}
+
+void ElemSection::addEntry(FunctionSymbol *Sym) {
+  if (Sym->hasTableIndex())
+    return;
+  Sym->setTableIndex(ElemOffset + IndirectFunctions.size());
+  IndirectFunctions.emplace_back(Sym);
+}
+
+void ElemSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  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 = ElemOffset;
+  }
+  writeInitExpr(OS, InitExpr);
+  writeUleb128(OS, IndirectFunctions.size(), "elem count");
+
+  uint32_t TableIndex = ElemOffset;
+  for (const FunctionSymbol *Sym : IndirectFunctions) {
+    assert(Sym->getTableIndex() == TableIndex);
+    writeUleb128(OS, Sym->getFunctionIndex(), "function index");
+    ++TableIndex;
+  }
+}
+
+void DataCountSection::writeBody() {
+  writeUleb128(BodyOutputStream, NumSegments, "data count");
+}
+
+bool DataCountSection::isNeeded() const {
+  return NumSegments && Out.TargetFeaturesSec->Features.count("bulk-memory");
+}
+
+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;
+}
+
+void LinkingSection::writeBody() {
+  raw_ostream &OS = BodyOutputStream;
+
+  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<OutputSectionSymbol>(Sym);
+        writeUleb128(Sub.OS, S->Section->SectionIndex, "sym section index");
+      }
+    }
+
+    Sub.writeTo(OS);
+  }
+
+  if (DataSegments.size()) {
+    SubSection Sub(WASM_SEGMENT_INFO);
+    writeUleb128(Sub.OS, DataSegments.size(), "num data segments");
+    for (const OutputSegment *S : DataSegments) {
+      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 : Out.FunctionSec->InputFunctions) {
+    StringRef Comdat = F->getComdatName();
+    if (!Comdat.empty())
+      Comdats[Comdat].emplace_back(
+          ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()});
+  }
+  for (uint32_t I = 0; I < DataSegments.size(); ++I) {
+    const auto &InputSegments = DataSegments[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);
+  }
+}
+
+void LinkingSection::addToSymtab(Symbol *Sym) {
+  Sym->setOutputSymbolIndex(SymtabEntries.size());
+  SymtabEntries.emplace_back(Sym);
+}
+
+unsigned NameSection::numNames() const {
+  unsigned NumNames = Out.ImportSec->NumImportedFunctions;
+  for (const InputFunction *F : Out.FunctionSec->InputFunctions)
+    if (!F->getName().empty() || !F->getDebugName().empty())
+      ++NumNames;
+
+  return NumNames;
+}
+
+// Create the custom "name" section containing debug symbol names.
+void NameSection::writeBody() {
+  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 : Out.ImportSec->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 : Out.FunctionSec->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(BodyOutputStream);
+}
+
+void ProducersSection::addInfo(const WasmProducerInfo &Info) {
+  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);
+}
+
+void ProducersSection::writeBody() {
+  auto &OS = BodyOutputStream;
+  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 TargetFeaturesSection::writeBody() {
+  SmallVector<std::string, 8> Emitted(Features.begin(), Features.end());
+  llvm::sort(Emitted);
+  auto &OS = BodyOutputStream;
+  writeUleb128(OS, Emitted.size(), "feature count");
+  for (auto &Feature : Emitted) {
+    writeU8(OS, WASM_FEATURE_PREFIX_USED, "feature used prefix");
+    writeStr(OS, Feature, "feature name");
+  }
+}
+
+void RelocSection::writeBody() {
+  uint32_t Count = Sec->numRelocations();
+  assert(Sec->SectionIndex != UINT32_MAX);
+  writeUleb128(BodyOutputStream, Sec->SectionIndex, "reloc section");
+  writeUleb128(BodyOutputStream, Count, "reloc count");
+  Sec->writeRelocations(BodyOutputStream);
+}

Propchange: lld/trunk/wasm/SyntheticSections.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SyntheticSections.h?rev=361233&view=auto
==============================================================================
--- lld/trunk/wasm/SyntheticSections.h (added)
+++ lld/trunk/wasm/SyntheticSections.h Tue May 21 02:13:09 2019
@@ -0,0 +1,323 @@
+//===- SyntheticSection.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Synthetic sections represent chunks of linker-created data. If you
+// need to create a chunk of data that to be included in some section
+// in the result, you probably want to create that as a synthetic section.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_SYNTHETIC_SECTIONS_H
+#define LLD_WASM_SYNTHETIC_SECTIONS_H
+
+#include "OutputSections.h"
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Object/WasmTraits.h"
+
+#define DEBUG_TYPE "lld"
+
+namespace lld {
+namespace wasm {
+
+// An init entry to be written to either the synthetic init func or the
+// linking metadata.
+struct WasmInitEntry {
+  const FunctionSymbol *Sym;
+  uint32_t Priority;
+};
+
+class SyntheticSection : public OutputSection {
+public:
+  SyntheticSection(uint32_t Type, std::string Name = "")
+      : OutputSection(Type, Name), BodyOutputStream(Body) {
+    if (!Name.empty())
+      writeStr(BodyOutputStream, Name, "section name");
+  }
+
+  void writeTo(uint8_t *Buf) override {
+    assert(Offset);
+    log("writing " + toString(*this));
+    memcpy(Buf + Offset, Header.data(), Header.size());
+    memcpy(Buf + Offset + Header.size(), Body.data(), Body.size());
+  }
+
+  size_t getSize() const override { return Header.size() + Body.size(); }
+
+  virtual void writeBody() {}
+
+  void finalizeContents() override {
+    writeBody();
+    BodyOutputStream.flush();
+    createHeader(Body.size());
+  }
+
+  raw_ostream &getStream() { return BodyOutputStream; }
+
+  std::string Body;
+
+protected:
+  llvm::raw_string_ostream BodyOutputStream;
+};
+
+// Create the custom "dylink" section containing information for the dynamic
+// linker.
+// See
+// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
+class DylinkSection : public SyntheticSection {
+public:
+  DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink") {}
+  bool isNeeded() const override { return Config->Pic; }
+  void writeBody() override;
+
+  uint32_t MemAlign = 0;
+  uint32_t MemSize = 0;
+};
+
+class TypeSection : public SyntheticSection {
+public:
+  TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {}
+
+  bool isNeeded() const override { return Types.size() > 0; };
+  void writeBody() override;
+  uint32_t registerType(const WasmSignature &Sig);
+  uint32_t lookupType(const WasmSignature &Sig);
+
+protected:
+  std::vector<const WasmSignature *> Types;
+  llvm::DenseMap<WasmSignature, int32_t> TypeIndices;
+};
+
+class ImportSection : public SyntheticSection {
+public:
+  ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {}
+  bool isNeeded() const override { return numImports() > 0; }
+  void writeBody() override;
+  void addImport(Symbol *Sym);
+  void addGOTEntry(Symbol *Sym);
+  uint32_t numImports() const;
+
+  unsigned NumImportedGlobals = 0;
+  unsigned NumImportedFunctions = 0;
+  unsigned NumImportedEvents = 0;
+  std::vector<const Symbol *> ImportedSymbols;
+
+protected:
+  std::vector<const Symbol *> GOTSymbols;
+};
+
+class FunctionSection : public SyntheticSection {
+public:
+  FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {}
+
+  bool isNeeded() const override { return InputFunctions.size() > 0; };
+  void writeBody() override;
+  void addFunction(InputFunction *Func);
+
+  std::vector<InputFunction *> InputFunctions;
+
+protected:
+};
+
+class MemorySection : public SyntheticSection {
+public:
+  MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}
+
+  bool isNeeded() const override { return !Config->ImportMemory; }
+  void writeBody() override;
+
+  uint32_t NumMemoryPages = 0;
+  uint32_t MaxMemoryPages = 0;
+};
+
+class TableSection : public SyntheticSection {
+public:
+  TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {}
+
+  bool isNeeded() const override {
+    // 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.
+    return !Config->ImportTable;
+  }
+
+  void writeBody() override;
+};
+
+class GlobalSection : public SyntheticSection {
+public:
+  GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {}
+  uint32_t numGlobals() const {
+    return InputGlobals.size() + DefinedFakeGlobals.size();
+  }
+  bool isNeeded() const override { return numGlobals() > 0; }
+  void writeBody() override;
+  void addGlobal(InputGlobal *Global);
+
+  std::vector<const DefinedData *> DefinedFakeGlobals;
+  std::vector<InputGlobal *> InputGlobals;
+};
+
+// 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.)
+class EventSection : public SyntheticSection {
+public:
+  EventSection() : SyntheticSection(llvm::wasm::WASM_SEC_EVENT) {}
+  void writeBody() override;
+  bool isNeeded() const override { return InputEvents.size() > 0; }
+  void addEvent(InputEvent *Event);
+
+  std::vector<InputEvent *> InputEvents;
+};
+
+class ExportSection : public SyntheticSection {
+public:
+  ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {}
+  bool isNeeded() const override { return Exports.size() > 0; }
+  void writeBody() override;
+
+  std::vector<llvm::wasm::WasmExport> Exports;
+};
+
+class ElemSection : public SyntheticSection {
+public:
+  ElemSection(uint32_t Offset)
+      : SyntheticSection(llvm::wasm::WASM_SEC_ELEM), ElemOffset(Offset) {}
+  bool isNeeded() const override { return IndirectFunctions.size() > 0; };
+  void writeBody() override;
+  void addEntry(FunctionSymbol *Sym);
+  uint32_t numEntries() const { return IndirectFunctions.size(); }
+  uint32_t ElemOffset;
+
+protected:
+  std::vector<const FunctionSymbol *> IndirectFunctions;
+};
+
+class DataCountSection : public SyntheticSection {
+public:
+  DataCountSection(uint32_t NumSegments)
+      : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT),
+        NumSegments(NumSegments) {}
+  bool isNeeded() const override;
+  void writeBody() override;
+
+protected:
+  uint32_t NumSegments;
+};
+
+// Create the custom "linking" section containing linker metadata.
+// This is only created when relocatable output is requested.
+class LinkingSection : public SyntheticSection {
+public:
+  LinkingSection(const std::vector<WasmInitEntry> &InitFunctions,
+                 const std::vector<OutputSegment *> &DataSegments)
+      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"),
+        InitFunctions(InitFunctions), DataSegments(DataSegments) {}
+  bool isNeeded() const override { return Config->Relocatable; }
+  void writeBody() override;
+  void addToSymtab(Symbol *Sym);
+
+protected:
+  std::vector<const Symbol *> SymtabEntries;
+  llvm::StringMap<uint32_t> SectionSymbolIndices;
+  const std::vector<WasmInitEntry> &InitFunctions;
+  const std::vector<OutputSegment *> &DataSegments;
+};
+
+// Create the custom "name" section containing debug symbol names.
+class NameSection : public SyntheticSection {
+public:
+  NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {}
+  bool isNeeded() const override {
+    return !Config->StripDebug && !Config->StripAll && numNames() > 0;
+  }
+  void writeBody() override;
+  unsigned numNames() const;
+};
+
+class ProducersSection : public SyntheticSection {
+public:
+  ProducersSection()
+      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}
+  bool isNeeded() const override {
+    return !Config->StripAll && fieldCount() > 0;
+  }
+  void writeBody() override;
+  void addInfo(const llvm::wasm::WasmProducerInfo &Info);
+
+protected:
+  int fieldCount() const {
+    return int(!Languages.empty()) + int(!Tools.empty()) + int(!SDKs.empty());
+  }
+  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;
+};
+
+class TargetFeaturesSection : public SyntheticSection {
+public:
+  TargetFeaturesSection()
+      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}
+  bool isNeeded() const override {
+    return !Config->StripAll && Features.size() > 0;
+  }
+  void writeBody() override;
+
+  llvm::SmallSet<std::string, 8> Features;
+};
+
+class RelocSection : public SyntheticSection {
+public:
+  RelocSection(StringRef Name, OutputSection *Sec)
+      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, Name), Sec(Sec) {}
+  void writeBody() override;
+  bool isNeeded() const override { return Sec->numRelocations() > 0; };
+
+protected:
+  OutputSection *Sec;
+};
+
+// Linker generated output sections
+struct OutStruct {
+  DylinkSection *DylinkSec;
+  TypeSection *TypeSec;
+  FunctionSection *FunctionSec;
+  ImportSection *ImportSec;
+  TableSection *TableSec;
+  MemorySection *MemorySec;
+  GlobalSection *GlobalSec;
+  EventSection *EventSec;
+  ExportSection *ExportSec;
+  ElemSection *ElemSec;
+  DataCountSection *DataCountSec;
+  LinkingSection *LinkingSec;
+  NameSection *NameSec;
+  ProducersSection *ProducersSec;
+  TargetFeaturesSection *TargetFeaturesSec;
+};
+
+extern OutStruct Out;
+
+} // namespace wasm
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/SyntheticSections.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Tue May 21 02:13:09 2019
@@ -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;
 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 @@ public:
 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;
 
+  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 @@ private:
 
 } // 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 @@ void Writer::createCustomSections() {
   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));
-  }
-}
 
-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;
+    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::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 @@ void Writer::createRelocSections() {
   // 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));
-  }
-}
-
-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);
+    addSection(make<RelocSection>(Name, Sec));
   }
-
-  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::writeHeader() {
 
 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 @@ void Writer::writeSections() {
 // 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 @@ void Writer::layoutMemory() {
   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 @@ void Writer::layoutMemory() {
   log("mem: static data = " + Twine(MemoryPtr - DataStart));
 
   if (Config->Shared) {
-    MemSize = MemoryPtr;
+    Out.DylinkSec->MemSize = MemoryPtr;
     return;
   }
 
@@ -838,9 +269,10 @@ void Writer::layoutMemory() {
     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 @@ void Writer::layoutMemory() {
       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();
-
-  if (!Config->StripAll) {
-    createProducersSection();
-    createTargetFeaturesSection();
-  }
+  addSection(Out.NameSec);
+  addSection(Out.ProducersSec);
+  addSection(Out.TargetFeaturesSec);
+}
 
+void Writer::finalizeSections() {
   for (OutputSection *S : OutputSections) {
     S->setOffset(FileSize);
     S->finalizeContents();
@@ -900,7 +329,7 @@ void Writer::createSections() {
   }
 }
 
-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 @@ void Writer::calculateTargetFeatures() {
 
   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 @@ void Writer::calculateTargetFeatures() {
   }
 
   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 @@ void Writer::calculateTargetFeatures() {
   // 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 @@ void Writer::calculateImports() {
       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 @@ void Writer::calculateExports() {
     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 @@ void Writer::calculateExports() {
       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 @@ void Writer::calculateTypes() {
     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);
-  }
-
-  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);
+      Out.FunctionSec->addFunction(Func);
   }
 
-  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::calculateInitFunctions() {
                     });
 }
 
+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 @@ void Writer::run() {
   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 @@ void Writer::run() {
   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();

Modified: lld/trunk/wasm/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.h?rev=361233&r1=361232&r2=361233&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.h (original)
+++ lld/trunk/wasm/Writer.h Tue May 21 02:13:09 2019
@@ -14,8 +14,6 @@ namespace wasm {
 
 void writeResult();
 
-extern const char *DefaultModule;
-
 } // namespace wasm
 } // namespace lld
 




More information about the llvm-commits mailing list