2017-11-17 18:14:09 +00:00
|
|
|
//===- Writer.cpp ---------------------------------------------------------===//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// 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
|
2017-11-17 18:14:09 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Writer.h"
|
|
|
|
#include "Config.h"
|
2018-01-10 01:13:34 +00:00
|
|
|
#include "InputChunks.h"
|
2018-12-08 06:17:43 +00:00
|
|
|
#include "InputEvent.h"
|
2018-02-23 05:08:53 +00:00
|
|
|
#include "InputGlobal.h"
|
2017-11-17 18:14:09 +00:00
|
|
|
#include "OutputSections.h"
|
|
|
|
#include "OutputSegment.h"
|
|
|
|
#include "SymbolTable.h"
|
|
|
|
#include "WriterUtils.h"
|
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2017-11-28 20:39:17 +00:00
|
|
|
#include "lld/Common/Memory.h"
|
2018-03-07 10:37:50 +00:00
|
|
|
#include "lld/Common/Strings.h"
|
2017-11-17 18:14:09 +00:00
|
|
|
#include "lld/Common/Threads.h"
|
2018-02-20 21:53:18 +00:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2019-01-17 02:29:41 +00:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2018-04-10 16:12:49 +00:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2018-02-23 05:08:53 +00:00
|
|
|
#include "llvm/BinaryFormat/Wasm.h"
|
2018-03-14 15:58:16 +00:00
|
|
|
#include "llvm/Object/WasmTraits.h"
|
2017-11-17 18:14:09 +00:00
|
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/Support/LEB128.h"
|
2019-03-13 21:29:20 +00:00
|
|
|
#include "llvm/Support/Path.h"
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
#include <cstdarg>
|
2018-01-12 22:25:17 +00:00
|
|
|
#include <map>
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
#define DEBUG_TYPE "lld"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::wasm;
|
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::wasm;
|
|
|
|
|
2019-02-04 19:13:46 +00:00
|
|
|
static constexpr int StackAlignment = 16;
|
|
|
|
static constexpr const char *FunctionTableName = "__indirect_function_table";
|
|
|
|
const char *lld::wasm::DefaultModule = "env";
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
// An init entry to be written to either the synthetic init func or the
|
|
|
|
// linking metadata.
|
|
|
|
struct WasmInitEntry {
|
2018-03-12 19:56:23 +00:00
|
|
|
const FunctionSymbol *Sym;
|
2018-02-23 05:08:53 +00:00
|
|
|
uint32_t Priority;
|
2018-01-18 23:40:49 +00:00
|
|
|
};
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
// The writer writes a SymbolTable result to a file.
|
|
|
|
class Writer {
|
|
|
|
public:
|
|
|
|
void run();
|
|
|
|
|
|
|
|
private:
|
|
|
|
void openFile();
|
|
|
|
|
2018-01-10 19:18:22 +00:00
|
|
|
uint32_t lookupType(const WasmSignature &Sig);
|
|
|
|
uint32_t registerType(const WasmSignature &Sig);
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2018-01-12 18:35:13 +00:00
|
|
|
void createCtorFunction();
|
|
|
|
void calculateInitFunctions();
|
2018-01-09 23:56:44 +00:00
|
|
|
void assignIndexes();
|
2017-11-17 18:14:09 +00:00
|
|
|
void calculateImports();
|
2018-01-18 23:40:49 +00:00
|
|
|
void calculateExports();
|
2018-05-04 23:14:42 +00:00
|
|
|
void calculateCustomSections();
|
2018-02-23 05:08:53 +00:00
|
|
|
void assignSymtab();
|
2017-11-17 18:14:09 +00:00
|
|
|
void calculateTypes();
|
|
|
|
void createOutputSegments();
|
|
|
|
void layoutMemory();
|
|
|
|
void createHeader();
|
|
|
|
void createSections();
|
2018-03-07 13:28:16 +00:00
|
|
|
SyntheticSection *createSyntheticSection(uint32_t Type, StringRef Name = "");
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
// Builtin sections
|
|
|
|
void createTypeSection();
|
|
|
|
void createFunctionSection();
|
|
|
|
void createTableSection();
|
|
|
|
void createGlobalSection();
|
2018-12-08 06:17:43 +00:00
|
|
|
void createEventSection();
|
2017-11-17 18:14:09 +00:00
|
|
|
void createExportSection();
|
|
|
|
void createImportSection();
|
|
|
|
void createMemorySection();
|
|
|
|
void createElemSection();
|
|
|
|
void createCodeSection();
|
|
|
|
void createDataSection();
|
2018-04-10 16:12:49 +00:00
|
|
|
void createCustomSections();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
// Custom sections
|
2018-11-15 00:37:21 +00:00
|
|
|
void createDylinkSection();
|
2017-11-17 18:14:09 +00:00
|
|
|
void createRelocSections();
|
|
|
|
void createLinkingSection();
|
|
|
|
void createNameSection();
|
2019-01-17 02:29:41 +00:00
|
|
|
void createProducersSection();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
void writeHeader();
|
|
|
|
void writeSections();
|
|
|
|
|
|
|
|
uint64_t FileSize = 0;
|
2018-11-15 00:37:21 +00:00
|
|
|
uint32_t TableBase = 0;
|
2017-11-17 18:14:09 +00:00
|
|
|
uint32_t NumMemoryPages = 0;
|
2018-03-14 13:53:58 +00:00
|
|
|
uint32_t MaxMemoryPages = 0;
|
2018-11-15 00:37:21 +00:00
|
|
|
// Memory size and aligment. Written to the "dylink" section
|
|
|
|
// when build with -shared or -pie.
|
|
|
|
uint32_t MemAlign = 0;
|
|
|
|
uint32_t MemSize = 0;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
std::vector<const WasmSignature *> Types;
|
2018-03-14 15:58:16 +00:00
|
|
|
DenseMap<WasmSignature, int32_t> TypeIndices;
|
2018-02-23 05:08:53 +00:00
|
|
|
std::vector<const Symbol *> ImportedSymbols;
|
|
|
|
unsigned NumImportedFunctions = 0;
|
|
|
|
unsigned NumImportedGlobals = 0;
|
2018-12-08 06:17:43 +00:00
|
|
|
unsigned NumImportedEvents = 0;
|
2018-05-10 18:10:34 +00:00
|
|
|
std::vector<WasmExport> Exports;
|
2018-02-23 05:08:53 +00:00
|
|
|
std::vector<const DefinedData *> DefinedFakeGlobals;
|
|
|
|
std::vector<InputGlobal *> InputGlobals;
|
2018-02-21 18:29:23 +00:00
|
|
|
std::vector<InputFunction *> InputFunctions;
|
2018-12-08 06:17:43 +00:00
|
|
|
std::vector<InputEvent *> InputEvents;
|
2018-02-14 18:27:59 +00:00
|
|
|
std::vector<const FunctionSymbol *> IndirectFunctions;
|
2018-02-23 05:08:53 +00:00
|
|
|
std::vector<const Symbol *> SymtabEntries;
|
|
|
|
std::vector<WasmInitEntry> InitFunctions;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-04-10 16:12:49 +00:00
|
|
|
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
|
2018-05-04 23:14:42 +00:00
|
|
|
llvm::StringMap<SectionSymbol *> CustomSectionSymbols;
|
2018-04-10 16:12:49 +00:00
|
|
|
|
2017-11-17 18:14:09 +00: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 05:08:53 +00:00
|
|
|
uint32_t NumImports = ImportedSymbols.size();
|
2017-11-17 18:14:09 +00:00
|
|
|
if (Config->ImportMemory)
|
|
|
|
++NumImports;
|
2018-03-28 12:53:29 +00:00
|
|
|
if (Config->ImportTable)
|
2018-03-27 17:38:51 +00:00
|
|
|
++NumImports;
|
2017-11-17 18:14:09 +00: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;
|
2019-02-04 19:13:46 +00:00
|
|
|
Import.Module = DefaultModule;
|
2017-11-17 18:14:09 +00:00
|
|
|
Import.Field = "memory";
|
|
|
|
Import.Kind = WASM_EXTERNAL_MEMORY;
|
|
|
|
Import.Memory.Flags = 0;
|
|
|
|
Import.Memory.Initial = NumMemoryPages;
|
2018-03-14 13:53:58 +00:00
|
|
|
if (MaxMemoryPages != 0) {
|
|
|
|
Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
|
|
|
Import.Memory.Maximum = MaxMemoryPages;
|
|
|
|
}
|
2018-11-06 18:02:39 +00:00
|
|
|
if (Config->SharedMemory)
|
2018-11-06 17:59:32 +00:00
|
|
|
Import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
|
2017-11-17 18:14:09 +00:00
|
|
|
writeImport(OS, Import);
|
|
|
|
}
|
|
|
|
|
2018-03-28 12:53:29 +00:00
|
|
|
if (Config->ImportTable) {
|
2018-11-15 00:37:21 +00:00
|
|
|
uint32_t TableSize = TableBase + IndirectFunctions.size();
|
2018-03-27 17:38:51 +00:00
|
|
|
WasmImport Import;
|
2019-02-04 19:13:46 +00:00
|
|
|
Import.Module = DefaultModule;
|
|
|
|
Import.Field = FunctionTableName;
|
2018-03-27 17:38:51 +00:00
|
|
|
Import.Kind = WASM_EXTERNAL_TABLE;
|
2019-01-08 06:25:55 +00:00
|
|
|
Import.Table.ElemType = WASM_TYPE_FUNCREF;
|
2018-12-03 22:37:55 +00:00
|
|
|
Import.Table.Limits = {0, TableSize, 0};
|
2018-03-27 17:38:51 +00:00
|
|
|
writeImport(OS, Import);
|
|
|
|
}
|
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
for (const Symbol *Sym : ImportedSymbols) {
|
2017-11-17 18:14:09 +00:00
|
|
|
WasmImport Import;
|
2019-02-07 22:00:48 +00:00
|
|
|
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();
|
2019-02-04 19:13:46 +00:00
|
|
|
Import.Module = DefaultModule;
|
2019-02-07 22:00:48 +00:00
|
|
|
}
|
2019-02-01 02:29:57 +00:00
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
|
|
|
|
Import.Kind = WASM_EXTERNAL_FUNCTION;
|
2018-12-08 06:17:43 +00:00
|
|
|
Import.SigIndex = lookupType(*FunctionSym->Signature);
|
2019-03-12 21:53:23 +00:00
|
|
|
} else if (auto *DataSym = dyn_cast<UndefinedData>(Sym)) {
|
|
|
|
Import.Kind = WASM_EXTERNAL_GLOBAL;
|
|
|
|
Import.Global = {WASM_TYPE_I32, true};
|
2018-12-08 06:17:43 +00:00
|
|
|
} else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
|
2018-02-23 05:08:53 +00:00
|
|
|
Import.Kind = WASM_EXTERNAL_GLOBAL;
|
|
|
|
Import.Global = *GlobalSym->getGlobalType();
|
2018-12-08 06:17:43 +00:00
|
|
|
} else {
|
|
|
|
auto *EventSym = cast<EventSymbol>(Sym);
|
|
|
|
Import.Kind = WASM_EXTERNAL_EVENT;
|
|
|
|
Import.Event.Attribute = EventSym->getEventType()->Attribute;
|
|
|
|
Import.Event.SigIndex = lookupType(*EventSym->Signature);
|
2018-02-23 05:08:53 +00:00
|
|
|
}
|
2017-11-17 18:14:09 +00: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-19 19:56:27 +00:00
|
|
|
for (const WasmSignature *Sig : Types)
|
2017-11-17 18:14:09 +00:00
|
|
|
writeSig(OS, *Sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createFunctionSection() {
|
2018-02-21 18:29:23 +00:00
|
|
|
if (InputFunctions.empty())
|
2017-11-17 18:14:09 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-02-21 18:29:23 +00:00
|
|
|
writeUleb128(OS, InputFunctions.size(), "function count");
|
|
|
|
for (const InputFunction *Func : InputFunctions)
|
2018-01-10 19:18:22 +00:00
|
|
|
writeUleb128(OS, lookupType(Func->Signature), "sig index");
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createMemorySection() {
|
|
|
|
if (Config->ImportMemory)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-03-14 13:53:58 +00:00
|
|
|
bool HasMax = MaxMemoryPages != 0;
|
2017-11-17 18:14:09 +00:00
|
|
|
writeUleb128(OS, 1, "memory count");
|
2018-11-06 18:02:39 +00:00
|
|
|
unsigned Flags = 0;
|
|
|
|
if (HasMax)
|
|
|
|
Flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
2018-11-06 17:59:32 +00:00
|
|
|
if (Config->SharedMemory)
|
|
|
|
Flags |= WASM_LIMITS_FLAG_IS_SHARED;
|
|
|
|
writeUleb128(OS, Flags, "memory limits flags");
|
2017-11-17 18:14:09 +00:00
|
|
|
writeUleb128(OS, NumMemoryPages, "initial pages");
|
2018-03-14 13:53:58 +00:00
|
|
|
if (HasMax)
|
|
|
|
writeUleb128(OS, MaxMemoryPages, "max pages");
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createGlobalSection() {
|
2018-02-23 05:08:53 +00:00
|
|
|
unsigned NumGlobals = InputGlobals.size() + DefinedFakeGlobals.size();
|
|
|
|
if (NumGlobals == 0)
|
2017-12-07 01:51:24 +00:00
|
|
|
return;
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
writeUleb128(OS, NumGlobals, "global count");
|
|
|
|
for (const InputGlobal *G : InputGlobals)
|
|
|
|
writeGlobal(OS, G->Global);
|
|
|
|
for (const DefinedData *Sym : DefinedFakeGlobals) {
|
2017-12-05 19:05:45 +00:00
|
|
|
WasmGlobal Global;
|
2018-02-23 05:08:53 +00:00
|
|
|
Global.Type = {WASM_TYPE_I32, false};
|
2017-12-05 19:05:45 +00:00
|
|
|
Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
|
|
|
Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
|
2017-11-17 18:14:09 +00:00
|
|
|
writeGlobal(OS, Global);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 06:17:43 +00:00
|
|
|
// The event section contains a list of declared wasm events associated with the
|
|
|
|
// module. Currently the only supported event kind is exceptions. A single event
|
|
|
|
// entry represents a single event with an event tag. All C++ exceptions are
|
|
|
|
// represented by a single event. An event entry in this section contains
|
|
|
|
// information on what kind of event it is (e.g. exception) and the type of
|
|
|
|
// values contained in a single event object. (In wasm, an event can contain
|
|
|
|
// multiple values of primitive types. But for C++ exceptions, we just throw a
|
|
|
|
// pointer which is an i32 value (for wasm32 architecture), so the signature of
|
|
|
|
// C++ exception is (i32)->(void), because all event types are assumed to have
|
|
|
|
// void return type to share WasmSignature with functions.)
|
|
|
|
void Writer::createEventSection() {
|
|
|
|
unsigned NumEvents = InputEvents.size();
|
|
|
|
if (NumEvents == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_EVENT);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
|
|
|
writeUleb128(OS, NumEvents, "event count");
|
|
|
|
for (InputEvent *E : InputEvents) {
|
|
|
|
E->Event.Type.SigIndex = lookupType(E->Signature);
|
|
|
|
writeEvent(OS, E->Event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
void Writer::createTableSection() {
|
2018-03-28 12:53:29 +00:00
|
|
|
if (Config->ImportTable)
|
2018-03-27 17:38:51 +00: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-11 22:00:56 +00: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-11-15 00:37:21 +00:00
|
|
|
uint32_t TableSize = TableBase + IndirectFunctions.size();
|
2017-12-11 22:00:56 +00:00
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
|
|
|
writeUleb128(OS, 1, "table count");
|
2018-03-27 17:38:51 +00:00
|
|
|
WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
|
2019-01-08 06:25:55 +00:00
|
|
|
writeTableType(OS, WasmTable{WASM_TYPE_FUNCREF, Limits});
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createExportSection() {
|
2018-05-10 18:10:34 +00:00
|
|
|
if (!Exports.size())
|
2017-11-17 18:14:09 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT);
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
2018-05-10 18:10:34 +00:00
|
|
|
writeUleb128(OS, Exports.size(), "export count");
|
|
|
|
for (const WasmExport &Export : Exports)
|
2017-12-07 01:51:24 +00:00
|
|
|
writeExport(OS, Export);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2018-05-04 23:14:42 +00: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
|
2019-01-17 02:29:41 +00:00
|
|
|
if (Name == "linking" || Name == "name" || Name == "producers" ||
|
|
|
|
Name.startswith("reloc."))
|
2018-05-04 23:14:42 +00:00
|
|
|
continue;
|
|
|
|
// .. or it is a debug section
|
|
|
|
if (StripDebug && Name.startswith(".debug_"))
|
|
|
|
continue;
|
|
|
|
CustomSectionMapping[Name].push_back(Section);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 16:12:49 +00:00
|
|
|
void Writer::createCustomSections() {
|
|
|
|
log("createCustomSections");
|
|
|
|
for (auto &Pair : CustomSectionMapping) {
|
|
|
|
StringRef Name = Pair.first();
|
2018-05-04 23:14:42 +00:00
|
|
|
|
|
|
|
auto P = CustomSectionSymbols.find(Name);
|
|
|
|
if (P != CustomSectionSymbols.end()) {
|
|
|
|
uint32_t SectionIndex = OutputSections.size();
|
|
|
|
P->second->setOutputSectionIndex(SectionIndex);
|
|
|
|
}
|
|
|
|
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
|
2018-04-10 16:12:49 +00:00
|
|
|
OutputSections.push_back(make<CustomSection>(Name, Pair.second));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
void Writer::createElemSection() {
|
2017-12-11 22:00:56 +00:00
|
|
|
if (IndirectFunctions.empty())
|
2017-11-17 18:14:09 +00: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;
|
2018-11-15 00:37:21 +00:00
|
|
|
if (Config->Pic) {
|
2019-01-08 06:25:55 +00:00
|
|
|
InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
|
2018-11-15 18:15:54 +00:00
|
|
|
InitExpr.Value.Global = WasmSym::TableBase->getGlobalIndex();
|
2018-11-15 00:37:21 +00:00
|
|
|
} else {
|
|
|
|
InitExpr.Opcode = WASM_OPCODE_I32_CONST;
|
|
|
|
InitExpr.Value.Int32 = TableBase;
|
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
writeInitExpr(OS, InitExpr);
|
2017-12-11 22:00:56 +00:00
|
|
|
writeUleb128(OS, IndirectFunctions.size(), "elem count");
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-11-15 00:37:21 +00:00
|
|
|
uint32_t TableIndex = TableBase;
|
2018-02-14 18:27:59 +00:00
|
|
|
for (const FunctionSymbol *Sym : IndirectFunctions) {
|
2017-12-11 22:00:56 +00:00
|
|
|
assert(Sym->getTableIndex() == TableIndex);
|
2018-03-12 19:56:23 +00:00
|
|
|
writeUleb128(OS, Sym->getFunctionIndex(), "function index");
|
2017-12-11 22:00:56 +00:00
|
|
|
++TableIndex;
|
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createCodeSection() {
|
2018-02-21 18:29:23 +00:00
|
|
|
if (InputFunctions.empty())
|
2017-11-17 18:14:09 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
log("createCodeSection");
|
|
|
|
|
2018-02-21 18:29:23 +00:00
|
|
|
auto Section = make<CodeSection>(InputFunctions);
|
2017-11-17 18:14:09 +00: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-19 19:56:27 +00:00
|
|
|
// Create relocations sections in the final output.
|
2017-11-17 18:14:09 +00: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-24 23:09:57 +00:00
|
|
|
for (size_t I = 0; I < OrigSize; I++) {
|
|
|
|
OutputSection *OSec = OutputSections[I];
|
2018-02-28 00:01:31 +00:00
|
|
|
uint32_t Count = OSec->numRelocations();
|
2017-11-17 18:14:09 +00:00
|
|
|
if (!Count)
|
|
|
|
continue;
|
|
|
|
|
2018-02-28 00:01:31 +00:00
|
|
|
StringRef Name;
|
|
|
|
if (OSec->Type == WASM_SEC_DATA)
|
|
|
|
Name = "reloc.DATA";
|
|
|
|
else if (OSec->Type == WASM_SEC_CODE)
|
|
|
|
Name = "reloc.CODE";
|
2018-05-04 23:14:42 +00:00
|
|
|
else if (OSec->Type == WASM_SEC_CUSTOM)
|
|
|
|
Name = Saver.save("reloc." + OSec->Name);
|
2017-11-17 18:14:09 +00:00
|
|
|
else
|
2018-05-04 23:14:42 +00:00
|
|
|
llvm_unreachable(
|
|
|
|
"relocations only supported for code, data, or custom sections");
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-02-28 00:01:31 +00:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name);
|
2017-11-17 18:14:09 +00:00
|
|
|
raw_ostream &OS = Section->getStream();
|
2018-04-24 23:09:57 +00:00
|
|
|
writeUleb128(OS, I, "reloc section");
|
2017-11-17 18:14:09 +00:00
|
|
|
writeUleb128(OS, Count, "reloc count");
|
2018-02-28 00:01:31 +00:00
|
|
|
OSec->writeRelocations(OS);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 00:28:07 +00: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;
|
2019-02-07 22:00:48 +00:00
|
|
|
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;
|
|
|
|
}
|
2018-02-28 00:28:07 +00:00
|
|
|
return Flags;
|
|
|
|
}
|
|
|
|
|
2018-02-28 00:52:42 +00: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 03:38:14 +00:00
|
|
|
writeUleb128(To, Type, "subsection type");
|
|
|
|
writeUleb128(To, Body.size(), "subsection size");
|
2018-02-28 00:52:42 +00:00
|
|
|
To.write(Body.data(), Body.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint32_t Type;
|
|
|
|
std::string Body;
|
|
|
|
|
|
|
|
public:
|
|
|
|
raw_string_ostream OS{Body};
|
|
|
|
};
|
|
|
|
|
2018-11-15 00:37:21 +00:00
|
|
|
// Create the custom "dylink" section containing information for the dynamic
|
|
|
|
// linker.
|
|
|
|
// See
|
|
|
|
// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
|
|
|
|
void Writer::createDylinkSection() {
|
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "dylink");
|
|
|
|
raw_ostream &OS = Section->getStream();
|
|
|
|
|
|
|
|
writeUleb128(OS, MemSize, "MemSize");
|
2019-01-16 01:43:21 +00:00
|
|
|
writeUleb128(OS, MemAlign, "MemAlign");
|
2018-11-15 00:37:21 +00:00
|
|
|
writeUleb128(OS, IndirectFunctions.size(), "TableSize");
|
|
|
|
writeUleb128(OS, 0, "TableAlign");
|
2019-03-13 21:29:20 +00:00
|
|
|
writeUleb128(OS, Symtab->SharedFiles.size(), "Needed");
|
|
|
|
for (auto *SO : Symtab->SharedFiles)
|
|
|
|
writeStr(OS, llvm::sys::path::filename(SO->getName()), "so name");
|
2018-11-15 00:37:21 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 00:53:21 +00:00
|
|
|
// Create the custom "linking" section containing linker metadata.
|
2017-11-17 18:14:09 +00: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-26 18:17:21 +00:00
|
|
|
writeUleb128(OS, WasmMetadataVersion, "Version");
|
2017-12-19 17:09:45 +00:00
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
if (!SymtabEntries.empty()) {
|
2018-02-28 00:39:30 +00:00
|
|
|
SubSection Sub(WASM_SYMBOL_TABLE);
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols");
|
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
for (const Symbol *Sym : SymtabEntries) {
|
|
|
|
assert(Sym->isDefined() || Sym->isUndefined());
|
|
|
|
WasmSymbolType Kind = Sym->getWasmType();
|
2018-02-28 00:28:07 +00:00
|
|
|
uint32_t Flags = getWasmFlags(Sym);
|
|
|
|
|
2018-03-01 18:06:39 +00:00
|
|
|
writeU8(Sub.OS, Kind, "sym kind");
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, Flags, "sym flags");
|
2018-02-28 00:28:07 +00:00
|
|
|
|
2018-03-12 19:56:23 +00:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
|
|
|
|
writeUleb128(Sub.OS, F->getFunctionIndex(), "index");
|
2019-02-07 22:00:48 +00:00
|
|
|
if (Sym->isDefined() ||
|
|
|
|
(Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
|
2018-02-28 00:52:42 +00:00
|
|
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
2018-03-12 19:56:23 +00:00
|
|
|
} else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {
|
|
|
|
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
|
2019-02-07 22:00:48 +00:00
|
|
|
if (Sym->isDefined() ||
|
|
|
|
(Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
|
2018-03-12 19:56:23 +00:00
|
|
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
2018-12-08 06:17:43 +00:00
|
|
|
} else if (auto *E = dyn_cast<EventSymbol>(Sym)) {
|
|
|
|
writeUleb128(Sub.OS, E->getEventIndex(), "index");
|
2019-02-07 22:00:48 +00:00
|
|
|
if (Sym->isDefined() ||
|
|
|
|
(Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
|
2018-12-08 06:17:43 +00:00
|
|
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
2018-05-05 10:53:31 +00:00
|
|
|
} else if (isa<DataSymbol>(Sym)) {
|
2018-02-28 00:52:42 +00:00
|
|
|
writeStr(Sub.OS, Sym->getName(), "sym name");
|
2018-02-23 05:08:53 +00:00
|
|
|
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
|
|
|
|
writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(),
|
2018-02-28 00:39:30 +00:00
|
|
|
"data offset");
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, DataSym->getSize(), "data size");
|
2018-02-23 05:08:53 +00:00
|
|
|
}
|
2018-05-04 23:14:42 +00:00
|
|
|
} else {
|
|
|
|
auto *S = cast<SectionSymbol>(Sym);
|
|
|
|
writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index");
|
2018-02-23 05:08:53 +00:00
|
|
|
}
|
2018-01-18 23:40:49 +00:00
|
|
|
}
|
2018-02-28 00:28:07 +00:00
|
|
|
|
2018-02-28 00:52:42 +00:00
|
|
|
Sub.writeTo(OS);
|
2018-01-18 23:40:49 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 17:09:45 +00:00
|
|
|
if (Segments.size()) {
|
2018-02-28 00:39:30 +00:00
|
|
|
SubSection Sub(WASM_SEGMENT_INFO);
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, Segments.size(), "num data segments");
|
2017-11-17 18:14:09 +00:00
|
|
|
for (const OutputSegment *S : Segments) {
|
2018-02-28 00:52:42 +00:00
|
|
|
writeStr(Sub.OS, S->Name, "segment name");
|
|
|
|
writeUleb128(Sub.OS, S->Alignment, "alignment");
|
|
|
|
writeUleb128(Sub.OS, 0, "flags");
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2018-02-28 00:52:42 +00:00
|
|
|
Sub.writeTo(OS);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2017-12-19 17:09:45 +00:00
|
|
|
|
|
|
|
if (!InitFunctions.empty()) {
|
2018-02-28 00:39:30 +00:00
|
|
|
SubSection Sub(WASM_INIT_FUNCS);
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, InitFunctions.size(), "num init functions");
|
2018-02-23 05:08:53 +00:00
|
|
|
for (const WasmInitEntry &F : InitFunctions) {
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, F.Priority, "priority");
|
|
|
|
writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index");
|
2017-12-19 17:09:45 +00:00
|
|
|
}
|
2018-02-28 00:52:42 +00:00
|
|
|
Sub.writeTo(OS);
|
2017-12-19 17:09:45 +00:00
|
|
|
}
|
2018-01-12 22:25:17 +00:00
|
|
|
|
2018-03-07 13:28:16 +00:00
|
|
|
struct ComdatEntry {
|
|
|
|
unsigned Kind;
|
|
|
|
uint32_t Index;
|
|
|
|
};
|
|
|
|
std::map<StringRef, std::vector<ComdatEntry>> Comdats;
|
2018-01-12 22:25:17 +00:00
|
|
|
|
2018-02-21 18:29:23 +00:00
|
|
|
for (const InputFunction *F : InputFunctions) {
|
2018-03-14 15:45:11 +00:00
|
|
|
StringRef Comdat = F->getComdatName();
|
2018-01-12 22:25:17 +00:00
|
|
|
if (!Comdat.empty())
|
|
|
|
Comdats[Comdat].emplace_back(
|
2018-03-12 19:56:23 +00:00
|
|
|
ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()});
|
2018-01-12 22:25:17 +00:00
|
|
|
}
|
|
|
|
for (uint32_t I = 0; I < Segments.size(); ++I) {
|
2018-01-13 15:57:48 +00:00
|
|
|
const auto &InputSegments = Segments[I]->InputSegments;
|
|
|
|
if (InputSegments.empty())
|
|
|
|
continue;
|
2018-03-14 15:45:11 +00:00
|
|
|
StringRef Comdat = InputSegments[0]->getComdatName();
|
2018-01-13 15:59:53 +00:00
|
|
|
#ifndef NDEBUG
|
2018-01-13 15:57:48 +00:00
|
|
|
for (const InputSegment *IS : InputSegments)
|
2018-03-14 15:45:11 +00:00
|
|
|
assert(IS->getComdatName() == Comdat);
|
2018-01-13 15:59:53 +00:00
|
|
|
#endif
|
2018-01-12 22:25:17 +00:00
|
|
|
if (!Comdat.empty())
|
|
|
|
Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Comdats.empty()) {
|
2018-02-28 00:39:30 +00:00
|
|
|
SubSection Sub(WASM_COMDAT_INFO);
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, Comdats.size(), "num comdats");
|
2018-01-12 22:25:17 +00:00
|
|
|
for (const auto &C : Comdats) {
|
2018-02-28 00:52:42 +00: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-12 22:25:17 +00:00
|
|
|
for (const ComdatEntry &Entry : C.second) {
|
2018-03-01 18:06:39 +00:00
|
|
|
writeU8(Sub.OS, Entry.Kind, "entry kind");
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, Entry.Index, "entry index");
|
2018-01-12 22:25:17 +00:00
|
|
|
}
|
|
|
|
}
|
2018-02-28 00:52:42 +00:00
|
|
|
Sub.writeTo(OS);
|
2018-01-12 22:25:17 +00:00
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the custom "name" section containing debug symbol names.
|
|
|
|
void Writer::createNameSection() {
|
2018-02-23 05:08:53 +00:00
|
|
|
unsigned NumNames = NumImportedFunctions;
|
2018-02-21 18:29:23 +00:00
|
|
|
for (const InputFunction *F : InputFunctions)
|
2018-04-20 17:09:18 +00:00
|
|
|
if (!F->getName().empty() || !F->getDebugName().empty())
|
2018-01-17 20:19:04 +00:00
|
|
|
++NumNames;
|
2018-01-12 18:35:13 +00:00
|
|
|
|
2018-01-17 20:19:04 +00:00
|
|
|
if (NumNames == 0)
|
|
|
|
return;
|
2018-01-12 18:35:13 +00:00
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name");
|
|
|
|
|
2018-02-28 00:39:30 +00:00
|
|
|
SubSection Sub(WASM_NAMES_FUNCTION);
|
2018-02-28 00:52:42 +00:00
|
|
|
writeUleb128(Sub.OS, NumNames, "name count");
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
// Names must appear in function index order. As it happens ImportedSymbols
|
|
|
|
// and InputFunctions are numbered in order with imported functions coming
|
2018-01-17 20:19:04 +00:00
|
|
|
// first.
|
2018-02-23 05:08:53 +00:00
|
|
|
for (const Symbol *S : ImportedSymbols) {
|
2018-03-12 19:56:23 +00:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(S)) {
|
|
|
|
writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
|
2018-11-09 16:57:41 +00:00
|
|
|
writeStr(Sub.OS, toString(*S), "symbol name");
|
2018-03-12 19:56:23 +00:00
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2018-02-21 18:29:23 +00:00
|
|
|
for (const InputFunction *F : InputFunctions) {
|
2018-01-17 20:19:04 +00:00
|
|
|
if (!F->getName().empty()) {
|
2018-03-12 19:56:23 +00:00
|
|
|
writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
|
2018-04-20 17:09:18 +00:00
|
|
|
if (!F->getDebugName().empty()) {
|
|
|
|
writeStr(Sub.OS, F->getDebugName(), "symbol name");
|
|
|
|
} else {
|
2018-11-09 16:57:41 +00:00
|
|
|
writeStr(Sub.OS, maybeDemangleSymbol(F->getName()), "symbol name");
|
2018-04-20 17:09:18 +00:00
|
|
|
}
|
2018-01-17 20:19:04 +00:00
|
|
|
}
|
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-02-28 00:52:42 +00:00
|
|
|
Sub.writeTo(Section->getStream());
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2019-01-17 02:29:41 +00:00
|
|
|
void Writer::createProducersSection() {
|
|
|
|
SmallVector<std::pair<std::string, std::string>, 8> Languages;
|
|
|
|
SmallVector<std::pair<std::string, std::string>, 8> Tools;
|
|
|
|
SmallVector<std::pair<std::string, std::string>, 8> SDKs;
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
const WasmProducerInfo &Info = File->getWasmObj()->getProducerInfo();
|
|
|
|
for (auto &Producers : {std::make_pair(&Info.Languages, &Languages),
|
|
|
|
std::make_pair(&Info.Tools, &Tools),
|
|
|
|
std::make_pair(&Info.SDKs, &SDKs)})
|
|
|
|
for (auto &Producer : *Producers.first)
|
|
|
|
if (Producers.second->end() ==
|
|
|
|
std::find_if(Producers.second->begin(), Producers.second->end(),
|
|
|
|
[&](std::pair<std::string, std::string> Seen) {
|
|
|
|
return Seen.first == Producer.first;
|
|
|
|
}))
|
|
|
|
Producers.second->push_back(Producer);
|
|
|
|
}
|
|
|
|
int FieldCount =
|
|
|
|
int(!Languages.empty()) + int(!Tools.empty()) + int(!SDKs.empty());
|
|
|
|
if (FieldCount == 0)
|
|
|
|
return;
|
|
|
|
SyntheticSection *Section =
|
|
|
|
createSyntheticSection(WASM_SEC_CUSTOM, "producers");
|
|
|
|
auto &OS = Section->getStream();
|
|
|
|
writeUleb128(OS, FieldCount, "field count");
|
|
|
|
for (auto &Field :
|
|
|
|
{std::make_pair("language", Languages),
|
|
|
|
std::make_pair("processed-by", Tools), std::make_pair("sdk", SDKs)}) {
|
|
|
|
if (Field.second.empty())
|
|
|
|
continue;
|
|
|
|
writeStr(OS, Field.first, "field name");
|
|
|
|
writeUleb128(OS, Field.second.size(), "number of entries");
|
|
|
|
for (auto &Entry : Field.second) {
|
|
|
|
writeStr(OS, Entry.first, "producer name");
|
|
|
|
writeStr(OS, Entry.second, "producer version");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-17 18:14:09 +00: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 00:53:21 +00:00
|
|
|
// to each of the input data sections as well as the explicit stack region.
|
2018-05-03 17:21:53 +00:00
|
|
|
// The default memory layout is as follows, from low to high.
|
|
|
|
//
|
2018-02-02 22:59:56 +00:00
|
|
|
// - initialized data (starting at Config->GlobalBase)
|
|
|
|
// - BSS data (not currently implemented in llvm)
|
|
|
|
// - explicit stack (Config->ZStackSize)
|
|
|
|
// - heap start / unallocated
|
2018-05-03 17:21:53 +00:00
|
|
|
//
|
|
|
|
// The --stack-first option means that stack is placed before any static data.
|
2018-08-29 21:03:16 +00:00
|
|
|
// 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-17 18:14:09 +00:00
|
|
|
void Writer::layoutMemory() {
|
2018-05-03 17:21:53 +00:00
|
|
|
createOutputSegments();
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
uint32_t MemoryPtr = 0;
|
|
|
|
|
2018-05-03 17:21:53 +00:00
|
|
|
auto PlaceStack = [&]() {
|
2018-11-15 00:37:21 +00:00
|
|
|
if (Config->Relocatable || Config->Shared)
|
2018-05-03 17:21:53 +00:00
|
|
|
return;
|
2019-02-04 19:13:46 +00:00
|
|
|
MemoryPtr = alignTo(MemoryPtr, StackAlignment);
|
|
|
|
if (Config->ZStackSize != alignTo(Config->ZStackSize, StackAlignment))
|
|
|
|
error("stack size must be " + Twine(StackAlignment) + "-byte aligned");
|
2018-05-03 17:21:53 +00:00
|
|
|
log("mem: stack size = " + Twine(Config->ZStackSize));
|
|
|
|
log("mem: stack base = " + Twine(MemoryPtr));
|
|
|
|
MemoryPtr += Config->ZStackSize;
|
2018-11-15 18:15:54 +00:00
|
|
|
auto *SP = cast<DefinedGlobal>(WasmSym::StackPointer);
|
|
|
|
SP->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
|
2018-05-03 17:21:53 +00:00
|
|
|
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-17 18:14:09 +00:00
|
|
|
|
2018-02-02 22:59:56 +00:00
|
|
|
// Arbitrarily set __dso_handle handle to point to the start of the data
|
|
|
|
// segments.
|
|
|
|
if (WasmSym::DsoHandle)
|
2018-05-03 17:21:53 +00:00
|
|
|
WasmSym::DsoHandle->setVirtualAddress(DataStart);
|
2018-02-02 22:59:56 +00:00
|
|
|
|
2018-11-15 00:37:21 +00:00
|
|
|
MemAlign = 0;
|
2017-11-17 18:14:09 +00:00
|
|
|
for (OutputSegment *Seg : Segments) {
|
2018-11-15 00:37:21 +00:00
|
|
|
MemAlign = std::max(MemAlign, Seg->Alignment);
|
2019-01-17 22:09:09 +00:00
|
|
|
MemoryPtr = alignTo(MemoryPtr, 1ULL << Seg->Alignment);
|
2017-11-17 18:14:09 +00:00
|
|
|
Seg->StartVA = MemoryPtr;
|
2018-03-14 13:50:20 +00:00
|
|
|
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name,
|
|
|
|
MemoryPtr, Seg->Size, Seg->Alignment));
|
2017-11-17 18:14:09 +00:00
|
|
|
MemoryPtr += Seg->Size;
|
|
|
|
}
|
|
|
|
|
2018-02-02 22:59:56 +00:00
|
|
|
// TODO: Add .bss space here.
|
2018-02-07 03:04:53 +00:00
|
|
|
if (WasmSym::DataEnd)
|
|
|
|
WasmSym::DataEnd->setVirtualAddress(MemoryPtr);
|
2018-02-02 22:59:56 +00:00
|
|
|
|
2018-05-03 17:21:53 +00:00
|
|
|
log("mem: static data = " + Twine(MemoryPtr - DataStart));
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-11-15 18:15:54 +00:00
|
|
|
if (Config->Shared) {
|
|
|
|
MemSize = MemoryPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-03 17:21:53 +00:00
|
|
|
if (!Config->StackFirst)
|
|
|
|
PlaceStack();
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2018-05-03 17:21:53 +00: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-02 22:59:56 +00:00
|
|
|
WasmSym::HeapBase->setVirtualAddress(MemoryPtr);
|
2018-03-14 13:50:20 +00:00
|
|
|
log("mem: heap base = " + Twine(MemoryPtr));
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 13:53:58 +00: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;
|
|
|
|
}
|
2018-11-15 00:37:21 +00:00
|
|
|
MemSize = MemoryPtr;
|
|
|
|
NumMemoryPages = alignTo(MemoryPtr, WasmPageSize) / WasmPageSize;
|
2018-03-14 13:50:20 +00:00
|
|
|
log("mem: total pages = " + Twine(NumMemoryPages));
|
2018-03-14 13:53:58 +00: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-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SyntheticSection *Writer::createSyntheticSection(uint32_t Type,
|
2018-01-10 19:18:22 +00:00
|
|
|
StringRef Name) {
|
2017-11-17 18:14:09 +00:00
|
|
|
auto Sec = make<SyntheticSection>(Type, Name);
|
2017-12-20 05:14:48 +00:00
|
|
|
log("createSection: " + toString(*Sec));
|
2017-11-17 18:14:09 +00:00
|
|
|
OutputSections.push_back(Sec);
|
|
|
|
return Sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createSections() {
|
|
|
|
// Known sections
|
2018-11-15 00:37:21 +00:00
|
|
|
if (Config->Pic)
|
|
|
|
createDylinkSection();
|
2017-11-17 18:14:09 +00:00
|
|
|
createTypeSection();
|
|
|
|
createImportSection();
|
|
|
|
createFunctionSection();
|
|
|
|
createTableSection();
|
|
|
|
createMemorySection();
|
|
|
|
createGlobalSection();
|
2018-12-08 06:17:43 +00:00
|
|
|
createEventSection();
|
2017-11-17 18:14:09 +00:00
|
|
|
createExportSection();
|
|
|
|
createElemSection();
|
|
|
|
createCodeSection();
|
|
|
|
createDataSection();
|
2018-04-10 16:12:49 +00:00
|
|
|
createCustomSections();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
// Custom sections
|
2018-02-27 23:58:03 +00:00
|
|
|
if (Config->Relocatable) {
|
|
|
|
createLinkingSection();
|
2018-03-05 12:33:58 +00:00
|
|
|
createRelocSections();
|
2018-02-27 23:58:03 +00:00
|
|
|
}
|
2019-01-17 02:29:41 +00:00
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
if (!Config->StripDebug && !Config->StripAll)
|
|
|
|
createNameSection();
|
|
|
|
|
2019-01-17 02:29:41 +00:00
|
|
|
if (!Config->StripAll)
|
|
|
|
createProducersSection();
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
for (OutputSection *S : OutputSections) {
|
|
|
|
S->setOffset(FileSize);
|
|
|
|
S->finalizeContents();
|
|
|
|
FileSize += S->getSize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::calculateImports() {
|
2017-12-15 19:23:49 +00:00
|
|
|
for (Symbol *Sym : Symtab->getSymbols()) {
|
2018-02-23 05:08:53 +00:00
|
|
|
if (!Sym->isUndefined())
|
|
|
|
continue;
|
|
|
|
if (Sym->isWeak() && !Config->Relocatable)
|
2017-12-15 19:23:49 +00:00
|
|
|
continue;
|
2018-04-20 17:18:06 +00:00
|
|
|
if (!Sym->isLive())
|
|
|
|
continue;
|
2018-05-30 18:07:52 +00:00
|
|
|
if (!Sym->IsUsedInRegularObj)
|
|
|
|
continue;
|
2019-03-12 21:53:23 +00:00
|
|
|
// In relocatable output we don't generate imports for data symbols.
|
|
|
|
// These live only in the symbol table.
|
|
|
|
if (Config->Relocatable && isa<DataSymbol>(Sym))
|
|
|
|
continue;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
|
2018-02-23 05:08:53 +00:00
|
|
|
ImportedSymbols.emplace_back(Sym);
|
2018-03-12 19:56:23 +00:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
|
|
|
F->setFunctionIndex(NumImportedFunctions++);
|
2018-12-08 06:17:43 +00:00
|
|
|
else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
|
|
|
|
G->setGlobalIndex(NumImportedGlobals++);
|
2019-03-12 21:53:23 +00:00
|
|
|
else if (auto *D = dyn_cast<UndefinedData>(Sym))
|
|
|
|
D->setGlobalIndex(NumImportedGlobals++);
|
2018-02-23 05:08:53 +00:00
|
|
|
else
|
2018-12-08 06:17:43 +00:00
|
|
|
cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-18 23:40:49 +00:00
|
|
|
void Writer::calculateExports() {
|
2018-02-23 05:08:53 +00:00
|
|
|
if (Config->Relocatable)
|
|
|
|
return;
|
|
|
|
|
2018-05-10 18:10:34 +00:00
|
|
|
if (!Config->Relocatable && !Config->ImportMemory)
|
|
|
|
Exports.push_back(WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
|
|
|
|
|
|
|
|
if (!Config->Relocatable && Config->ExportTable)
|
2019-02-04 19:13:46 +00:00
|
|
|
Exports.push_back(WasmExport{FunctionTableName, WASM_EXTERNAL_TABLE, 0});
|
2018-05-10 18:10:34 +00:00
|
|
|
|
|
|
|
unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
|
|
|
|
|
2018-03-01 09:38:02 +00:00
|
|
|
for (Symbol *Sym : Symtab->getSymbols()) {
|
2018-06-28 17:04:58 +00:00
|
|
|
if (!Sym->isExported())
|
2018-03-01 09:38:02 +00:00
|
|
|
continue;
|
2018-02-23 05:08:53 +00:00
|
|
|
if (!Sym->isLive())
|
2018-03-01 09:38:02 +00:00
|
|
|
continue;
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2018-05-10 18:10:34 +00: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)) {
|
2018-06-07 01:27:07 +00:00
|
|
|
// TODO(sbc): Remove this check once to mutable global proposal is
|
|
|
|
// implement in all major browsers.
|
|
|
|
// See: https://github.com/WebAssembly/mutable-global
|
|
|
|
if (G->getGlobalType()->Mutable) {
|
|
|
|
// Only the __stack_pointer should ever be create as mutable.
|
|
|
|
assert(G == WasmSym::StackPointer);
|
|
|
|
continue;
|
|
|
|
}
|
2018-05-10 18:10:34 +00:00
|
|
|
Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
|
2018-12-08 06:17:43 +00:00
|
|
|
} else if (auto *E = dyn_cast<DefinedEvent>(Sym)) {
|
|
|
|
Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()};
|
2018-05-10 18:10:34 +00:00
|
|
|
} else {
|
|
|
|
auto *D = cast<DefinedData>(Sym);
|
2018-02-23 05:08:53 +00:00
|
|
|
DefinedFakeGlobals.emplace_back(D);
|
2018-05-10 18:10:34 +00:00
|
|
|
Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++};
|
|
|
|
}
|
|
|
|
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "Export: " << Name << "\n");
|
2018-05-10 18:10:34 +00:00
|
|
|
Exports.push_back(Export);
|
2018-03-01 09:38:02 +00:00
|
|
|
}
|
2018-02-23 05:08:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::assignSymtab() {
|
|
|
|
if (!Config->Relocatable)
|
|
|
|
return;
|
2018-01-18 23:40:49 +00:00
|
|
|
|
2018-05-04 23:14:42 +00:00
|
|
|
StringMap<uint32_t> SectionSymbolIndices;
|
|
|
|
|
2018-02-23 05:08:53 +00:00
|
|
|
unsigned SymbolIndex = SymtabEntries.size();
|
2018-05-04 23:14:42 +00:00
|
|
|
|
2019-01-30 18:55:15 +00:00
|
|
|
auto AddSymbol = [&](Symbol *Sym) {
|
|
|
|
if (auto *S = dyn_cast<SectionSymbol>(Sym)) {
|
|
|
|
StringRef Name = S->getName();
|
|
|
|
if (CustomSectionMapping.count(Name) == 0)
|
|
|
|
return;
|
2018-05-04 23:14:42 +00:00
|
|
|
|
2019-01-30 18:55:15 +00:00
|
|
|
auto SSI = SectionSymbolIndices.find(Name);
|
|
|
|
if (SSI != SectionSymbolIndices.end()) {
|
|
|
|
Sym->setOutputSymbolIndex(SSI->second);
|
|
|
|
return;
|
2018-05-04 23:14:42 +00:00
|
|
|
}
|
|
|
|
|
2019-01-30 18:55:15 +00:00
|
|
|
SectionSymbolIndices[Name] = SymbolIndex;
|
|
|
|
CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym);
|
|
|
|
|
|
|
|
Sym->markLive();
|
2018-01-18 23:40:49 +00:00
|
|
|
}
|
|
|
|
|
2019-01-30 18:55:15 +00:00
|
|
|
// (Since this is relocatable output, GC is not performed so symbols must
|
|
|
|
// be live.)
|
|
|
|
assert(Sym->isLive());
|
|
|
|
Sym->setOutputSymbolIndex(SymbolIndex++);
|
|
|
|
SymtabEntries.emplace_back(Sym);
|
|
|
|
};
|
|
|
|
|
|
|
|
for (Symbol *Sym : Symtab->getSymbols())
|
2019-03-08 21:10:48 +00:00
|
|
|
if (Sym->IsUsedInRegularObj)
|
2019-01-30 18:55:15 +00:00
|
|
|
AddSymbol(Sym);
|
|
|
|
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Local symtab entries: " << File->getName() << "\n");
|
|
|
|
for (Symbol *Sym : File->getSymbols())
|
|
|
|
if (Sym->isLocal())
|
|
|
|
AddSymbol(Sym);
|
|
|
|
}
|
2018-01-18 23:40:49 +00:00
|
|
|
}
|
|
|
|
|
2018-01-10 19:18:22 +00:00
|
|
|
uint32_t Writer::lookupType(const WasmSignature &Sig) {
|
2018-01-10 20:12:26 +00:00
|
|
|
auto It = TypeIndices.find(Sig);
|
|
|
|
if (It == TypeIndices.end()) {
|
2018-01-10 19:18:22 +00:00
|
|
|
error("type not found: " + toString(Sig));
|
2018-01-10 20:12:26 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return It->second;
|
2018-01-10 19:18:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Writer::registerType(const WasmSignature &Sig) {
|
2017-11-30 01:40:08 +00:00
|
|
|
auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
|
2018-01-10 19:18:22 +00:00
|
|
|
if (Pair.second) {
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "type " << toString(Sig) << "\n");
|
2017-11-30 01:40:08 +00:00
|
|
|
Types.push_back(&Sig);
|
2018-01-10 19:18:22 +00:00
|
|
|
}
|
2017-11-30 01:40:08 +00:00
|
|
|
return Pair.first->second;
|
|
|
|
}
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
void Writer::calculateTypes() {
|
2018-01-31 23:48:14 +00: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
|
2018-12-08 06:17:43 +00:00
|
|
|
// 4. The signatures of all imported events
|
|
|
|
// 5. The signatures of all defined events
|
2018-01-31 23:48:14 +00:00
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-01-31 23:48:14 +00: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-17 18:14:09 +00:00
|
|
|
}
|
2018-01-12 18:35:13 +00:00
|
|
|
|
2018-12-08 06:17:43 +00:00
|
|
|
for (const Symbol *Sym : ImportedSymbols) {
|
2018-02-23 05:08:53 +00:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
2018-12-08 06:17:43 +00:00
|
|
|
registerType(*F->Signature);
|
|
|
|
else if (auto *E = dyn_cast<EventSymbol>(Sym))
|
|
|
|
registerType(*E->Signature);
|
|
|
|
}
|
2018-01-31 23:48:14 +00:00
|
|
|
|
2018-02-21 18:29:23 +00:00
|
|
|
for (const InputFunction *F : InputFunctions)
|
2018-01-31 23:48:14 +00:00
|
|
|
registerType(F->Signature);
|
2018-12-08 06:17:43 +00:00
|
|
|
|
|
|
|
for (const InputEvent *E : InputEvents)
|
|
|
|
registerType(E->Signature);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2018-01-09 23:56:44 +00:00
|
|
|
void Writer::assignIndexes() {
|
2018-11-19 23:21:25 +00:00
|
|
|
assert(InputFunctions.empty());
|
|
|
|
uint32_t FunctionIndex = NumImportedFunctions;
|
2018-03-09 16:43:05 +00:00
|
|
|
auto AddDefinedFunction = [&](InputFunction *Func) {
|
|
|
|
if (!Func->Live)
|
|
|
|
return;
|
|
|
|
InputFunctions.emplace_back(Func);
|
2018-03-12 19:56:23 +00:00
|
|
|
Func->setFunctionIndex(FunctionIndex++);
|
2018-03-09 16:43:05 +00:00
|
|
|
};
|
|
|
|
|
2018-03-12 15:44:07 +00:00
|
|
|
for (InputFunction *Func : Symtab->SyntheticFunctions)
|
|
|
|
AddDefinedFunction(Func);
|
|
|
|
|
2018-01-08 23:39:11 +00:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
|
2018-03-09 16:43:05 +00:00
|
|
|
for (InputFunction *Func : File->Functions)
|
|
|
|
AddDefinedFunction(Func);
|
2018-01-09 23:56:44 +00:00
|
|
|
}
|
|
|
|
|
2018-11-15 00:37:21 +00:00
|
|
|
uint32_t TableIndex = TableBase;
|
2018-02-23 04:59:57 +00:00
|
|
|
auto HandleRelocs = [&](InputChunk *Chunk) {
|
|
|
|
if (!Chunk->Live)
|
|
|
|
return;
|
|
|
|
ObjFile *File = Chunk->File;
|
|
|
|
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
|
2018-02-23 05:08:53 +00:00
|
|
|
for (const WasmRelocation &Reloc : Chunk->getRelocations()) {
|
2019-02-04 17:49:33 +00:00
|
|
|
if (Reloc.Type == R_WASM_TABLE_INDEX_I32 ||
|
|
|
|
Reloc.Type == R_WASM_TABLE_INDEX_SLEB) {
|
2018-02-23 04:59:57 +00:00
|
|
|
FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index);
|
2018-03-12 19:56:23 +00:00
|
|
|
if (Sym->hasTableIndex() || !Sym->hasFunctionIndex())
|
2018-02-23 04:59:57 +00:00
|
|
|
continue;
|
|
|
|
Sym->setTableIndex(TableIndex++);
|
|
|
|
IndirectFunctions.emplace_back(Sym);
|
2019-02-04 17:49:33 +00:00
|
|
|
} else if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) {
|
2018-02-23 05:08:53 +00:00
|
|
|
// Mark target type as live
|
2018-02-23 04:59:57 +00:00
|
|
|
File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
|
|
|
|
File->TypeIsUsed[Reloc.Index] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-09 23:56:44 +00:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n");
|
2018-02-23 05:08:53 +00:00
|
|
|
for (InputChunk *Chunk : File->Functions)
|
2018-02-23 04:59:57 +00:00
|
|
|
HandleRelocs(Chunk);
|
2018-02-23 05:08:53 +00:00
|
|
|
for (InputChunk *Chunk : File->Segments)
|
2018-02-23 04:59:57 +00:00
|
|
|
HandleRelocs(Chunk);
|
2018-05-04 23:14:42 +00:00
|
|
|
for (auto &P : File->CustomSections)
|
|
|
|
HandleRelocs(P);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2018-11-19 23:21:25 +00:00
|
|
|
assert(InputGlobals.empty());
|
|
|
|
uint32_t GlobalIndex = NumImportedGlobals;
|
2018-02-23 05:08:53 +00:00
|
|
|
auto AddDefinedGlobal = [&](InputGlobal *Global) {
|
|
|
|
if (Global->Live) {
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
|
2018-03-12 19:56:23 +00:00
|
|
|
Global->setGlobalIndex(GlobalIndex++);
|
2018-02-23 05:08:53 +00:00
|
|
|
InputGlobals.push_back(Global);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-03-09 16:43:05 +00:00
|
|
|
for (InputGlobal *Global : Symtab->SyntheticGlobals)
|
|
|
|
AddDefinedGlobal(Global);
|
2018-02-23 05:08:53 +00:00
|
|
|
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
|
2018-02-23 05:08:53 +00:00
|
|
|
for (InputGlobal *Global : File->Globals)
|
|
|
|
AddDefinedGlobal(Global);
|
|
|
|
}
|
2018-12-08 06:17:43 +00:00
|
|
|
|
|
|
|
assert(InputEvents.empty());
|
|
|
|
uint32_t EventIndex = NumImportedEvents;
|
|
|
|
auto AddDefinedEvent = [&](InputEvent *Event) {
|
|
|
|
if (Event->Live) {
|
|
|
|
LLVM_DEBUG(dbgs() << "AddDefinedEvent: " << EventIndex << "\n");
|
|
|
|
Event->setEventIndex(EventIndex++);
|
|
|
|
InputEvents.push_back(Event);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n");
|
|
|
|
for (InputEvent *Event : File->Events)
|
|
|
|
AddDefinedEvent(Event);
|
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static StringRef getOutputDataSegmentName(StringRef Name) {
|
2018-11-15 00:37:21 +00:00
|
|
|
// With PIC code we currently only support a single data segment since
|
|
|
|
// we only have a single __memory_base to use as our base address.
|
|
|
|
if (Config->Pic)
|
|
|
|
return "data";
|
[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-10 18:23:51 +00:00
|
|
|
if (!Config->MergeDataSegments)
|
2017-11-17 18:14:09 +00:00
|
|
|
return Name;
|
2018-02-28 00:57:28 +00:00
|
|
|
if (Name.startswith(".text."))
|
|
|
|
return ".text";
|
|
|
|
if (Name.startswith(".data."))
|
|
|
|
return ".data";
|
|
|
|
if (Name.startswith(".bss."))
|
|
|
|
return ".bss";
|
2018-08-08 18:02:55 +00:00
|
|
|
if (Name.startswith(".rodata."))
|
|
|
|
return ".rodata";
|
2017-11-17 18:14:09 +00:00
|
|
|
return Name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createOutputSegments() {
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
for (InputSegment *Segment : File->Segments) {
|
2018-02-13 20:29:38 +00:00
|
|
|
if (!Segment->Live)
|
2018-01-12 22:25:17 +00:00
|
|
|
continue;
|
2017-11-17 18:14:09 +00:00
|
|
|
StringRef Name = getOutputDataSegmentName(Segment->getName());
|
|
|
|
OutputSegment *&S = SegmentMap[Name];
|
|
|
|
if (S == nullptr) {
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n");
|
2018-02-23 05:08:53 +00:00
|
|
|
S = make<OutputSegment>(Name, Segments.size());
|
2017-11-17 18:14:09 +00:00
|
|
|
Segments.push_back(S);
|
|
|
|
}
|
|
|
|
S->addInputSegment(Segment);
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-12 18:35:13 +00: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() {
|
2019-03-01 22:35:47 +00:00
|
|
|
if (!WasmSym::CallCtors->isLive())
|
|
|
|
return;
|
|
|
|
|
2018-03-02 14:48:50 +00:00
|
|
|
// First write the body's contents to a string.
|
|
|
|
std::string BodyContent;
|
2018-01-12 18:35:13 +00:00
|
|
|
{
|
2018-03-02 14:48:50 +00:00
|
|
|
raw_string_ostream OS(BodyContent);
|
2018-01-12 18:35:13 +00:00
|
|
|
writeUleb128(OS, 0, "num locals");
|
2018-02-23 05:08:53 +00:00
|
|
|
for (const WasmInitEntry &F : InitFunctions) {
|
2018-01-12 18:35:13 +00:00
|
|
|
writeU8(OS, OPCODE_CALL, "CALL");
|
2018-03-12 19:56:23 +00:00
|
|
|
writeUleb128(OS, F.Sym->getFunctionIndex(), "function index");
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
|
|
|
writeU8(OS, OPCODE_END, "END");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we know the size of the body we can create the final function body
|
2018-03-02 14:48:50 +00:00
|
|
|
std::string FunctionBody;
|
|
|
|
{
|
|
|
|
raw_string_ostream OS(FunctionBody);
|
|
|
|
writeUleb128(OS, BodyContent.size(), "function size");
|
|
|
|
OS << BodyContent;
|
|
|
|
}
|
2018-02-28 17:43:15 +00:00
|
|
|
|
2018-10-22 08:35:39 +00:00
|
|
|
ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
|
2018-03-09 16:43:05 +00:00
|
|
|
cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body);
|
2018-01-12 18:35:13 +00: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() {
|
2019-03-02 04:55:02 +00:00
|
|
|
if (!Config->Relocatable && !WasmSym::CallCtors->isLive())
|
|
|
|
return;
|
|
|
|
|
2018-01-12 18:35:13 +00:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
const WasmLinkingData &L = File->getWasmObj()->linkingData();
|
2018-03-02 14:46:54 +00:00
|
|
|
for (const WasmInitFunc &F : L.InitFunctions) {
|
|
|
|
FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol);
|
2019-03-01 22:35:47 +00:00
|
|
|
assert(Sym->isLive());
|
2018-12-08 06:17:43 +00:00
|
|
|
if (*Sym->Signature != WasmSignature{{}, {}})
|
2018-03-02 14:46:54 +00:00
|
|
|
error("invalid signature for init func: " + toString(*Sym));
|
|
|
|
InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority});
|
|
|
|
}
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
2018-02-28 00:15:59 +00:00
|
|
|
|
2018-01-12 18:35:13 +00:00
|
|
|
// Sort in order of priority (lowest first) so that they are called
|
|
|
|
// in the correct order.
|
2018-02-21 00:34:34 +00:00
|
|
|
std::stable_sort(InitFunctions.begin(), InitFunctions.end(),
|
2018-02-23 05:08:53 +00:00
|
|
|
[](const WasmInitEntry &L, const WasmInitEntry &R) {
|
2018-02-21 00:34:34 +00:00
|
|
|
return L.Priority < R.Priority;
|
|
|
|
});
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
void Writer::run() {
|
2018-11-15 00:37:21 +00:00
|
|
|
if (Config->Relocatable || Config->Pic)
|
2018-02-27 23:58:03 +00:00
|
|
|
Config->GlobalBase = 0;
|
|
|
|
|
2018-11-15 00:37:21 +00:00
|
|
|
// For PIC code the table base is assigned dynamically by the loader.
|
|
|
|
// For non-PIC, we start at 1 so that accessing table index 0 always traps.
|
|
|
|
if (!Config->Pic)
|
|
|
|
TableBase = 1;
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
log("-- calculateImports");
|
|
|
|
calculateImports();
|
2018-01-09 23:56:44 +00:00
|
|
|
log("-- assignIndexes");
|
|
|
|
assignIndexes();
|
2018-01-12 18:35:13 +00:00
|
|
|
log("-- calculateInitFunctions");
|
|
|
|
calculateInitFunctions();
|
|
|
|
if (!Config->Relocatable)
|
|
|
|
createCtorFunction();
|
2018-01-31 23:48:14 +00:00
|
|
|
log("-- calculateTypes");
|
|
|
|
calculateTypes();
|
2018-02-23 05:08:53 +00:00
|
|
|
log("-- layoutMemory");
|
|
|
|
layoutMemory();
|
|
|
|
log("-- calculateExports");
|
|
|
|
calculateExports();
|
2018-05-04 23:14:42 +00:00
|
|
|
log("-- calculateCustomSections");
|
|
|
|
calculateCustomSections();
|
2018-02-23 05:08:53 +00:00
|
|
|
log("-- assignSymtab");
|
|
|
|
assignSymtab();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
if (errorHandler().Verbose) {
|
2018-02-21 18:29:23 +00:00
|
|
|
log("Defined Functions: " + Twine(InputFunctions.size()));
|
2018-02-23 05:08:53 +00:00
|
|
|
log("Defined Globals : " + Twine(InputGlobals.size()));
|
2018-12-08 06:17:43 +00:00
|
|
|
log("Defined Events : " + Twine(InputEvents.size()));
|
2018-02-23 05:08:53 +00:00
|
|
|
log("Function Imports : " + Twine(NumImportedFunctions));
|
|
|
|
log("Global Imports : " + Twine(NumImportedGlobals));
|
2018-12-08 06:17:43 +00:00
|
|
|
log("Event Imports : " + Twine(NumImportedEvents));
|
2017-11-17 18:14:09 +00: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(); }
|