2017-11-18 02:14:09 +08:00
|
|
|
//===- Writer.cpp ---------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Writer.h"
|
|
|
|
#include "Config.h"
|
2018-01-10 09:13:34 +08:00
|
|
|
#include "InputChunks.h"
|
2018-02-23 13:08:53 +08:00
|
|
|
#include "InputGlobal.h"
|
2017-11-18 02:14:09 +08:00
|
|
|
#include "OutputSections.h"
|
|
|
|
#include "OutputSegment.h"
|
|
|
|
#include "SymbolTable.h"
|
|
|
|
#include "WriterUtils.h"
|
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2017-11-29 04:39:17 +08:00
|
|
|
#include "lld/Common/Memory.h"
|
2018-03-07 18:37:50 +08:00
|
|
|
#include "lld/Common/Strings.h"
|
2017-11-18 02:14:09 +08:00
|
|
|
#include "lld/Common/Threads.h"
|
2018-02-21 05:53:18 +08:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2018-04-11 00:12:49 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2018-02-23 13:08:53 +08:00
|
|
|
#include "llvm/BinaryFormat/Wasm.h"
|
2018-03-14 23:58:16 +08:00
|
|
|
#include "llvm/Object/WasmTraits.h"
|
2017-11-18 02:14:09 +08:00
|
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/Support/LEB128.h"
|
|
|
|
|
|
|
|
#include <cstdarg>
|
2018-01-13 06:25:17 +08:00
|
|
|
#include <map>
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
#define DEBUG_TYPE "lld"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::wasm;
|
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::wasm;
|
|
|
|
|
|
|
|
static constexpr int kStackAlignment = 16;
|
2018-01-25 05:37:30 +08:00
|
|
|
static constexpr int kInitialTableOffset = 1;
|
2018-03-28 01:38:51 +08:00
|
|
|
static constexpr const char *kFunctionTableName = "__indirect_function_table";
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
// An init entry to be written to either the synthetic init func or the
|
|
|
|
// linking metadata.
|
|
|
|
struct WasmInitEntry {
|
2018-03-13 03:56:23 +08:00
|
|
|
const FunctionSymbol *Sym;
|
2018-02-23 13:08:53 +08:00
|
|
|
uint32_t Priority;
|
2018-01-19 07:40:49 +08:00
|
|
|
};
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
// The writer writes a SymbolTable result to a file.
|
|
|
|
class Writer {
|
|
|
|
public:
|
|
|
|
void run();
|
|
|
|
|
|
|
|
private:
|
|
|
|
void openFile();
|
|
|
|
|
2018-01-11 03:18:22 +08:00
|
|
|
uint32_t lookupType(const WasmSignature &Sig);
|
|
|
|
uint32_t registerType(const WasmSignature &Sig);
|
2018-02-23 13:08:53 +08:00
|
|
|
|
2018-01-13 02:35:13 +08:00
|
|
|
void createCtorFunction();
|
|
|
|
void calculateInitFunctions();
|
2018-01-10 07:56:44 +08:00
|
|
|
void assignIndexes();
|
2017-11-18 02:14:09 +08:00
|
|
|
void calculateImports();
|
2018-01-19 07:40:49 +08:00
|
|
|
void calculateExports();
|
2018-05-05 07:14:42 +08:00
|
|
|
void calculateCustomSections();
|
2018-02-23 13:08:53 +08:00
|
|
|
void assignSymtab();
|
2017-11-18 02:14:09 +08:00
|
|
|
void calculateTypes();
|
|
|
|
void createOutputSegments();
|
|
|
|
void layoutMemory();
|
|
|
|
void createHeader();
|
|
|
|
void createSections();
|
2018-03-07 21:28:16 +08:00
|
|
|
SyntheticSection *createSyntheticSection(uint32_t Type, StringRef Name = "");
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
// Builtin sections
|
|
|
|
void createTypeSection();
|
|
|
|
void createFunctionSection();
|
|
|
|
void createTableSection();
|
|
|
|
void createGlobalSection();
|
|
|
|
void createExportSection();
|
|
|
|
void createImportSection();
|
|
|
|
void createMemorySection();
|
|
|
|
void createElemSection();
|
|
|
|
void createCodeSection();
|
|
|
|
void createDataSection();
|
2018-04-11 00:12:49 +08:00
|
|
|
void createCustomSections();
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
// Custom sections
|
|
|
|
void createRelocSections();
|
|
|
|
void createLinkingSection();
|
|
|
|
void createNameSection();
|
|
|
|
|
|
|
|
void writeHeader();
|
|
|
|
void writeSections();
|
|
|
|
|
|
|
|
uint64_t FileSize = 0;
|
|
|
|
uint32_t NumMemoryPages = 0;
|
2018-03-14 21:53:58 +08:00
|
|
|
uint32_t MaxMemoryPages = 0;
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
std::vector<const WasmSignature *> Types;
|
2018-03-14 23:58:16 +08:00
|
|
|
DenseMap<WasmSignature, int32_t> TypeIndices;
|
2018-02-23 13:08:53 +08:00
|
|
|
std::vector<const Symbol *> ImportedSymbols;
|
|
|
|
unsigned NumImportedFunctions = 0;
|
|
|
|
unsigned NumImportedGlobals = 0;
|
2018-05-11 02:10:34 +08:00
|
|
|
std::vector<WasmExport> Exports;
|
2018-02-23 13:08:53 +08:00
|
|
|
std::vector<const DefinedData *> DefinedFakeGlobals;
|
|
|
|
std::vector<InputGlobal *> InputGlobals;
|
2018-02-22 02:29:23 +08:00
|
|
|
std::vector<InputFunction *> InputFunctions;
|
2018-02-15 02:27:59 +08:00
|
|
|
std::vector<const FunctionSymbol *> IndirectFunctions;
|
2018-02-23 13:08:53 +08:00
|
|
|
std::vector<const Symbol *> SymtabEntries;
|
|
|
|
std::vector<WasmInitEntry> InitFunctions;
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-04-11 00:12:49 +08:00
|
|
|
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
|
2018-05-05 07:14:42 +08:00
|
|
|
llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
|
2018-04-11 00:12:49 +08:00
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
// Elements that are used to construct the final output
|
|
|
|
std::string Header;
|
|
|
|
std::vector<OutputSection *> OutputSections;
|
|
|
|
|
|
|
|
std::unique_ptr<FileOutputBuffer> Buffer;
|
|
|
|
|
|
|
|
std::vector<OutputSegment *> Segments;
|
|
|
|
llvm::SmallDenseMap<StringRef, OutputSegment *> SegmentMap;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
void Writer::createImportSection() {
|
2018-02-23 13:08:53 +08:00
|
|
|
uint32_t NumImports = ImportedSymbols.size();
|
2017-11-18 02:14:09 +08:00
|
|
|
if (Config->ImportMemory)
|
|
|
|
++NumImports;
|
2018-03-28 20:53:29 +08:00
|
|
|
if (Config->ImportTable)
|
2018-03-28 01:38:51 +08:00
|
|
|
++NumImports;
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
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 = "env";
|
|
|
|
Import.Field = "memory";
|
|
|
|
Import.Kind = WASM_EXTERNAL_MEMORY;
|
|
|
|
Import.Memory.Flags = 0;
|
|
|
|
Import.Memory.Initial = NumMemoryPages;
|
2018-03-14 21:53:58 +08:00
|
|
|
if (MaxMemoryPages != 0) {
|
|
|
|
Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
|
|
|
Import.Memory.Maximum = MaxMemoryPages;
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
writeImport(OS, Import);
|
|
|
|
}
|
|
|
|
|
2018-03-28 20:53:29 +08:00
|
|
|
if (Config->ImportTable) {
|
2018-03-28 01:38:51 +08:00
|
|
|
uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
|
|
|
|
WasmImport Import;
|
|
|
|
Import.Module = "env";
|
|
|
|
Import.Field = kFunctionTableName;
|
|
|
|
Import.Kind = WASM_EXTERNAL_TABLE;
|
|
|
|
Import.Table.ElemType = WASM_TYPE_ANYFUNC;
|
|
|
|
Import.Table.Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
|
|
|
|
writeImport(OS, Import);
|
|
|
|
}
|
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
for (const Symbol *Sym : ImportedSymbols) {
|
2017-11-18 02:14:09 +08:00
|
|
|
WasmImport Import;
|
|
|
|
Import.Module = "env";
|
|
|
|
Import.Field = Sym->getName();
|
2018-02-23 13:08:53 +08:00
|
|
|
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
|
|
|
|
Import.Kind = WASM_EXTERNAL_FUNCTION;
|
|
|
|
Import.SigIndex = lookupType(*FunctionSym->getFunctionType());
|
|
|
|
} else {
|
|
|
|
auto *GlobalSym = cast<GlobalSymbol>(Sym);
|
|
|
|
Import.Kind = WASM_EXTERNAL_GLOBAL;
|
|
|
|
Import.Global = *GlobalSym->getGlobalType();
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
writeImport(OS, Import);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createTypeSection() {
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_TYPE);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
writeUleb128(OS, Types.size(), "type count");
|
2017-12-20 03:56:27 +08:00
|
|
|
for (const WasmSignature *Sig : Types)
|
2017-11-18 02:14:09 +08:00
|
|
|
writeSig(OS, *Sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createFunctionSection() {
|
2018-02-22 02:29:23 +08:00
|
|
|
if (InputFunctions.empty())
|
2017-11-18 02:14:09 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-02-22 02:29:23 +08:00
|
|
|
writeUleb128(OS, InputFunctions.size(), "function count");
|
|
|
|
for (const InputFunction *Func : InputFunctions)
|
2018-01-11 03:18:22 +08:00
|
|
|
writeUleb128(OS, lookupType(Func->Signature), "sig index");
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createMemorySection() {
|
|
|
|
if (Config->ImportMemory)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-03-14 21:53:58 +08:00
|
|
|
bool HasMax = MaxMemoryPages != 0;
|
2017-11-18 02:14:09 +08:00
|
|
|
writeUleb128(OS, 1, "memory count");
|
2018-03-15 05:43:04 +08:00
|
|
|
writeUleb128(OS, HasMax ? static_cast<unsigned>(WASM_LIMITS_FLAG_HAS_MAX) : 0,
|
|
|
|
"memory limits flags");
|
2017-11-18 02:14:09 +08:00
|
|
|
writeUleb128(OS, NumMemoryPages, "initial pages");
|
2018-03-14 21:53:58 +08:00
|
|
|
if (HasMax)
|
|
|
|
writeUleb128(OS, MaxMemoryPages, "max pages");
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createGlobalSection() {
|
2018-02-23 13:08:53 +08:00
|
|
|
unsigned NumGlobals = InputGlobals.size() + DefinedFakeGlobals.size();
|
|
|
|
if (NumGlobals == 0)
|
2017-12-07 09:51:24 +08:00
|
|
|
return;
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
writeUleb128(OS, NumGlobals, "global count");
|
|
|
|
for (const InputGlobal *G : InputGlobals)
|
|
|
|
writeGlobal(OS, G->Global);
|
|
|
|
for (const DefinedData *Sym : DefinedFakeGlobals) {
|
2017-12-06 03:05:45 +08:00
|
|
|
WasmGlobal Global;
|
2018-02-23 13:08:53 +08:00
|
|
|
Global.Type = {WASM_TYPE_I32, false};
|
2017-12-06 03:05:45 +08:00
|
|
|
Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
|
|
|
Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
|
2017-11-18 02:14:09 +08:00
|
|
|
writeGlobal(OS, Global);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createTableSection() {
|
2018-03-28 20:53:29 +08:00
|
|
|
if (Config->ImportTable)
|
2018-03-28 01:38:51 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Always output a table section (or table import), even if there are no
|
|
|
|
// indirect calls. There are two reasons for this:
|
2017-12-12 06:00:56 +08:00
|
|
|
// 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.
|
2018-01-25 05:37:30 +08:00
|
|
|
uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
|
2017-12-12 06:00:56 +08:00
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
|
|
|
writeUleb128(OS, 1, "table count");
|
2018-03-28 01:38:51 +08:00
|
|
|
WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
|
|
|
|
writeTableType(OS, WasmTable{WASM_TYPE_ANYFUNC, Limits});
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createExportSection() {
|
2018-05-11 02:10:34 +08:00
|
|
|
if (!Exports.size())
|
2017-11-18 02:14:09 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-05-11 02:10:34 +08:00
|
|
|
writeUleb128(OS, Exports.size(), "export count");
|
|
|
|
for (const WasmExport &Export : Exports)
|
2017-12-07 09:51:24 +08:00
|
|
|
writeExport(OS, Export);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 07:14:42 +08:00
|
|
|
void Writer::calculateCustomSections() {
|
|
|
|
log("calculateCustomSections");
|
|
|
|
bool StripDebug = Config->StripDebug || Config->StripAll;
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
for (InputSection *Section : File->CustomSections) {
|
|
|
|
StringRef Name = Section->getName();
|
|
|
|
// These custom sections are known the linker and synthesized rather than
|
|
|
|
// blindly copied
|
|
|
|
if (Name == "linking" || Name == "name" || Name.startswith("reloc."))
|
|
|
|
continue;
|
|
|
|
// .. or it is a debug section
|
|
|
|
if (StripDebug && Name.startswith(".debug_"))
|
|
|
|
continue;
|
|
|
|
CustomSectionMapping[Name].push_back(Section);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-11 00:12:49 +08:00
|
|
|
void Writer::createCustomSections() {
|
|
|
|
log("createCustomSections");
|
|
|
|
for (auto &Pair : CustomSectionMapping) {
|
|
|
|
StringRef Name = Pair.first();
|
2018-05-05 07:14:42 +08:00
|
|
|
|
|
|
|
auto P = CustomSectionSymbols.find(Name);
|
|
|
|
if (P != CustomSectionSymbols.end()) {
|
|
|
|
uint32_t SectionIndex = OutputSections.size();
|
|
|
|
P->second->setOutputSectionIndex(SectionIndex);
|
|
|
|
}
|
|
|
|
|
2018-04-11 00:12:49 +08:00
|
|
|
DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
|
|
|
|
OutputSections.push_back(make<CustomSection>(Name, Pair.second));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
void Writer::createElemSection() {
|
2017-12-12 06:00:56 +08:00
|
|
|
if (IndirectFunctions.empty())
|
2017-11-18 02:14:09 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_ELEM);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
|
|
|
writeUleb128(OS, 1, "segment count");
|
|
|
|
writeUleb128(OS, 0, "table index");
|
|
|
|
WasmInitExpr InitExpr;
|
|
|
|
InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
2018-01-25 05:37:30 +08:00
|
|
|
InitExpr.Value.Int32 = kInitialTableOffset;
|
2017-11-18 02:14:09 +08:00
|
|
|
writeInitExpr(OS, InitExpr);
|
2017-12-12 06:00:56 +08:00
|
|
|
writeUleb128(OS, IndirectFunctions.size(), "elem count");
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-01-25 05:37:30 +08:00
|
|
|
uint32_t TableIndex = kInitialTableOffset;
|
2018-02-15 02:27:59 +08:00
|
|
|
for (const FunctionSymbol *Sym : IndirectFunctions) {
|
2017-12-12 06:00:56 +08:00
|
|
|
assert(Sym->getTableIndex() == TableIndex);
|
2018-03-13 03:56:23 +08:00
|
|
|
writeUleb128(OS, Sym->getFunctionIndex(), "function index");
|
2017-12-12 06:00:56 +08:00
|
|
|
++TableIndex;
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createCodeSection() {
|
2018-02-22 02:29:23 +08:00
|
|
|
if (InputFunctions.empty())
|
2017-11-18 02:14:09 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
log("createCodeSection");
|
|
|
|
|
2018-02-22 02:29:23 +08:00
|
|
|
auto Section = make<CodeSection>(InputFunctions);
|
2017-11-18 02:14:09 +08:00
|
|
|
OutputSections.push_back(Section);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createDataSection() {
|
|
|
|
if (!Segments.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
log("createDataSection");
|
|
|
|
auto Section = make<DataSection>(Segments);
|
|
|
|
OutputSections.push_back(Section);
|
|
|
|
}
|
|
|
|
|
2017-12-20 03:56:27 +08:00
|
|
|
// Create relocations sections in the final output.
|
2017-11-18 02:14:09 +08:00
|
|
|
// These are only created when relocatable output is requested.
|
|
|
|
void Writer::createRelocSections() {
|
|
|
|
log("createRelocSections");
|
|
|
|
// Don't use iterator here since we are adding to OutputSection
|
|
|
|
size_t OrigSize = OutputSections.size();
|
2018-04-25 07:09:57 +08:00
|
|
|
for (size_t I = 0; I < OrigSize; I++) {
|
|
|
|
OutputSection *OSec = OutputSections[I];
|
2018-02-28 08:01:31 +08:00
|
|
|
uint32_t Count = OSec->numRelocations();
|
2017-11-18 02:14:09 +08:00
|
|
|
if (!Count)
|
|
|
|
continue;
|
|
|
|
|
2018-02-28 08:01:31 +08:00
|
|
|
StringRef Name;
|
|
|
|
if (OSec->Type == WASM_SEC_DATA)
|
|
|
|
Name = "reloc.DATA";
|
|
|
|
else if (OSec->Type == WASM_SEC_CODE)
|
|
|
|
Name = "reloc.CODE";
|
2018-05-05 07:14:42 +08:00
|
|
|
else if (OSec->Type == WASM_SEC_CUSTOM)
|
|
|
|
Name = Saver.save("reloc." + OSec->Name);
|
2017-11-18 02:14:09 +08:00
|
|
|
else
|
2018-05-05 07:14:42 +08:00
|
|
|
llvm_unreachable(
|
|
|
|
"relocations only supported for code, data, or custom sections");
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-02-28 08:01:31 +08:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name);
|
2017-11-18 02:14:09 +08:00
|
|
|
raw_ostream &OS = Section->getStream();
|
2018-04-25 07:09:57 +08:00
|
|
|
writeUleb128(OS, I, "reloc section");
|
2017-11-18 02:14:09 +08:00
|
|
|
writeUleb128(OS, Count, "reloc count");
|
2018-02-28 08:01:31 +08:00
|
|
|
OSec->writeRelocations(OS);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 08:28:07 +08:00
|
|
|
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;
|
|
|
|
return Flags;
|
|
|
|
}
|
|
|
|
|
2018-02-28 08:52:42 +08:00
|
|
|
// 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();
|
2018-02-28 11:38:14 +08:00
|
|
|
writeUleb128(To, Type, "subsection type");
|
|
|
|
writeUleb128(To, Body.size(), "subsection size");
|
2018-02-28 08:52:42 +08:00
|
|
|
To.write(Body.data(), Body.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint32_t Type;
|
|
|
|
std::string Body;
|
|
|
|
|
|
|
|
public:
|
|
|
|
raw_string_ostream OS{Body};
|
|
|
|
};
|
|
|
|
|
2017-12-01 08:53:21 +08:00
|
|
|
// Create the custom "linking" section containing linker metadata.
|
2017-11-18 02:14:09 +08:00
|
|
|
// This is only created when relocatable output is requested.
|
|
|
|
void Writer::createLinkingSection() {
|
|
|
|
SyntheticSection *Section =
|
|
|
|
createSyntheticSection(WASM_SEC_CUSTOM, "linking");
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-04-27 02:17:21 +08:00
|
|
|
writeUleb128(OS, WasmMetadataVersion, "Version");
|
2017-12-20 01:09:45 +08:00
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
if (!SymtabEntries.empty()) {
|
2018-02-28 08:39:30 +08:00
|
|
|
SubSection Sub(WASM_SYMBOL_TABLE);
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols");
|
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
for (const Symbol *Sym : SymtabEntries) {
|
|
|
|
assert(Sym->isDefined() || Sym->isUndefined());
|
|
|
|
WasmSymbolType Kind = Sym->getWasmType();
|
2018-02-28 08:28:07 +08:00
|
|
|
uint32_t Flags = getWasmFlags(Sym);
|
|
|
|
|
2018-03-02 02:06:39 +08:00
|
|
|
writeU8(Sub.OS, Kind, "sym kind");
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, Flags, "sym flags");
|
2018-02-28 08:28:07 +08:00
|
|
|
|
2018-03-13 03:56:23 +08:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
|
|
|
|
writeUleb128(Sub.OS, F->getFunctionIndex(), "index");
|
2018-02-23 13:08:53 +08:00
|
|
|
if (Sym->isDefined())
|
2018-02-28 08:52:42 +08:00
|
|
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
2018-03-13 03:56:23 +08:00
|
|
|
} else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {
|
|
|
|
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
|
|
|
|
if (Sym->isDefined())
|
|
|
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
2018-05-05 18:53:31 +08:00
|
|
|
} else if (isa<DataSymbol>(Sym)) {
|
2018-02-28 08:52:42 +08:00
|
|
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
2018-02-23 13:08:53 +08:00
|
|
|
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
|
|
|
|
writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(),
|
2018-02-28 08:39:30 +08:00
|
|
|
"data offset");
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, DataSym->getSize(), "data size");
|
2018-02-23 13:08:53 +08:00
|
|
|
}
|
2018-05-05 07:14:42 +08:00
|
|
|
} else {
|
|
|
|
auto *S = cast<SectionSymbol>(Sym);
|
|
|
|
writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index");
|
2018-02-23 13:08:53 +08:00
|
|
|
}
|
2018-01-19 07:40:49 +08:00
|
|
|
}
|
2018-02-28 08:28:07 +08:00
|
|
|
|
2018-02-28 08:52:42 +08:00
|
|
|
Sub.writeTo(OS);
|
2018-01-19 07:40:49 +08:00
|
|
|
}
|
|
|
|
|
2017-12-20 01:09:45 +08:00
|
|
|
if (Segments.size()) {
|
2018-02-28 08:39:30 +08:00
|
|
|
SubSection Sub(WASM_SEGMENT_INFO);
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, Segments.size(), "num data segments");
|
2017-11-18 02:14:09 +08:00
|
|
|
for (const OutputSegment *S : Segments) {
|
2018-02-28 08:52:42 +08:00
|
|
|
writeStr(Sub.OS, S->Name, "segment name");
|
|
|
|
writeUleb128(Sub.OS, S->Alignment, "alignment");
|
|
|
|
writeUleb128(Sub.OS, 0, "flags");
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
2018-02-28 08:52:42 +08:00
|
|
|
Sub.writeTo(OS);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
2017-12-20 01:09:45 +08:00
|
|
|
|
|
|
|
if (!InitFunctions.empty()) {
|
2018-02-28 08:39:30 +08:00
|
|
|
SubSection Sub(WASM_INIT_FUNCS);
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, InitFunctions.size(), "num init functions");
|
2018-02-23 13:08:53 +08:00
|
|
|
for (const WasmInitEntry &F : InitFunctions) {
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, F.Priority, "priority");
|
|
|
|
writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index");
|
2017-12-20 01:09:45 +08:00
|
|
|
}
|
2018-02-28 08:52:42 +08:00
|
|
|
Sub.writeTo(OS);
|
2017-12-20 01:09:45 +08:00
|
|
|
}
|
2018-01-13 06:25:17 +08:00
|
|
|
|
2018-03-07 21:28:16 +08:00
|
|
|
struct ComdatEntry {
|
|
|
|
unsigned Kind;
|
|
|
|
uint32_t Index;
|
|
|
|
};
|
|
|
|
std::map<StringRef, std::vector<ComdatEntry>> Comdats;
|
2018-01-13 06:25:17 +08:00
|
|
|
|
2018-02-22 02:29:23 +08:00
|
|
|
for (const InputFunction *F : InputFunctions) {
|
2018-03-14 23:45:11 +08:00
|
|
|
StringRef Comdat = F->getComdatName();
|
2018-01-13 06:25:17 +08:00
|
|
|
if (!Comdat.empty())
|
|
|
|
Comdats[Comdat].emplace_back(
|
2018-03-13 03:56:23 +08:00
|
|
|
ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()});
|
2018-01-13 06:25:17 +08:00
|
|
|
}
|
|
|
|
for (uint32_t I = 0; I < Segments.size(); ++I) {
|
2018-01-13 23:57:48 +08:00
|
|
|
const auto &InputSegments = Segments[I]->InputSegments;
|
|
|
|
if (InputSegments.empty())
|
|
|
|
continue;
|
2018-03-14 23:45:11 +08:00
|
|
|
StringRef Comdat = InputSegments[0]->getComdatName();
|
2018-01-13 23:59:53 +08:00
|
|
|
#ifndef NDEBUG
|
2018-01-13 23:57:48 +08:00
|
|
|
for (const InputSegment *IS : InputSegments)
|
2018-03-14 23:45:11 +08:00
|
|
|
assert(IS->getComdatName() == Comdat);
|
2018-01-13 23:59:53 +08:00
|
|
|
#endif
|
2018-01-13 06:25:17 +08:00
|
|
|
if (!Comdat.empty())
|
|
|
|
Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Comdats.empty()) {
|
2018-02-28 08:39:30 +08:00
|
|
|
SubSection Sub(WASM_COMDAT_INFO);
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, Comdats.size(), "num comdats");
|
2018-01-13 06:25:17 +08:00
|
|
|
for (const auto &C : Comdats) {
|
2018-02-28 08:52:42 +08:00
|
|
|
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");
|
2018-01-13 06:25:17 +08:00
|
|
|
for (const ComdatEntry &Entry : C.second) {
|
2018-03-02 02:06:39 +08:00
|
|
|
writeU8(Sub.OS, Entry.Kind, "entry kind");
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, Entry.Index, "entry index");
|
2018-01-13 06:25:17 +08:00
|
|
|
}
|
|
|
|
}
|
2018-02-28 08:52:42 +08:00
|
|
|
Sub.writeTo(OS);
|
2018-01-13 06:25:17 +08:00
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the custom "name" section containing debug symbol names.
|
|
|
|
void Writer::createNameSection() {
|
2018-02-23 13:08:53 +08:00
|
|
|
unsigned NumNames = NumImportedFunctions;
|
2018-02-22 02:29:23 +08:00
|
|
|
for (const InputFunction *F : InputFunctions)
|
2018-04-21 01:09:18 +08:00
|
|
|
if (!F->getName().empty() || !F->getDebugName().empty())
|
2018-01-18 04:19:04 +08:00
|
|
|
++NumNames;
|
2018-01-13 02:35:13 +08:00
|
|
|
|
2018-01-18 04:19:04 +08:00
|
|
|
if (NumNames == 0)
|
|
|
|
return;
|
2018-01-13 02:35:13 +08:00
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name");
|
|
|
|
|
2018-02-28 08:39:30 +08:00
|
|
|
SubSection Sub(WASM_NAMES_FUNCTION);
|
2018-02-28 08:52:42 +08:00
|
|
|
writeUleb128(Sub.OS, NumNames, "name count");
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
// Names must appear in function index order. As it happens ImportedSymbols
|
|
|
|
// and InputFunctions are numbered in order with imported functions coming
|
2018-01-18 04:19:04 +08:00
|
|
|
// first.
|
2018-02-23 13:08:53 +08:00
|
|
|
for (const Symbol *S : ImportedSymbols) {
|
2018-03-13 03:56:23 +08:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(S)) {
|
|
|
|
writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
|
2018-03-13 21:30:04 +08:00
|
|
|
Optional<std::string> Name = demangleItanium(F->getName());
|
|
|
|
writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name");
|
2018-03-13 03:56:23 +08:00
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
2018-02-22 02:29:23 +08:00
|
|
|
for (const InputFunction *F : InputFunctions) {
|
2018-01-18 04:19:04 +08:00
|
|
|
if (!F->getName().empty()) {
|
2018-03-13 03:56:23 +08:00
|
|
|
writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
|
2018-04-21 01:09:18 +08:00
|
|
|
if (!F->getDebugName().empty()) {
|
|
|
|
writeStr(Sub.OS, F->getDebugName(), "symbol name");
|
|
|
|
} else {
|
|
|
|
Optional<std::string> Name = demangleItanium(F->getName());
|
|
|
|
writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name");
|
|
|
|
}
|
2018-01-18 04:19:04 +08:00
|
|
|
}
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-02-28 08:52:42 +08:00
|
|
|
Sub.writeTo(Section->getStream());
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::writeHeader() {
|
|
|
|
memcpy(Buffer->getBufferStart(), Header.data(), Header.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::writeSections() {
|
|
|
|
uint8_t *Buf = Buffer->getBufferStart();
|
|
|
|
parallelForEach(OutputSections, [Buf](OutputSection *S) { S->writeTo(Buf); });
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix the memory layout of the output binary. This assigns memory offsets
|
2017-12-01 08:53:21 +08:00
|
|
|
// to each of the input data sections as well as the explicit stack region.
|
2018-05-04 01:21:53 +08:00
|
|
|
// The default memory layout is as follows, from low to high.
|
|
|
|
//
|
2018-02-03 06:59:56 +08:00
|
|
|
// - initialized data (starting at Config->GlobalBase)
|
|
|
|
// - BSS data (not currently implemented in llvm)
|
|
|
|
// - explicit stack (Config->ZStackSize)
|
|
|
|
// - heap start / unallocated
|
2018-05-04 01:21:53 +08:00
|
|
|
//
|
|
|
|
// The --stack-first option means that stack is placed before any static data.
|
|
|
|
// This can be useful since it means that stack overflow traps immediately rather
|
|
|
|
// than overwriting global data, but also increases code size since all static
|
|
|
|
// data loads and stores requires larger offsets.
|
2017-11-18 02:14:09 +08:00
|
|
|
void Writer::layoutMemory() {
|
2018-05-04 01:21:53 +08:00
|
|
|
createOutputSegments();
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
uint32_t MemoryPtr = 0;
|
|
|
|
|
2018-05-04 01:21:53 +08:00
|
|
|
auto PlaceStack = [&]() {
|
|
|
|
if (Config->Relocatable)
|
|
|
|
return;
|
|
|
|
MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
|
|
|
|
if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
|
|
|
|
error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
|
|
|
|
log("mem: stack size = " + Twine(Config->ZStackSize));
|
|
|
|
log("mem: stack base = " + Twine(MemoryPtr));
|
|
|
|
MemoryPtr += Config->ZStackSize;
|
|
|
|
WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
|
|
|
|
log("mem: stack top = " + Twine(MemoryPtr));
|
|
|
|
};
|
|
|
|
|
|
|
|
if (Config->StackFirst) {
|
|
|
|
PlaceStack();
|
|
|
|
} else {
|
|
|
|
MemoryPtr = Config->GlobalBase;
|
|
|
|
log("mem: global base = " + Twine(Config->GlobalBase));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t DataStart = MemoryPtr;
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-02-03 06:59:56 +08:00
|
|
|
// Arbitrarily set __dso_handle handle to point to the start of the data
|
|
|
|
// segments.
|
|
|
|
if (WasmSym::DsoHandle)
|
2018-05-04 01:21:53 +08:00
|
|
|
WasmSym::DsoHandle->setVirtualAddress(DataStart);
|
2018-02-03 06:59:56 +08:00
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
for (OutputSegment *Seg : Segments) {
|
|
|
|
MemoryPtr = alignTo(MemoryPtr, Seg->Alignment);
|
|
|
|
Seg->StartVA = MemoryPtr;
|
2018-03-14 21:50:20 +08:00
|
|
|
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name,
|
|
|
|
MemoryPtr, Seg->Size, Seg->Alignment));
|
2017-11-18 02:14:09 +08:00
|
|
|
MemoryPtr += Seg->Size;
|
|
|
|
}
|
|
|
|
|
2018-02-03 06:59:56 +08:00
|
|
|
// TODO: Add .bss space here.
|
2018-02-07 11:04:53 +08:00
|
|
|
if (WasmSym::DataEnd)
|
|
|
|
WasmSym::DataEnd->setVirtualAddress(MemoryPtr);
|
2018-02-03 06:59:56 +08:00
|
|
|
|
2018-05-04 01:21:53 +08:00
|
|
|
log("mem: static data = " + Twine(MemoryPtr - DataStart));
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-05-04 01:21:53 +08:00
|
|
|
if (!Config->StackFirst)
|
|
|
|
PlaceStack();
|
2018-02-23 13:08:53 +08:00
|
|
|
|
2018-05-04 01:21:53 +08:00
|
|
|
// Set `__heap_base` to directly follow the end of the stack or global data.
|
|
|
|
// The fact that this comes last means that a malloc/brk implementation
|
|
|
|
// can grow the heap at runtime.
|
|
|
|
if (!Config->Relocatable) {
|
2018-02-03 06:59:56 +08:00
|
|
|
WasmSym::HeapBase->setVirtualAddress(MemoryPtr);
|
2018-03-14 21:50:20 +08:00
|
|
|
log("mem: heap base = " + Twine(MemoryPtr));
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2018-03-14 21:53:58 +08:00
|
|
|
if (Config->InitialMemory != 0) {
|
|
|
|
if (Config->InitialMemory != alignTo(Config->InitialMemory, WasmPageSize))
|
|
|
|
error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned");
|
|
|
|
if (MemoryPtr > Config->InitialMemory)
|
|
|
|
error("initial memory too small, " + Twine(MemoryPtr) + " bytes needed");
|
|
|
|
else
|
|
|
|
MemoryPtr = Config->InitialMemory;
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
uint32_t MemSize = alignTo(MemoryPtr, WasmPageSize);
|
|
|
|
NumMemoryPages = MemSize / WasmPageSize;
|
2018-03-14 21:50:20 +08:00
|
|
|
log("mem: total pages = " + Twine(NumMemoryPages));
|
2018-03-14 21:53:58 +08:00
|
|
|
|
|
|
|
if (Config->MaxMemory != 0) {
|
|
|
|
if (Config->MaxMemory != alignTo(Config->MaxMemory, WasmPageSize))
|
|
|
|
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));
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SyntheticSection *Writer::createSyntheticSection(uint32_t Type,
|
2018-01-11 03:18:22 +08:00
|
|
|
StringRef Name) {
|
2017-11-18 02:14:09 +08:00
|
|
|
auto Sec = make<SyntheticSection>(Type, Name);
|
2017-12-20 13:14:48 +08:00
|
|
|
log("createSection: " + toString(*Sec));
|
2017-11-18 02:14:09 +08:00
|
|
|
OutputSections.push_back(Sec);
|
|
|
|
return Sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createSections() {
|
|
|
|
// Known sections
|
|
|
|
createTypeSection();
|
|
|
|
createImportSection();
|
|
|
|
createFunctionSection();
|
|
|
|
createTableSection();
|
|
|
|
createMemorySection();
|
|
|
|
createGlobalSection();
|
|
|
|
createExportSection();
|
|
|
|
createElemSection();
|
|
|
|
createCodeSection();
|
|
|
|
createDataSection();
|
2018-04-11 00:12:49 +08:00
|
|
|
createCustomSections();
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
// Custom sections
|
2018-02-28 07:58:03 +08:00
|
|
|
if (Config->Relocatable) {
|
|
|
|
createLinkingSection();
|
2018-03-05 20:33:58 +08:00
|
|
|
createRelocSections();
|
2018-02-28 07:58:03 +08:00
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
if (!Config->StripDebug && !Config->StripAll)
|
|
|
|
createNameSection();
|
|
|
|
|
|
|
|
for (OutputSection *S : OutputSections) {
|
|
|
|
S->setOffset(FileSize);
|
|
|
|
S->finalizeContents();
|
|
|
|
FileSize += S->getSize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::calculateImports() {
|
2017-12-16 03:23:49 +08:00
|
|
|
for (Symbol *Sym : Symtab->getSymbols()) {
|
2018-02-23 13:08:53 +08:00
|
|
|
if (!Sym->isUndefined())
|
|
|
|
continue;
|
|
|
|
if (isa<DataSymbol>(Sym))
|
|
|
|
continue;
|
|
|
|
if (Sym->isWeak() && !Config->Relocatable)
|
2017-12-16 03:23:49 +08:00
|
|
|
continue;
|
2018-04-21 01:18:06 +08:00
|
|
|
if (!Sym->isLive())
|
|
|
|
continue;
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
|
|
|
|
ImportedSymbols.emplace_back(Sym);
|
2018-03-13 03:56:23 +08:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
|
|
|
F->setFunctionIndex(NumImportedFunctions++);
|
2018-02-23 13:08:53 +08:00
|
|
|
else
|
2018-03-13 03:56:23 +08:00
|
|
|
cast<GlobalSymbol>(Sym)->setGlobalIndex(NumImportedGlobals++);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-19 07:40:49 +08:00
|
|
|
void Writer::calculateExports() {
|
2018-02-23 13:08:53 +08:00
|
|
|
if (Config->Relocatable)
|
|
|
|
return;
|
|
|
|
|
2018-05-11 02:10:34 +08:00
|
|
|
if (!Config->Relocatable && !Config->ImportMemory)
|
|
|
|
Exports.push_back(WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
|
|
|
|
|
|
|
|
if (!Config->Relocatable && Config->ExportTable)
|
|
|
|
Exports.push_back(WasmExport{kFunctionTableName, WASM_EXTERNAL_TABLE, 0});
|
|
|
|
|
|
|
|
unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
|
|
|
|
|
2018-03-01 17:38:02 +08:00
|
|
|
for (Symbol *Sym : Symtab->getSymbols()) {
|
2018-02-23 13:08:53 +08:00
|
|
|
if (!Sym->isDefined())
|
2018-03-01 17:38:02 +08:00
|
|
|
continue;
|
2018-02-23 13:08:53 +08:00
|
|
|
if (Sym->isHidden() || Sym->isLocal())
|
2018-03-01 17:38:02 +08:00
|
|
|
continue;
|
2018-02-23 13:08:53 +08:00
|
|
|
if (!Sym->isLive())
|
2018-03-01 17:38:02 +08:00
|
|
|
continue;
|
2018-02-23 13:08:53 +08:00
|
|
|
|
2018-05-11 02:10:34 +08:00
|
|
|
StringRef Name = Sym->getName();
|
|
|
|
WasmExport Export;
|
|
|
|
if (auto *F = dyn_cast<DefinedFunction>(Sym)) {
|
|
|
|
Export = {Name, WASM_EXTERNAL_FUNCTION, F->getFunctionIndex()};
|
|
|
|
} else if (auto *G = dyn_cast<DefinedGlobal>(Sym)) {
|
|
|
|
Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
|
|
|
|
} else {
|
|
|
|
auto *D = cast<DefinedData>(Sym);
|
2018-02-23 13:08:53 +08:00
|
|
|
DefinedFakeGlobals.emplace_back(D);
|
2018-05-11 02:10:34 +08:00
|
|
|
Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++};
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "Export: " << Name << "\n");
|
|
|
|
Exports.push_back(Export);
|
2018-03-01 17:38:02 +08:00
|
|
|
}
|
2018-02-23 13:08:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::assignSymtab() {
|
|
|
|
if (!Config->Relocatable)
|
|
|
|
return;
|
2018-01-19 07:40:49 +08:00
|
|
|
|
2018-05-05 07:14:42 +08:00
|
|
|
StringMap<uint32_t> SectionSymbolIndices;
|
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
unsigned SymbolIndex = SymtabEntries.size();
|
2018-01-19 07:40:49 +08:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-02-23 13:08:53 +08:00
|
|
|
DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n");
|
2018-01-19 07:40:49 +08:00
|
|
|
for (Symbol *Sym : File->getSymbols()) {
|
2018-02-23 13:08:53 +08:00
|
|
|
if (Sym->getFile() != File)
|
2018-01-19 07:40:49 +08:00
|
|
|
continue;
|
2018-05-05 07:14:42 +08:00
|
|
|
|
|
|
|
if (auto *S = dyn_cast<SectionSymbol>(Sym)) {
|
|
|
|
StringRef Name = S->getName();
|
|
|
|
if (CustomSectionMapping.count(Name) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto SSI = SectionSymbolIndices.find(Name);
|
|
|
|
if (SSI != SectionSymbolIndices.end()) {
|
|
|
|
Sym->setOutputSymbolIndex(SSI->second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
SectionSymbolIndices[Name] = SymbolIndex;
|
|
|
|
CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym);
|
|
|
|
|
|
|
|
Sym->markLive();
|
|
|
|
}
|
|
|
|
|
2018-03-07 19:15:47 +08:00
|
|
|
// (Since this is relocatable output, GC is not performed so symbols must
|
|
|
|
// be live.)
|
|
|
|
assert(Sym->isLive());
|
2018-02-23 13:08:53 +08:00
|
|
|
Sym->setOutputSymbolIndex(SymbolIndex++);
|
|
|
|
SymtabEntries.emplace_back(Sym);
|
2018-01-19 07:40:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
// For the moment, relocatable output doesn't contain any synthetic functions,
|
|
|
|
// so no need to look through the Symtab for symbols not referenced by
|
|
|
|
// Symtab->ObjectFiles.
|
2018-01-19 07:40:49 +08:00
|
|
|
}
|
|
|
|
|
2018-01-11 03:18:22 +08:00
|
|
|
uint32_t Writer::lookupType(const WasmSignature &Sig) {
|
2018-01-11 04:12:26 +08:00
|
|
|
auto It = TypeIndices.find(Sig);
|
|
|
|
if (It == TypeIndices.end()) {
|
2018-01-11 03:18:22 +08:00
|
|
|
error("type not found: " + toString(Sig));
|
2018-01-11 04:12:26 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return It->second;
|
2018-01-11 03:18:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Writer::registerType(const WasmSignature &Sig) {
|
2017-11-30 09:40:08 +08:00
|
|
|
auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
|
2018-01-11 03:18:22 +08:00
|
|
|
if (Pair.second) {
|
|
|
|
DEBUG(dbgs() << "type " << toString(Sig) << "\n");
|
2017-11-30 09:40:08 +08:00
|
|
|
Types.push_back(&Sig);
|
2018-01-11 03:18:22 +08:00
|
|
|
}
|
2017-11-30 09:40:08 +08:00
|
|
|
return Pair.first->second;
|
|
|
|
}
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
void Writer::calculateTypes() {
|
2018-02-01 07:48:14 +08:00
|
|
|
// The output type section is the union of the following sets:
|
|
|
|
// 1. Any signature used in the TYPE relocation
|
|
|
|
// 2. The signatures of all imported functions
|
|
|
|
// 3. The signatures of all defined functions
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-02-01 07:48:14 +08:00
|
|
|
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]);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
2018-01-13 02:35:13 +08:00
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
for (const Symbol *Sym : ImportedSymbols)
|
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
|
|
|
registerType(*F->getFunctionType());
|
2018-02-01 07:48:14 +08:00
|
|
|
|
2018-02-22 02:29:23 +08:00
|
|
|
for (const InputFunction *F : InputFunctions)
|
2018-02-01 07:48:14 +08:00
|
|
|
registerType(F->Signature);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2018-01-10 07:56:44 +08:00
|
|
|
void Writer::assignIndexes() {
|
2018-02-23 13:08:53 +08:00
|
|
|
uint32_t FunctionIndex = NumImportedFunctions + InputFunctions.size();
|
2018-03-10 00:43:05 +08:00
|
|
|
auto AddDefinedFunction = [&](InputFunction *Func) {
|
|
|
|
if (!Func->Live)
|
|
|
|
return;
|
|
|
|
InputFunctions.emplace_back(Func);
|
2018-03-13 03:56:23 +08:00
|
|
|
Func->setFunctionIndex(FunctionIndex++);
|
2018-03-10 00:43:05 +08:00
|
|
|
};
|
|
|
|
|
2018-03-12 23:44:07 +08:00
|
|
|
for (InputFunction *Func : Symtab->SyntheticFunctions)
|
|
|
|
AddDefinedFunction(Func);
|
|
|
|
|
2018-01-09 07:39:11 +08:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-01-10 07:56:44 +08:00
|
|
|
DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
|
2018-03-10 00:43:05 +08:00
|
|
|
for (InputFunction *Func : File->Functions)
|
|
|
|
AddDefinedFunction(Func);
|
2018-01-10 07:56:44 +08:00
|
|
|
}
|
|
|
|
|
2018-02-23 13:08:53 +08:00
|
|
|
uint32_t TableIndex = kInitialTableOffset;
|
2018-02-23 12:59:57 +08:00
|
|
|
auto HandleRelocs = [&](InputChunk *Chunk) {
|
|
|
|
if (!Chunk->Live)
|
|
|
|
return;
|
|
|
|
ObjFile *File = Chunk->File;
|
|
|
|
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
|
2018-02-23 13:08:53 +08:00
|
|
|
for (const WasmRelocation &Reloc : Chunk->getRelocations()) {
|
2018-02-23 12:59:57 +08:00
|
|
|
if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 ||
|
|
|
|
Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) {
|
|
|
|
FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index);
|
2018-03-13 03:56:23 +08:00
|
|
|
if (Sym->hasTableIndex() || !Sym->hasFunctionIndex())
|
2018-02-23 12:59:57 +08:00
|
|
|
continue;
|
|
|
|
Sym->setTableIndex(TableIndex++);
|
|
|
|
IndirectFunctions.emplace_back(Sym);
|
|
|
|
} else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) {
|
2018-02-23 13:08:53 +08:00
|
|
|
// Mark target type as live
|
2018-02-23 12:59:57 +08:00
|
|
|
File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
|
|
|
|
File->TypeIsUsed[Reloc.Index] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-10 07:56:44 +08:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-02-01 07:48:14 +08:00
|
|
|
DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
|
2018-02-23 13:08:53 +08:00
|
|
|
for (InputChunk *Chunk : File->Functions)
|
2018-02-23 12:59:57 +08:00
|
|
|
HandleRelocs(Chunk);
|
2018-02-23 13:08:53 +08:00
|
|
|
for (InputChunk *Chunk : File->Segments)
|
2018-02-23 12:59:57 +08:00
|
|
|
HandleRelocs(Chunk);
|
2018-05-05 07:14:42 +08:00
|
|
|
for (auto &P : File->CustomSections)
|
|
|
|
HandleRelocs(P);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
2018-02-23 13:08:53 +08:00
|
|
|
|
|
|
|
uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size();
|
|
|
|
auto AddDefinedGlobal = [&](InputGlobal *Global) {
|
|
|
|
if (Global->Live) {
|
|
|
|
DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
|
2018-03-13 03:56:23 +08:00
|
|
|
Global->setGlobalIndex(GlobalIndex++);
|
2018-02-23 13:08:53 +08:00
|
|
|
InputGlobals.push_back(Global);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-03-10 00:43:05 +08:00
|
|
|
for (InputGlobal *Global : Symtab->SyntheticGlobals)
|
|
|
|
AddDefinedGlobal(Global);
|
2018-02-23 13:08:53 +08:00
|
|
|
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
|
|
|
|
for (InputGlobal *Global : File->Globals)
|
|
|
|
AddDefinedGlobal(Global);
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static StringRef getOutputDataSegmentName(StringRef Name) {
|
[WebAssembly] Add a flag to control merging data segments
Merging data segments produces smaller code sizes because each segment
has some boilerplate. Therefore, merging data segments is generally the
right approach, especially with wasm where binaries are typically
delivered over the network.
However, when analyzing wasm binaries, it can be helpful to get a
conservative picture of which functions are using which data
segments[0]. Perhaps there is a large data segment that you didn't
expect to be included in the wasm, introduced by some library you're
using, and you'd like to know which library it was. In this scenario,
merging data segments only makes the analysis worse.
Alternatively, perhaps you will remove some dead functions by-hand[1]
that can't be statically proven dead by the compiler or lld, and
removing these functions might make some data garbage collect-able, and
you'd like to run `--gc-sections` again so that this now-unused data can
be collected. If the segments were originally merged, then a single use
of the merged data segment will entrench all of the data.
[0] https://github.com/rustwasm/twiggy
[1] https://github.com/fitzgen/wasm-snip
Patch by Nick Fitzgerald!
Differential Revision: https://reviews.llvm.org/D46417
llvm-svn: 332013
2018-05-11 02:23:51 +08:00
|
|
|
if (!Config->MergeDataSegments)
|
2017-11-18 02:14:09 +08:00
|
|
|
return Name;
|
2018-02-28 08:57:28 +08:00
|
|
|
if (Name.startswith(".text."))
|
|
|
|
return ".text";
|
|
|
|
if (Name.startswith(".data."))
|
|
|
|
return ".data";
|
|
|
|
if (Name.startswith(".bss."))
|
|
|
|
return ".bss";
|
2017-11-18 02:14:09 +08:00
|
|
|
return Name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createOutputSegments() {
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
for (InputSegment *Segment : File->Segments) {
|
2018-02-14 04:29:38 +08:00
|
|
|
if (!Segment->Live)
|
2018-01-13 06:25:17 +08:00
|
|
|
continue;
|
2017-11-18 02:14:09 +08:00
|
|
|
StringRef Name = getOutputDataSegmentName(Segment->getName());
|
|
|
|
OutputSegment *&S = SegmentMap[Name];
|
|
|
|
if (S == nullptr) {
|
|
|
|
DEBUG(dbgs() << "new segment: " << Name << "\n");
|
2018-02-23 13:08:53 +08:00
|
|
|
S = make<OutputSegment>(Name, Segments.size());
|
2017-11-18 02:14:09 +08:00
|
|
|
Segments.push_back(S);
|
|
|
|
}
|
|
|
|
S->addInputSegment(Segment);
|
|
|
|
DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-13 02:35:13 +08:00
|
|
|
static const int OPCODE_CALL = 0x10;
|
|
|
|
static const int OPCODE_END = 0xb;
|
|
|
|
|
|
|
|
// Create synthetic "__wasm_call_ctors" function based on ctor functions
|
|
|
|
// in input object.
|
|
|
|
void Writer::createCtorFunction() {
|
2018-03-02 22:48:50 +08:00
|
|
|
// First write the body's contents to a string.
|
|
|
|
std::string BodyContent;
|
2018-01-13 02:35:13 +08:00
|
|
|
{
|
2018-03-02 22:48:50 +08:00
|
|
|
raw_string_ostream OS(BodyContent);
|
2018-01-13 02:35:13 +08:00
|
|
|
writeUleb128(OS, 0, "num locals");
|
2018-02-23 13:08:53 +08:00
|
|
|
for (const WasmInitEntry &F : InitFunctions) {
|
2018-01-13 02:35:13 +08:00
|
|
|
writeU8(OS, OPCODE_CALL, "CALL");
|
2018-03-13 03:56:23 +08:00
|
|
|
writeUleb128(OS, F.Sym->getFunctionIndex(), "function index");
|
2018-01-13 02:35:13 +08:00
|
|
|
}
|
|
|
|
writeU8(OS, OPCODE_END, "END");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we know the size of the body we can create the final function body
|
2018-03-02 22:48:50 +08:00
|
|
|
std::string FunctionBody;
|
|
|
|
{
|
|
|
|
raw_string_ostream OS(FunctionBody);
|
|
|
|
writeUleb128(OS, BodyContent.size(), "function size");
|
|
|
|
OS << BodyContent;
|
|
|
|
}
|
2018-03-01 01:43:15 +08:00
|
|
|
|
2018-03-10 00:43:05 +08:00
|
|
|
ArrayRef<uint8_t> Body = toArrayRef(Saver.save(FunctionBody));
|
|
|
|
cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body);
|
2018-01-13 02:35:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Populate InitFunctions vector with init functions from all input objects.
|
|
|
|
// This is then used either when creating the output linking section or to
|
|
|
|
// synthesize the "__wasm_call_ctors" function.
|
|
|
|
void Writer::calculateInitFunctions() {
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
const WasmLinkingData &L = File->getWasmObj()->linkingData();
|
2018-03-02 22:46:54 +08:00
|
|
|
for (const WasmInitFunc &F : L.InitFunctions) {
|
|
|
|
FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol);
|
|
|
|
if (*Sym->getFunctionType() != WasmSignature{{}, WASM_TYPE_NORESULT})
|
|
|
|
error("invalid signature for init func: " + toString(*Sym));
|
|
|
|
InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority});
|
|
|
|
}
|
2018-01-13 02:35:13 +08:00
|
|
|
}
|
2018-02-28 08:15:59 +08:00
|
|
|
|
2018-01-13 02:35:13 +08:00
|
|
|
// Sort in order of priority (lowest first) so that they are called
|
|
|
|
// in the correct order.
|
2018-02-21 08:34:34 +08:00
|
|
|
std::stable_sort(InitFunctions.begin(), InitFunctions.end(),
|
2018-02-23 13:08:53 +08:00
|
|
|
[](const WasmInitEntry &L, const WasmInitEntry &R) {
|
2018-02-21 08:34:34 +08:00
|
|
|
return L.Priority < R.Priority;
|
|
|
|
});
|
2018-01-13 02:35:13 +08:00
|
|
|
}
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
void Writer::run() {
|
2018-02-28 07:58:03 +08:00
|
|
|
if (Config->Relocatable)
|
|
|
|
Config->GlobalBase = 0;
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
log("-- calculateImports");
|
|
|
|
calculateImports();
|
2018-01-10 07:56:44 +08:00
|
|
|
log("-- assignIndexes");
|
|
|
|
assignIndexes();
|
2018-01-13 02:35:13 +08:00
|
|
|
log("-- calculateInitFunctions");
|
|
|
|
calculateInitFunctions();
|
|
|
|
if (!Config->Relocatable)
|
|
|
|
createCtorFunction();
|
2018-02-01 07:48:14 +08:00
|
|
|
log("-- calculateTypes");
|
|
|
|
calculateTypes();
|
2018-02-23 13:08:53 +08:00
|
|
|
log("-- layoutMemory");
|
|
|
|
layoutMemory();
|
|
|
|
log("-- calculateExports");
|
|
|
|
calculateExports();
|
2018-05-05 07:14:42 +08:00
|
|
|
log("-- calculateCustomSections");
|
|
|
|
calculateCustomSections();
|
2018-02-23 13:08:53 +08:00
|
|
|
log("-- assignSymtab");
|
|
|
|
assignSymtab();
|
2017-11-18 02:14:09 +08:00
|
|
|
|
|
|
|
if (errorHandler().Verbose) {
|
2018-02-22 02:29:23 +08:00
|
|
|
log("Defined Functions: " + Twine(InputFunctions.size()));
|
2018-02-23 13:08:53 +08:00
|
|
|
log("Defined Globals : " + Twine(InputGlobals.size()));
|
|
|
|
log("Function Imports : " + Twine(NumImportedFunctions));
|
|
|
|
log("Global Imports : " + Twine(NumImportedGlobals));
|
2017-11-18 02:14:09 +08:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles)
|
|
|
|
File->dumpInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
createHeader();
|
|
|
|
log("-- createSections");
|
|
|
|
createSections();
|
|
|
|
|
|
|
|
log("-- openFile");
|
|
|
|
openFile();
|
|
|
|
if (errorCount())
|
|
|
|
return;
|
|
|
|
|
|
|
|
writeHeader();
|
|
|
|
|
|
|
|
log("-- writeSections");
|
|
|
|
writeSections();
|
|
|
|
if (errorCount())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (Error E = Buffer->commit())
|
|
|
|
fatal("failed to write the output file: " + toString(std::move(E)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open a result file.
|
|
|
|
void Writer::openFile() {
|
|
|
|
log("writing: " + Config->OutputFile);
|
|
|
|
|
|
|
|
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
|
|
|
FileOutputBuffer::create(Config->OutputFile, FileSize,
|
|
|
|
FileOutputBuffer::F_executable);
|
|
|
|
|
|
|
|
if (!BufferOrErr)
|
|
|
|
error("failed to open " + Config->OutputFile + ": " +
|
|
|
|
toString(BufferOrErr.takeError()));
|
|
|
|
else
|
|
|
|
Buffer = std::move(*BufferOrErr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createHeader() {
|
|
|
|
raw_string_ostream OS(Header);
|
|
|
|
writeBytes(OS, WasmMagic, sizeof(WasmMagic), "wasm magic");
|
|
|
|
writeU32(OS, WasmVersion, "wasm version");
|
|
|
|
OS.flush();
|
|
|
|
FileSize += Header.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void lld::wasm::writeResult() { Writer().run(); }
|