forked from OSchip/llvm-project
[WebAssembly] Refactor synthetic sections and relocation processing. NFC.
Major refactor to better match the structure of the ELF linker. - Split out relocation processing into scanRelocations - Split out synthetic sections into their own classes. Differential Revision: https://reviews.llvm.org/D61811 llvm-svn: 361233
This commit is contained in:
parent
f33f181678
commit
8fcf012693
|
@ -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}
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -75,7 +75,10 @@ uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
|
|||
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 WasmSymbol &Sym) {
|
|||
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 =
|
||||
|
|
|
@ -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_ostream &OS) const {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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() const {
|
|||
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 Name, uint32_t Flags, InputFile *File,
|
|||
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::Kind Kind) {
|
|||
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 *Sym) {
|
|||
|
||||
message(toString(Sym->getFile()) + S + Sym->getName());
|
||||
}
|
||||
|
||||
const char *lld::wasm::DefaultModule = "env";
|
||||
const char *lld::wasm::FunctionTableName = "__indirect_function_table";
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -14,8 +14,6 @@ namespace wasm {
|
|||
|
||||
void writeResult();
|
||||
|
||||
extern const char *DefaultModule;
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace lld
|
||||
|
||||
|
|
Loading…
Reference in New Issue