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"
|
2019-05-21 09:13:09 +00:00
|
|
|
#include "Relocations.h"
|
2017-11-17 18:14:09 +00:00
|
|
|
#include "SymbolTable.h"
|
2019-05-21 09:13:09 +00:00
|
|
|
#include "SyntheticSections.h"
|
2017-11-17 18:14:09 +00:00
|
|
|
#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"
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
#include "llvm/ADT/SmallSet.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"
|
|
|
|
|
|
|
|
#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;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// The writer writes a SymbolTable result to a file.
|
|
|
|
class Writer {
|
|
|
|
public:
|
|
|
|
void run();
|
|
|
|
|
|
|
|
private:
|
|
|
|
void openFile();
|
|
|
|
|
2019-04-04 18:40:51 +00:00
|
|
|
void createApplyRelocationsFunction();
|
|
|
|
void createCallCtorsFunction();
|
|
|
|
|
2018-01-09 23:56:44 +00:00
|
|
|
void assignIndexes();
|
2019-05-21 09:13:09 +00:00
|
|
|
void populateSymtab();
|
|
|
|
void populateProducers();
|
|
|
|
void populateTargetFeatures();
|
|
|
|
void calculateInitFunctions();
|
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();
|
2017-11-17 18:14:09 +00:00
|
|
|
void calculateTypes();
|
|
|
|
void createOutputSegments();
|
|
|
|
void layoutMemory();
|
|
|
|
void createHeader();
|
2019-05-21 09:13:09 +00:00
|
|
|
|
|
|
|
void addSection(OutputSection *Sec);
|
|
|
|
|
|
|
|
void addSections();
|
2018-04-10 16:12:49 +00:00
|
|
|
void createCustomSections();
|
2019-05-21 09:13:09 +00:00
|
|
|
void createSyntheticSections();
|
|
|
|
void finalizeSections();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
// Custom sections
|
|
|
|
void createRelocSections();
|
|
|
|
|
|
|
|
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
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
std::vector<WasmInitEntry> InitFunctions;
|
2018-04-10 16:12:49 +00:00
|
|
|
llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
|
|
|
|
|
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
|
|
|
|
|
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" ||
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
Name == "target_features" || 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-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
|
2018-04-10 16:12:49 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
OutputSection *Sec = make<CustomSection>(Name, Pair.second);
|
|
|
|
if (Config->Relocatable) {
|
|
|
|
auto *Sym = make<OutputSectionSymbol>(Sec);
|
|
|
|
Out.LinkingSec->addToSymtab(Sym);
|
|
|
|
Sec->SectionSym = Sym;
|
|
|
|
}
|
|
|
|
addSection(Sec);
|
2017-12-11 22:00:56 +00:00
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
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++) {
|
2019-05-21 09:13:09 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "check section " << I << "\n");
|
|
|
|
OutputSection *Sec = OutputSections[I];
|
|
|
|
|
|
|
|
// Count the number of needed sections.
|
|
|
|
uint32_t Count = Sec->numRelocations();
|
2017-11-17 18:14:09 +00:00
|
|
|
if (!Count)
|
|
|
|
continue;
|
|
|
|
|
2018-02-28 00:01:31 +00:00
|
|
|
StringRef Name;
|
2019-05-21 09:13:09 +00:00
|
|
|
if (Sec->Type == WASM_SEC_DATA)
|
2018-02-28 00:01:31 +00:00
|
|
|
Name = "reloc.DATA";
|
2019-05-21 09:13:09 +00:00
|
|
|
else if (Sec->Type == WASM_SEC_CODE)
|
2018-02-28 00:01:31 +00:00
|
|
|
Name = "reloc.CODE";
|
2019-05-21 09:13:09 +00:00
|
|
|
else if (Sec->Type == WASM_SEC_CUSTOM)
|
|
|
|
Name = Saver.save("reloc." + Sec->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
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
addSection(make<RelocSection>(Name, Sec));
|
2018-01-12 22:25:17 +00:00
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::populateProducers() {
|
2019-01-17 02:29:41 +00:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
const WasmProducerInfo &Info = File->getWasmObj()->getProducerInfo();
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.ProducersSec->addInfo(Info);
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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();
|
2019-05-21 09:13:09 +00:00
|
|
|
parallelForEach(OutputSections, [Buf](OutputSection *S) {
|
|
|
|
assert(S->isNeeded());
|
|
|
|
S->writeTo(Buf);
|
|
|
|
});
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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() {
|
|
|
|
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
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.DylinkSec->MemAlign = 0;
|
2017-11-17 18:14:09 +00:00
|
|
|
for (OutputSegment *Seg : Segments) {
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.DylinkSec->MemAlign = std::max(Out.DylinkSec->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) {
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.DylinkSec->MemSize = MemoryPtr;
|
2018-11-15 18:15:54 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.DylinkSec->MemSize = MemoryPtr;
|
|
|
|
Out.MemorySec->NumMemoryPages =
|
|
|
|
alignTo(MemoryPtr, WasmPageSize) / WasmPageSize;
|
|
|
|
log("mem: total pages = " + Twine(Out.MemorySec->NumMemoryPages));
|
2018-03-14 13:53:58 +00:00
|
|
|
|
2019-03-29 20:43:49 +00:00
|
|
|
// Check max if explicitly supplied or required by shared memory
|
|
|
|
if (Config->MaxMemory != 0 || Config->SharedMemory) {
|
2018-03-14 13:53:58 +00:00
|
|
|
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");
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.MemorySec->MaxMemoryPages = Config->MaxMemory / WasmPageSize;
|
|
|
|
log("mem: max pages = " + Twine(Out.MemorySec->MaxMemoryPages));
|
2018-03-14 13:53:58 +00:00
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::addSection(OutputSection *Sec) {
|
|
|
|
if (!Sec->isNeeded())
|
|
|
|
return;
|
|
|
|
log("addSection: " + toString(*Sec));
|
|
|
|
Sec->SectionIndex = OutputSections.size();
|
2017-11-17 18:14:09 +00:00
|
|
|
OutputSections.push_back(Sec);
|
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::addSections() {
|
|
|
|
addSection(Out.DylinkSec);
|
|
|
|
addSection(Out.TypeSec);
|
|
|
|
addSection(Out.ImportSec);
|
|
|
|
addSection(Out.FunctionSec);
|
|
|
|
addSection(Out.TableSec);
|
|
|
|
addSection(Out.MemorySec);
|
|
|
|
addSection(Out.GlobalSec);
|
|
|
|
addSection(Out.EventSec);
|
|
|
|
addSection(Out.ExportSec);
|
|
|
|
addSection(Out.ElemSec);
|
|
|
|
addSection(Out.DataCountSec);
|
|
|
|
|
|
|
|
addSection(make<CodeSection>(Out.FunctionSec->InputFunctions));
|
|
|
|
addSection(make<DataSection>(Segments));
|
|
|
|
|
2018-04-10 16:12:49 +00:00
|
|
|
createCustomSections();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
addSection(Out.LinkingSec);
|
2018-02-27 23:58:03 +00:00
|
|
|
if (Config->Relocatable) {
|
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
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
addSection(Out.NameSec);
|
|
|
|
addSection(Out.ProducersSec);
|
|
|
|
addSection(Out.TargetFeaturesSec);
|
|
|
|
}
|
2019-01-17 02:29:41 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::finalizeSections() {
|
2017-11-17 18:14:09 +00:00
|
|
|
for (OutputSection *S : OutputSections) {
|
|
|
|
S->setOffset(FileSize);
|
|
|
|
S->finalizeContents();
|
|
|
|
FileSize += S->getSize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::populateTargetFeatures() {
|
2019-03-26 04:11:05 +00:00
|
|
|
SmallSet<std::string, 8> Used;
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
SmallSet<std::string, 8> Required;
|
|
|
|
SmallSet<std::string, 8> Disallowed;
|
|
|
|
|
2019-03-26 04:11:05 +00:00
|
|
|
// Only infer used features if user did not specify features
|
|
|
|
bool InferFeatures = !Config->Features.hasValue();
|
|
|
|
|
|
|
|
if (!InferFeatures) {
|
|
|
|
for (auto &Feature : Config->Features.getValue())
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.TargetFeaturesSec->Features.insert(Feature);
|
2019-03-26 04:11:05 +00:00
|
|
|
// No need to read or check features
|
|
|
|
if (!Config->CheckFeatures)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
// Find the sets of used, required, and disallowed features
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
for (auto &Feature : File->getWasmObj()->getTargetFeatures()) {
|
|
|
|
switch (Feature.Prefix) {
|
|
|
|
case WASM_FEATURE_PREFIX_USED:
|
2019-03-26 04:11:05 +00:00
|
|
|
Used.insert(Feature.Name);
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
break;
|
|
|
|
case WASM_FEATURE_PREFIX_REQUIRED:
|
2019-03-26 04:11:05 +00:00
|
|
|
Used.insert(Feature.Name);
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
Required.insert(Feature.Name);
|
|
|
|
break;
|
|
|
|
case WASM_FEATURE_PREFIX_DISALLOWED:
|
|
|
|
Disallowed.insert(Feature.Name);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error("Unrecognized feature policy prefix " +
|
|
|
|
std::to_string(Feature.Prefix));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-26 04:11:05 +00:00
|
|
|
if (InferFeatures)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.TargetFeaturesSec->Features.insert(Used.begin(), Used.end());
|
2019-03-26 04:11:05 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
if (Out.TargetFeaturesSec->Features.count("atomics") && !Config->SharedMemory)
|
2019-03-29 20:43:49 +00:00
|
|
|
error("'atomics' feature is used, so --shared-memory must be used");
|
|
|
|
|
2019-03-26 04:11:05 +00:00
|
|
|
if (!Config->CheckFeatures)
|
|
|
|
return;
|
|
|
|
|
2019-03-29 20:43:49 +00:00
|
|
|
if (Disallowed.count("atomics") && Config->SharedMemory)
|
|
|
|
error(
|
|
|
|
"'atomics' feature is disallowed, so --shared-memory must not be used");
|
|
|
|
|
2019-03-26 04:11:05 +00:00
|
|
|
// Validate that used features are allowed in output
|
|
|
|
if (!InferFeatures) {
|
|
|
|
for (auto &Feature : Used) {
|
2019-05-21 09:13:09 +00:00
|
|
|
if (!Out.TargetFeaturesSec->Features.count(Feature))
|
2019-03-26 04:11:05 +00:00
|
|
|
error(Twine("Target feature '") + Feature + "' is not allowed.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
// Validate the required and disallowed constraints for each file
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
SmallSet<std::string, 8> ObjectFeatures;
|
|
|
|
for (auto &Feature : File->getWasmObj()->getTargetFeatures()) {
|
|
|
|
if (Feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED)
|
|
|
|
continue;
|
|
|
|
ObjectFeatures.insert(Feature.Name);
|
|
|
|
if (Disallowed.count(Feature.Name))
|
2019-03-26 04:11:05 +00:00
|
|
|
error(Twine("Target feature '") + Feature.Name +
|
|
|
|
"' is disallowed. Use --no-check-features to suppress.");
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
}
|
|
|
|
for (auto &Feature : Required) {
|
|
|
|
if (!ObjectFeatures.count(Feature))
|
2019-03-26 04:11:05 +00:00
|
|
|
error(Twine("Missing required target feature '") + Feature +
|
|
|
|
"'. Use --no-check-features to suppress.");
|
[WebAssembly] Target features section
Summary:
Implements a new target features section in assembly and object files
that records what features are used, required, and disallowed in
WebAssembly objects. The linker uses this information to ensure that
all objects participating in a link are feature-compatible and records
the set of used features in the output binary for use by optimizers
and other tools later in the toolchain.
The "atomics" feature is always required or disallowed to prevent
linking code with stripped atomics into multithreaded binaries. Other
features are marked used if they are enabled globally or on any
function in a module.
Future CLs will add linker flags for ignoring feature compatibility
checks and for specifying the set of allowed features, implement using
the presence of the "atomics" feature to control the type of memory
and segments in the linked binary, and add front-end flags for
relaxing the linkage policy for atomics.
Reviewers: aheejin, sbc100, dschuff
Subscribers: jgravelle-google, hiraditya, sunfish, mgrang, jfb, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59173
llvm-svn: 356610
2019-03-20 20:26:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
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-26 19:46:15 +00:00
|
|
|
// We don't generate imports for data symbols. They however can be imported
|
|
|
|
// as GOT entries.
|
|
|
|
if (isa<DataSymbol>(Sym))
|
2019-03-12 21:53:23 +00:00
|
|
|
continue;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2018-05-15 13:36:20 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.ImportSec->addImport(Sym);
|
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)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.ExportSec->Exports.push_back(
|
|
|
|
WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
|
2018-05-10 18:10:34 +00:00
|
|
|
|
|
|
|
if (!Config->Relocatable && Config->ExportTable)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.ExportSec->Exports.push_back(
|
|
|
|
WasmExport{FunctionTableName, WASM_EXTERNAL_TABLE, 0});
|
2018-05-10 18:10:34 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
unsigned FakeGlobalIndex =
|
2019-05-23 09:41:03 +00:00
|
|
|
Out.ImportSec->numImportedGlobals() + Out.GlobalSec->InputGlobals.size();
|
2018-05-10 18:10:34 +00:00
|
|
|
|
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);
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.GlobalSec->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");
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.ExportSec->Exports.push_back(Export);
|
2018-03-01 09:38:02 +00:00
|
|
|
}
|
2018-02-23 05:08:53 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::populateSymtab() {
|
2018-02-23 05:08:53 +00:00
|
|
|
if (!Config->Relocatable)
|
|
|
|
return;
|
2018-01-18 23:40:49 +00:00
|
|
|
|
2019-01-30 18:55:15 +00:00
|
|
|
for (Symbol *Sym : Symtab->getSymbols())
|
2019-03-08 21:10:48 +00:00
|
|
|
if (Sym->IsUsedInRegularObj)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.LinkingSec->addToSymtab(Sym);
|
2019-01-30 18:55:15 +00:00
|
|
|
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Local symtab entries: " << File->getName() << "\n");
|
|
|
|
for (Symbol *Sym : File->getSymbols())
|
2019-05-21 09:13:09 +00:00
|
|
|
if (Sym->isLocal() && !isa<SectionSymbol>(Sym))
|
|
|
|
Out.LinkingSec->addToSymtab(Sym);
|
2018-01-10 19:18:22 +00:00
|
|
|
}
|
2017-11-30 01:40:08 +00:00
|
|
|
}
|
|
|
|
|
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])
|
2019-05-21 09:13:09 +00:00
|
|
|
File->TypeMap[I] = Out.TypeSec->registerType(Types[I]);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2018-01-12 18:35:13 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
for (const Symbol *Sym : Out.ImportSec->ImportedSymbols) {
|
2018-02-23 05:08:53 +00:00
|
|
|
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.TypeSec->registerType(*F->Signature);
|
2018-12-08 06:17:43 +00:00
|
|
|
else if (auto *E = dyn_cast<EventSymbol>(Sym))
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.TypeSec->registerType(*E->Signature);
|
2018-12-08 06:17:43 +00:00
|
|
|
}
|
2018-01-31 23:48:14 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
for (const InputFunction *F : Out.FunctionSec->InputFunctions)
|
|
|
|
Out.TypeSec->registerType(F->Signature);
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
for (const InputEvent *E : Out.EventSec->InputEvents)
|
|
|
|
Out.TypeSec->registerType(E->Signature);
|
2019-05-10 01:52:08 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
static void scanRelocations() {
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "scanRelocations: " << File->getName() << "\n");
|
|
|
|
for (InputChunk *Chunk : File->Functions)
|
|
|
|
scanRelocations(Chunk);
|
|
|
|
for (InputChunk *Chunk : File->Segments)
|
|
|
|
scanRelocations(Chunk);
|
|
|
|
for (auto &P : File->CustomSections)
|
|
|
|
scanRelocations(P);
|
2019-03-16 01:18:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-09 23:56:44 +00:00
|
|
|
void Writer::assignIndexes() {
|
2019-05-23 09:41:03 +00:00
|
|
|
// Seal the import section, since other index spaces such as function and
|
|
|
|
// global are effected by the number of imports.
|
|
|
|
Out.ImportSec->seal();
|
2018-03-09 16:43:05 +00:00
|
|
|
|
2018-03-12 15:44:07 +00:00
|
|
|
for (InputFunction *Func : Symtab->SyntheticFunctions)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.FunctionSec->addFunction(Func);
|
2018-03-12 15:44:07 +00:00
|
|
|
|
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)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.FunctionSec->addFunction(Func);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2018-03-09 16:43:05 +00:00
|
|
|
for (InputGlobal *Global : Symtab->SyntheticGlobals)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.GlobalSec->addGlobal(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)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.GlobalSec->addGlobal(Global);
|
2018-02-23 05:08:53 +00:00
|
|
|
}
|
2018-12-08 06:17:43 +00:00
|
|
|
|
|
|
|
for (ObjFile *File : Symtab->ObjectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n");
|
|
|
|
for (InputEvent *Event : File->Events)
|
2019-05-21 09:13:09 +00:00
|
|
|
Out.EventSec->addEvent(Event);
|
2018-12-08 06:17:43 +00:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-04 18:40:51 +00:00
|
|
|
// For -shared (PIC) output, we create create a synthetic function which will
|
|
|
|
// apply any relocations to the data segments on startup. This function is
|
|
|
|
// called __wasm_apply_relocs and is added at the very beginning of
|
|
|
|
// __wasm_call_ctors before any of the constructors run.
|
|
|
|
void Writer::createApplyRelocationsFunction() {
|
|
|
|
LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n");
|
|
|
|
// First write the body's contents to a string.
|
|
|
|
std::string BodyContent;
|
|
|
|
{
|
|
|
|
raw_string_ostream OS(BodyContent);
|
|
|
|
writeUleb128(OS, 0, "num locals");
|
|
|
|
for (const OutputSegment *Seg : Segments)
|
|
|
|
for (const InputSegment *InSeg : Seg->InputSegments)
|
|
|
|
InSeg->generateRelocationCode(OS);
|
|
|
|
writeU8(OS, WASM_OPCODE_END, "END");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we know the size of the body we can create the final function body
|
|
|
|
std::string FunctionBody;
|
|
|
|
{
|
|
|
|
raw_string_ostream OS(FunctionBody);
|
|
|
|
writeUleb128(OS, BodyContent.size(), "function size");
|
|
|
|
OS << BodyContent;
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
|
|
|
|
cast<SyntheticFunction>(WasmSym::ApplyRelocs->Function)->setBody(Body);
|
|
|
|
}
|
2018-01-12 18:35:13 +00:00
|
|
|
|
|
|
|
// Create synthetic "__wasm_call_ctors" function based on ctor functions
|
|
|
|
// in input object.
|
2019-04-04 18:40:51 +00:00
|
|
|
void Writer::createCallCtorsFunction() {
|
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");
|
2019-04-04 18:40:51 +00:00
|
|
|
if (Config->Pic) {
|
|
|
|
writeU8(OS, WASM_OPCODE_CALL, "CALL");
|
|
|
|
writeUleb128(OS, WasmSym::ApplyRelocs->getFunctionIndex(),
|
|
|
|
"function index");
|
|
|
|
}
|
2018-02-23 05:08:53 +00:00
|
|
|
for (const WasmInitEntry &F : InitFunctions) {
|
2019-04-04 18:40:51 +00:00
|
|
|
writeU8(OS, WASM_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
|
|
|
}
|
2019-04-04 18:40:51 +00:00
|
|
|
writeU8(OS, WASM_OPCODE_END, "END");
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2019-04-23 02:42:06 +00:00
|
|
|
llvm::stable_sort(InitFunctions,
|
|
|
|
[](const WasmInitEntry &L, const WasmInitEntry &R) {
|
|
|
|
return L.Priority < R.Priority;
|
|
|
|
});
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::createSyntheticSections() {
|
|
|
|
Out.DylinkSec = make<DylinkSection>();
|
|
|
|
Out.TypeSec = make<TypeSection>();
|
|
|
|
Out.ImportSec = make<ImportSection>();
|
|
|
|
Out.FunctionSec = make<FunctionSection>();
|
|
|
|
Out.TableSec = make<TableSection>();
|
|
|
|
Out.MemorySec = make<MemorySection>();
|
|
|
|
Out.GlobalSec = make<GlobalSection>();
|
|
|
|
Out.EventSec = make<EventSection>();
|
|
|
|
Out.ExportSec = make<ExportSection>();
|
|
|
|
Out.ElemSec = make<ElemSection>(TableBase);
|
|
|
|
Out.DataCountSec = make<DataCountSection>(Segments.size());
|
|
|
|
Out.LinkingSec = make<LinkingSection>(InitFunctions, Segments);
|
|
|
|
Out.NameSec = make<NameSection>();
|
|
|
|
Out.ProducersSec = make<ProducersSection>();
|
|
|
|
Out.TargetFeaturesSec = make<TargetFeaturesSection>();
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
log("-- createOutputSegments");
|
|
|
|
createOutputSegments();
|
|
|
|
log("-- createSyntheticSections");
|
|
|
|
createSyntheticSections();
|
|
|
|
log("-- populateProducers");
|
|
|
|
populateProducers();
|
|
|
|
log("-- populateTargetFeatures");
|
|
|
|
populateTargetFeatures();
|
2017-11-17 18:14:09 +00:00
|
|
|
log("-- calculateImports");
|
|
|
|
calculateImports();
|
2019-05-23 09:41:03 +00:00
|
|
|
log("-- scanRelocations");
|
|
|
|
scanRelocations();
|
2018-01-09 23:56:44 +00:00
|
|
|
log("-- assignIndexes");
|
|
|
|
assignIndexes();
|
2018-01-12 18:35:13 +00:00
|
|
|
log("-- calculateInitFunctions");
|
|
|
|
calculateInitFunctions();
|
2019-05-21 17:16:33 +00:00
|
|
|
log("-- calculateTypes");
|
|
|
|
calculateTypes();
|
|
|
|
log("-- layoutMemory");
|
|
|
|
layoutMemory();
|
2019-04-04 18:40:51 +00:00
|
|
|
if (!Config->Relocatable) {
|
|
|
|
if (Config->Pic)
|
|
|
|
createApplyRelocationsFunction();
|
|
|
|
createCallCtorsFunction();
|
|
|
|
}
|
2018-02-23 05:08:53 +00:00
|
|
|
log("-- calculateExports");
|
|
|
|
calculateExports();
|
2018-05-04 23:14:42 +00:00
|
|
|
log("-- calculateCustomSections");
|
|
|
|
calculateCustomSections();
|
2019-05-21 09:13:09 +00:00
|
|
|
log("-- populateSymtab");
|
|
|
|
populateSymtab();
|
|
|
|
log("-- addSections");
|
|
|
|
addSections();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
if (errorHandler().Verbose) {
|
2019-05-21 09:13:09 +00:00
|
|
|
log("Defined Functions: " + Twine(Out.FunctionSec->InputFunctions.size()));
|
|
|
|
log("Defined Globals : " + Twine(Out.GlobalSec->InputGlobals.size()));
|
|
|
|
log("Defined Events : " + Twine(Out.EventSec->InputEvents.size()));
|
2019-05-23 09:41:03 +00:00
|
|
|
log("Function Imports : " + Twine(Out.ImportSec->numImportedFunctions()));
|
|
|
|
log("Global Imports : " + Twine(Out.ImportSec->numImportedGlobals()));
|
|
|
|
log("Event Imports : " + Twine(Out.ImportSec->numImportedEvents()));
|
2017-11-17 18:14:09 +00:00
|
|
|
for (ObjFile *File : Symtab->ObjectFiles)
|
|
|
|
File->dumpInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
createHeader();
|
2019-05-21 09:13:09 +00:00
|
|
|
log("-- finalizeSections");
|
|
|
|
finalizeSections();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
|
|
|
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(); }
|