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-07-11 05:40:30 +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-07-03 22:04:54 +00:00
|
|
|
void createInitMemoryFunction();
|
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
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
void addSection(OutputSection *sec);
|
2019-05-21 09:13:09 +00:00
|
|
|
|
|
|
|
void addSections();
|
2019-05-23 10:06:03 +00:00
|
|
|
|
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();
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
uint64_t fileSize = 0;
|
|
|
|
uint32_t tableBase = 0;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
std::vector<WasmInitEntry> initFunctions;
|
|
|
|
llvm::StringMap<std::vector<InputSection *>> customSectionMapping;
|
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
|
2019-07-11 05:40:30 +00:00
|
|
|
std::string header;
|
|
|
|
std::vector<OutputSection *> outputSections;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
std::unique_ptr<FileOutputBuffer> buffer;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
std::vector<OutputSegment *> segments;
|
|
|
|
llvm::SmallDenseMap<StringRef, OutputSegment *> segmentMap;
|
2017-11-17 18:14:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2018-05-04 23:14:42 +00:00
|
|
|
void Writer::calculateCustomSections() {
|
|
|
|
log("calculateCustomSections");
|
2019-07-11 05:40:30 +00:00
|
|
|
bool stripDebug = config->stripDebug || config->stripAll;
|
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
for (InputSection *section : file->customSections) {
|
|
|
|
StringRef name = section->getName();
|
2018-05-04 23:14:42 +00:00
|
|
|
// These custom sections are known the linker and synthesized rather than
|
|
|
|
// blindly copied
|
2019-07-11 05:40:30 +00:00
|
|
|
if (name == "linking" || name == "name" || name == "producers" ||
|
|
|
|
name == "target_features" || name.startswith("reloc."))
|
2018-05-04 23:14:42 +00:00
|
|
|
continue;
|
|
|
|
// .. or it is a debug section
|
2019-07-11 05:40:30 +00:00
|
|
|
if (stripDebug && name.startswith(".debug_"))
|
2018-05-04 23:14:42 +00:00
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
customSectionMapping[name].push_back(section);
|
2018-05-04 23:14:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 16:12:49 +00:00
|
|
|
void Writer::createCustomSections() {
|
|
|
|
log("createCustomSections");
|
2019-07-11 05:40:30 +00:00
|
|
|
for (auto &pair : customSectionMapping) {
|
|
|
|
StringRef name = pair.first();
|
|
|
|
LLVM_DEBUG(dbgs() << "createCustomSection: " << name << "\n");
|
|
|
|
|
|
|
|
OutputSection *sec = make<CustomSection>(name, pair.second);
|
|
|
|
if (config->relocatable || config->emitRelocs) {
|
|
|
|
auto *sym = make<OutputSectionSymbol>(sec);
|
|
|
|
out.linkingSec->addToSymtab(sym);
|
|
|
|
sec->sectionSym = sym;
|
2019-05-21 09:13:09 +00:00
|
|
|
}
|
2019-07-11 05:40:30 +00:00
|
|
|
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
|
2019-07-11 05:40:30 +00:00
|
|
|
size_t origSize = outputSections.size();
|
|
|
|
for (size_t i = 0; i < origSize; i++) {
|
|
|
|
LLVM_DEBUG(dbgs() << "check section " << i << "\n");
|
|
|
|
OutputSection *sec = outputSections[i];
|
2019-05-21 09:13:09 +00:00
|
|
|
|
|
|
|
// Count the number of needed sections.
|
2019-07-11 05:40:30 +00:00
|
|
|
uint32_t count = sec->getNumRelocations();
|
|
|
|
if (!count)
|
2017-11-17 18:14:09 +00:00
|
|
|
continue;
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
StringRef name;
|
|
|
|
if (sec->type == WASM_SEC_DATA)
|
|
|
|
name = "reloc.DATA";
|
|
|
|
else if (sec->type == WASM_SEC_CODE)
|
|
|
|
name = "reloc.CODE";
|
|
|
|
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-07-11 05:40:30 +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-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
const WasmProducerInfo &info = file->getWasmObj()->getProducerInfo();
|
|
|
|
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() {
|
2019-07-11 05:40:30 +00:00
|
|
|
memcpy(buffer->getBufferStart(), header.data(), header.size());
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::writeSections() {
|
2019-07-11 05:40:30 +00:00
|
|
|
uint8_t *buf = buffer->getBufferStart();
|
|
|
|
parallelForEach(outputSections, [buf](OutputSection *s) {
|
|
|
|
assert(s->isNeeded());
|
|
|
|
s->writeTo(buf);
|
2019-05-21 09:13:09 +00:00
|
|
|
});
|
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() {
|
2019-07-11 05:40:30 +00:00
|
|
|
uint32_t memoryPtr = 0;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
auto placeStack = [&]() {
|
2019-07-11 13:13:25 +00:00
|
|
|
if (config->relocatable || config->isPic)
|
2018-05-03 17:21:53 +00:00
|
|
|
return;
|
2019-07-11 05:40:30 +00:00
|
|
|
memoryPtr = alignTo(memoryPtr, stackAlignment);
|
|
|
|
if (config->zStackSize != alignTo(config->zStackSize, stackAlignment))
|
|
|
|
error("stack size must be " + Twine(stackAlignment) + "-byte aligned");
|
|
|
|
log("mem: stack size = " + Twine(config->zStackSize));
|
|
|
|
log("mem: stack base = " + Twine(memoryPtr));
|
|
|
|
memoryPtr += config->zStackSize;
|
|
|
|
auto *sp = cast<DefinedGlobal>(WasmSym::stackPointer);
|
|
|
|
sp->global->global.InitExpr.Value.Int32 = memoryPtr;
|
|
|
|
log("mem: stack top = " + Twine(memoryPtr));
|
2018-05-03 17:21:53 +00:00
|
|
|
};
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->stackFirst) {
|
|
|
|
placeStack();
|
2018-05-03 17:21:53 +00:00
|
|
|
} else {
|
2019-07-11 05:40:30 +00:00
|
|
|
memoryPtr = config->globalBase;
|
|
|
|
log("mem: global base = " + Twine(config->globalBase));
|
2018-05-03 17:21:53 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (WasmSym::globalBase)
|
|
|
|
WasmSym::globalBase->setVirtualAddress(config->globalBase);
|
2019-06-26 20:12:33 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
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.
|
2019-07-11 05:40:30 +00:00
|
|
|
if (WasmSym::dsoHandle)
|
|
|
|
WasmSym::dsoHandle->setVirtualAddress(dataStart);
|
2018-02-02 22:59:56 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
out.dylinkSec->memAlign = 0;
|
|
|
|
for (OutputSegment *seg : segments) {
|
|
|
|
out.dylinkSec->memAlign = std::max(out.dylinkSec->memAlign, seg->alignment);
|
|
|
|
memoryPtr = alignTo(memoryPtr, 1ULL << seg->alignment);
|
|
|
|
seg->startVA = memoryPtr;
|
|
|
|
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name,
|
|
|
|
memoryPtr, seg->size, seg->alignment));
|
|
|
|
memoryPtr += seg->size;
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2018-02-02 22:59:56 +00:00
|
|
|
// TODO: Add .bss space here.
|
2019-07-11 05:40:30 +00:00
|
|
|
if (WasmSym::dataEnd)
|
|
|
|
WasmSym::dataEnd->setVirtualAddress(memoryPtr);
|
2018-02-02 22:59:56 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
log("mem: static data = " + Twine(memoryPtr - dataStart));
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->shared) {
|
|
|
|
out.dylinkSec->memSize = memoryPtr;
|
2018-11-15 18:15:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +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.
|
2019-07-11 05:40:30 +00:00
|
|
|
log("mem: heap base = " + Twine(memoryPtr));
|
|
|
|
if (WasmSym::heapBase)
|
|
|
|
WasmSym::heapBase->setVirtualAddress(memoryPtr);
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->initialMemory != 0) {
|
|
|
|
if (config->initialMemory != alignTo(config->initialMemory, WasmPageSize))
|
2018-03-14 13:53:58 +00:00
|
|
|
error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned");
|
2019-07-11 05:40:30 +00:00
|
|
|
if (memoryPtr > config->initialMemory)
|
|
|
|
error("initial memory too small, " + Twine(memoryPtr) + " bytes needed");
|
2018-03-14 13:53:58 +00:00
|
|
|
else
|
2019-07-11 05:40:30 +00:00
|
|
|
memoryPtr = config->initialMemory;
|
2018-03-14 13:53:58 +00:00
|
|
|
}
|
2019-07-11 05:40:30 +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
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->maxMemory != 0 || config->sharedMemory) {
|
|
|
|
if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize))
|
2018-03-14 13:53:58 +00:00
|
|
|
error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
|
2019-07-11 05:40:30 +00:00
|
|
|
if (memoryPtr > config->maxMemory)
|
|
|
|
error("maximum memory too small, " + Twine(memoryPtr) + " bytes needed");
|
|
|
|
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-07-11 05:40:30 +00:00
|
|
|
void Writer::addSection(OutputSection *sec) {
|
|
|
|
if (!sec->isNeeded())
|
2019-05-21 09:13:09 +00:00
|
|
|
return;
|
2019-07-11 05:40:30 +00:00
|
|
|
log("addSection: " + toString(*sec));
|
|
|
|
sec->sectionIndex = outputSections.size();
|
|
|
|
outputSections.push_back(sec);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:06:03 +00:00
|
|
|
// If a section name is valid as a C identifier (which is rare because of
|
|
|
|
// the leading '.'), linkers are expected to define __start_<secname> and
|
|
|
|
// __stop_<secname> symbols. They are at beginning and end of the section,
|
|
|
|
// respectively. This is not requested by the ELF standard, but GNU ld and
|
|
|
|
// gold provide the feature, and used by many programs.
|
2019-07-11 05:40:30 +00:00
|
|
|
static void addStartStopSymbols(const OutputSegment *seg) {
|
|
|
|
StringRef name = seg->name;
|
|
|
|
if (!isValidCIdentifier(name))
|
2019-05-23 10:06:03 +00:00
|
|
|
return;
|
2019-07-11 05:40:30 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << name << "\n");
|
|
|
|
uint32_t start = seg->startVA;
|
|
|
|
uint32_t stop = start + seg->size;
|
|
|
|
symtab->addOptionalDataSymbol(saver.save("__start_" + name), start);
|
|
|
|
symtab->addOptionalDataSymbol(saver.save("__stop_" + name), stop);
|
2019-05-23 10:06:03 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::addSections() {
|
2019-07-11 05:40:30 +00:00
|
|
|
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));
|
2019-05-21 09:13:09 +00:00
|
|
|
|
2018-04-10 16:12:49 +00:00
|
|
|
createCustomSections();
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
addSection(out.linkingSec);
|
|
|
|
if (config->emitRelocs || 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-07-11 05:40:30 +00:00
|
|
|
addSection(out.nameSec);
|
|
|
|
addSection(out.producersSec);
|
|
|
|
addSection(out.targetFeaturesSec);
|
2019-05-21 09:13:09 +00:00
|
|
|
}
|
2019-01-17 02:29:41 +00:00
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::finalizeSections() {
|
2019-07-11 05:40:30 +00:00
|
|
|
for (OutputSection *s : outputSections) {
|
|
|
|
s->setOffset(fileSize);
|
|
|
|
s->finalizeContents();
|
|
|
|
fileSize += s->getSize();
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::populateTargetFeatures() {
|
2019-07-11 05:40:30 +00:00
|
|
|
StringMap<std::string> used;
|
|
|
|
StringMap<std::string> required;
|
|
|
|
StringMap<std::string> disallowed;
|
[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
|
|
|
|
2019-03-26 04:11:05 +00:00
|
|
|
// Only infer used features if user did not specify features
|
2019-07-11 05:40:30 +00:00
|
|
|
bool inferFeatures = !config->features.hasValue();
|
2019-03-26 04:11:05 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!inferFeatures) {
|
|
|
|
for (auto &feature : config->features.getValue())
|
|
|
|
out.targetFeaturesSec->features.insert(feature);
|
2019-03-26 04:11:05 +00:00
|
|
|
// No need to read or check features
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->checkFeatures)
|
2019-03-26 04:11:05 +00:00
|
|
|
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
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
StringRef fileName(file->getName());
|
|
|
|
for (auto &feature : file->getWasmObj()->getTargetFeatures()) {
|
|
|
|
switch (feature.Prefix) {
|
[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
|
|
|
case WASM_FEATURE_PREFIX_USED:
|
2019-07-11 05:40:30 +00:00
|
|
|
used.insert({feature.Name, fileName});
|
[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-07-11 05:40:30 +00:00
|
|
|
used.insert({feature.Name, fileName});
|
|
|
|
required.insert({feature.Name, fileName});
|
[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_DISALLOWED:
|
2019-07-11 05:40:30 +00:00
|
|
|
disallowed.insert({feature.Name, fileName});
|
[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;
|
|
|
|
default:
|
|
|
|
error("Unrecognized feature policy prefix " +
|
2019-07-11 05:40:30 +00:00
|
|
|
std::to_string(feature.Prefix));
|
[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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (inferFeatures)
|
|
|
|
out.targetFeaturesSec->features.insert(used.keys().begin(),
|
|
|
|
used.keys().end());
|
2019-05-30 21:57:23 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (out.targetFeaturesSec->features.count("atomics") &&
|
|
|
|
!config->sharedMemory) {
|
|
|
|
if (inferFeatures)
|
|
|
|
error(Twine("'atomics' feature is used by ") + used["atomics"] +
|
2019-05-30 21:57:23 +00:00
|
|
|
", so --shared-memory must be used");
|
|
|
|
else
|
|
|
|
error("'atomics' feature is used, so --shared-memory must be used");
|
|
|
|
}
|
2019-03-29 20:43:49 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->checkFeatures)
|
2019-03-26 04:11:05 +00:00
|
|
|
return;
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (disallowed.count("atomics") && config->sharedMemory)
|
|
|
|
error("'atomics' feature is disallowed by " + disallowed["atomics"] +
|
2019-05-30 21:57:23 +00:00
|
|
|
", so --shared-memory must not be used");
|
2019-03-29 20:43:49 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!used.count("bulk-memory") && config->passiveSegments)
|
2019-07-03 22:04:54 +00:00
|
|
|
error("'bulk-memory' feature must be used in order to emit passive "
|
|
|
|
"segments");
|
|
|
|
|
2019-03-26 04:11:05 +00:00
|
|
|
// Validate that used features are allowed in output
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!inferFeatures) {
|
|
|
|
for (auto &feature : used.keys()) {
|
|
|
|
if (!out.targetFeaturesSec->features.count(feature))
|
|
|
|
error(Twine("Target feature '") + feature + "' used by " +
|
|
|
|
used[feature] + " is not allowed.");
|
2019-03-26 04:11:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[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
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
StringRef fileName(file->getName());
|
|
|
|
SmallSet<std::string, 8> objectFeatures;
|
|
|
|
for (auto &feature : file->getWasmObj()->getTargetFeatures()) {
|
|
|
|
if (feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED)
|
[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
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
objectFeatures.insert(feature.Name);
|
|
|
|
if (disallowed.count(feature.Name))
|
|
|
|
error(Twine("Target feature '") + feature.Name + "' used in " +
|
|
|
|
fileName + " is disallowed by " + disallowed[feature.Name] +
|
2019-05-30 21:57:23 +00:00
|
|
|
". 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
|
|
|
}
|
2019-07-11 05:40:30 +00:00
|
|
|
for (auto &feature : required.keys()) {
|
|
|
|
if (!objectFeatures.count(feature))
|
|
|
|
error(Twine("Missing target feature '") + feature + "' in " + fileName +
|
|
|
|
", required by " + required[feature] +
|
2019-05-30 21:57:23 +00:00
|
|
|
". 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() {
|
2019-07-11 05:40:30 +00:00
|
|
|
for (Symbol *sym : symtab->getSymbols()) {
|
|
|
|
if (!sym->isUndefined())
|
2018-02-23 05:08:53 +00:00
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
if (sym->isWeak() && !config->relocatable)
|
2017-12-15 19:23:49 +00:00
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!sym->isLive())
|
2018-04-20 17:18:06 +00:00
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!sym->isUsedInRegularObj)
|
2018-05-30 18:07:52 +00:00
|
|
|
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.
|
2019-07-11 05:40:30 +00:00
|
|
|
if (isa<DataSymbol>(sym))
|
2019-03-12 21:53:23 +00:00
|
|
|
continue;
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "import: " << sym->getName() << "\n");
|
|
|
|
out.importSec->addImport(sym);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-18 23:40:49 +00:00
|
|
|
void Writer::calculateExports() {
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->relocatable)
|
2018-02-23 05:08:53 +00:00
|
|
|
return;
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->relocatable && !config->importMemory)
|
|
|
|
out.exportSec->exports.push_back(
|
2019-05-21 09:13:09 +00:00
|
|
|
WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
|
2018-05-10 18:10:34 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->relocatable && config->exportTable)
|
|
|
|
out.exportSec->exports.push_back(
|
|
|
|
WasmExport{functionTableName, WASM_EXTERNAL_TABLE, 0});
|
2018-05-10 18:10:34 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
unsigned fakeGlobalIndex = out.importSec->getNumImportedGlobals() +
|
|
|
|
out.globalSec->inputGlobals.size();
|
2018-05-10 18:10:34 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (Symbol *sym : symtab->getSymbols()) {
|
|
|
|
if (!sym->isExported())
|
2018-03-01 09:38:02 +00:00
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!sym->isLive())
|
2018-03-01 09:38:02 +00:00
|
|
|
continue;
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2019-07-11 05:40:30 +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
|
2019-07-11 05:40:30 +00:00
|
|
|
if (g->getGlobalType()->Mutable) {
|
2018-06-07 01:27:07 +00:00
|
|
|
// Only the __stack_pointer should ever be create as mutable.
|
2019-07-11 05:40:30 +00:00
|
|
|
assert(g == WasmSym::stackPointer);
|
2018-06-07 01:27:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-07-11 05:40:30 +00:00
|
|
|
export_ = {name, WASM_EXTERNAL_GLOBAL, g->getGlobalIndex()};
|
|
|
|
} else if (auto *e = dyn_cast<DefinedEvent>(sym)) {
|
|
|
|
export_ = {name, WASM_EXTERNAL_EVENT, e->getEventIndex()};
|
2018-05-10 18:10:34 +00:00
|
|
|
} else {
|
2019-07-11 05:40:30 +00:00
|
|
|
auto *d = cast<DefinedData>(sym);
|
|
|
|
out.globalSec->definedFakeGlobals.emplace_back(d);
|
|
|
|
export_ = {name, WASM_EXTERNAL_GLOBAL, fakeGlobalIndex++};
|
2018-05-10 18:10:34 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "Export: " << name << "\n");
|
|
|
|
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() {
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->relocatable && !config->emitRelocs)
|
2018-02-23 05:08:53 +00:00
|
|
|
return;
|
2018-01-18 23:40:49 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (Symbol *sym : symtab->getSymbols())
|
|
|
|
if (sym->isUsedInRegularObj && sym->isLive())
|
|
|
|
out.linkingSec->addToSymtab(sym);
|
2019-01-30 18:55:15 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Local symtab entries: " << file->getName() << "\n");
|
|
|
|
for (Symbol *sym : file->getSymbols())
|
|
|
|
if (sym->isLocal() && !isa<SectionSymbol>(sym) && sym->isLive())
|
|
|
|
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
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
ArrayRef<WasmSignature> types = file->getWasmObj()->types();
|
|
|
|
for (uint32_t i = 0; i < types.size(); i++)
|
|
|
|
if (file->typeIsUsed[i])
|
|
|
|
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-07-11 05:40:30 +00:00
|
|
|
for (const Symbol *sym : out.importSec->importedSymbols) {
|
|
|
|
if (auto *f = dyn_cast<FunctionSymbol>(sym))
|
|
|
|
out.typeSec->registerType(*f->signature);
|
|
|
|
else if (auto *e = dyn_cast<EventSymbol>(sym))
|
|
|
|
out.typeSec->registerType(*e->signature);
|
2018-12-08 06:17:43 +00:00
|
|
|
}
|
2018-01-31 23:48:14 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (const InputFunction *f : out.functionSec->inputFunctions)
|
|
|
|
out.typeSec->registerType(f->signature);
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +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() {
|
2019-07-11 05:40:30 +00:00
|
|
|
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.
|
2019-07-11 05:40:30 +00:00
|
|
|
out.importSec->seal();
|
2018-03-09 16:43:05 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (InputFunction *func : symtab->syntheticFunctions)
|
|
|
|
out.functionSec->addFunction(func);
|
2018-03-12 15:44:07 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Functions: " << file->getName() << "\n");
|
|
|
|
for (InputFunction *func : file->functions)
|
|
|
|
out.functionSec->addFunction(func);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (InputGlobal *global : symtab->syntheticGlobals)
|
|
|
|
out.globalSec->addGlobal(global);
|
2018-02-23 05:08:53 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Globals: " << file->getName() << "\n");
|
|
|
|
for (InputGlobal *global : file->globals)
|
|
|
|
out.globalSec->addGlobal(global);
|
2018-02-23 05:08:53 +00:00
|
|
|
}
|
2018-12-08 06:17:43 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Events: " << file->getName() << "\n");
|
|
|
|
for (InputEvent *event : file->events)
|
|
|
|
out.eventSec->addEvent(event);
|
2018-12-08 06:17:43 +00:00
|
|
|
}
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +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.
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->isPic)
|
2019-07-09 19:47:32 +00:00
|
|
|
return ".data";
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->mergeDataSegments)
|
|
|
|
return name;
|
|
|
|
if (name.startswith(".text."))
|
2018-02-28 00:57:28 +00:00
|
|
|
return ".text";
|
2019-07-11 05:40:30 +00:00
|
|
|
if (name.startswith(".data."))
|
2018-02-28 00:57:28 +00:00
|
|
|
return ".data";
|
2019-07-11 05:40:30 +00:00
|
|
|
if (name.startswith(".bss."))
|
2018-02-28 00:57:28 +00:00
|
|
|
return ".bss";
|
2019-07-11 05:40:30 +00:00
|
|
|
if (name.startswith(".rodata."))
|
2018-08-08 18:02:55 +00:00
|
|
|
return ".rodata";
|
2019-07-11 05:40:30 +00:00
|
|
|
return name;
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createOutputSegments() {
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
for (InputSegment *segment : file->segments) {
|
|
|
|
if (!segment->live)
|
2018-01-12 22:25:17 +00:00
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
StringRef name = getOutputDataSegmentName(segment->getName());
|
|
|
|
OutputSegment *&s = segmentMap[name];
|
|
|
|
if (s == nullptr) {
|
|
|
|
LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
|
|
|
|
s = make<OutputSegment>(name, segments.size());
|
|
|
|
if (config->passiveSegments)
|
|
|
|
s->initFlags = WASM_SEGMENT_IS_PASSIVE;
|
|
|
|
segments.push_back(s);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
2019-07-11 05:40:30 +00:00
|
|
|
s->addInputSegment(segment);
|
|
|
|
LLVM_DEBUG(dbgs() << "added data: " << name << ": " << s->size << "\n");
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
static void createFunction(DefinedFunction *func, StringRef bodyContent) {
|
|
|
|
std::string functionBody;
|
2019-07-03 22:04:54 +00:00
|
|
|
{
|
2019-07-11 05:40:30 +00:00
|
|
|
raw_string_ostream os(functionBody);
|
|
|
|
writeUleb128(os, bodyContent.size(), "function size");
|
|
|
|
os << bodyContent;
|
2019-07-03 22:04:54 +00:00
|
|
|
}
|
2019-07-11 05:40:30 +00:00
|
|
|
ArrayRef<uint8_t> body = arrayRefFromStringRef(saver.save(functionBody));
|
|
|
|
cast<SyntheticFunction>(func->function)->setBody(body);
|
2019-07-03 22:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createInitMemoryFunction() {
|
|
|
|
LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
|
2019-07-11 05:40:30 +00:00
|
|
|
std::string bodyContent;
|
2019-07-03 22:04:54 +00:00
|
|
|
{
|
2019-07-11 05:40:30 +00:00
|
|
|
raw_string_ostream os(bodyContent);
|
|
|
|
writeUleb128(os, 0, "num locals");
|
2019-07-03 22:04:54 +00:00
|
|
|
|
|
|
|
// initialize passive data segments
|
2019-07-11 05:40:30 +00:00
|
|
|
for (const OutputSegment *s : segments) {
|
|
|
|
if (s->initFlags & WASM_SEGMENT_IS_PASSIVE) {
|
2019-07-03 22:04:54 +00:00
|
|
|
// destination address
|
2019-07-11 05:40:30 +00:00
|
|
|
writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
|
2019-07-12 17:55:07 +00:00
|
|
|
writeSleb128(os, s->startVA, "destination address");
|
2019-07-03 22:04:54 +00:00
|
|
|
// source segment offset
|
2019-07-11 05:40:30 +00:00
|
|
|
writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
|
2019-07-12 17:55:07 +00:00
|
|
|
writeSleb128(os, 0, "segment offset");
|
2019-07-03 22:04:54 +00:00
|
|
|
// memory region size
|
2019-07-11 05:40:30 +00:00
|
|
|
writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
|
2019-07-12 17:55:07 +00:00
|
|
|
writeSleb128(os, s->size, "memory region size");
|
2019-07-03 22:04:54 +00:00
|
|
|
// memory.init instruction
|
2019-07-11 05:40:30 +00:00
|
|
|
writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
|
|
|
|
writeUleb128(os, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT");
|
|
|
|
writeUleb128(os, s->index, "segment index immediate");
|
|
|
|
writeU8(os, 0, "memory index immediate");
|
2019-07-03 22:04:54 +00:00
|
|
|
// data.drop instruction
|
2019-07-11 05:40:30 +00:00
|
|
|
writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
|
|
|
|
writeUleb128(os, WASM_OPCODE_DATA_DROP, "DATA.DROP");
|
|
|
|
writeUleb128(os, s->index, "segment index immediate");
|
2019-07-03 22:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-11 05:40:30 +00:00
|
|
|
writeU8(os, WASM_OPCODE_END, "END");
|
2019-07-03 22:04:54 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
createFunction(WasmSym::initMemory, bodyContent);
|
2019-07-03 22:04:54 +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
|
2019-07-03 22:04:54 +00:00
|
|
|
// called __wasm_apply_relocs and is added at the beginning of __wasm_call_ctors
|
|
|
|
// before any of the constructors run.
|
2019-04-04 18:40:51 +00:00
|
|
|
void Writer::createApplyRelocationsFunction() {
|
|
|
|
LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n");
|
|
|
|
// First write the body's contents to a string.
|
2019-07-11 05:40:30 +00:00
|
|
|
std::string bodyContent;
|
2019-04-04 18:40:51 +00:00
|
|
|
{
|
2019-07-11 05:40:30 +00:00
|
|
|
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");
|
2019-04-04 18:40:51 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
createFunction(WasmSym::applyRelocs, bodyContent);
|
2019-04-04 18:40:51 +00:00
|
|
|
}
|
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-07-11 05:40:30 +00:00
|
|
|
if (!WasmSym::callCtors->isLive())
|
2019-03-01 22:35:47 +00:00
|
|
|
return;
|
|
|
|
|
2018-03-02 14:48:50 +00:00
|
|
|
// First write the body's contents to a string.
|
2019-07-11 05:40:30 +00:00
|
|
|
std::string bodyContent;
|
2018-01-12 18:35:13 +00:00
|
|
|
{
|
2019-07-11 05:40:30 +00:00
|
|
|
raw_string_ostream os(bodyContent);
|
|
|
|
writeUleb128(os, 0, "num locals");
|
2019-07-03 22:04:54 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->passiveSegments) {
|
|
|
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
|
|
|
writeUleb128(os, WasmSym::initMemory->getFunctionIndex(),
|
2019-07-03 22:04:54 +00:00
|
|
|
"function index");
|
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->isPic) {
|
|
|
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
|
|
|
writeUleb128(os, WasmSym::applyRelocs->getFunctionIndex(),
|
2019-04-04 18:40:51 +00:00
|
|
|
"function index");
|
|
|
|
}
|
2019-07-03 22:04:54 +00:00
|
|
|
|
|
|
|
// Call constructors
|
2019-07-11 05:40:30 +00:00
|
|
|
for (const WasmInitEntry &f : initFunctions) {
|
|
|
|
writeU8(os, WASM_OPCODE_CALL, "CALL");
|
|
|
|
writeUleb128(os, f.sym->getFunctionIndex(), "function index");
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
2019-07-11 05:40:30 +00:00
|
|
|
writeU8(os, WASM_OPCODE_END, "END");
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
createFunction(WasmSym::callCtors, bodyContent);
|
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-07-11 05:40:30 +00:00
|
|
|
if (!config->relocatable && !WasmSym::callCtors->isLive())
|
2019-03-02 04:55:02 +00:00
|
|
|
return;
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
for (ObjFile *file : symtab->objectFiles) {
|
|
|
|
const WasmLinkingData &l = file->getWasmObj()->linkingData();
|
|
|
|
for (const WasmInitFunc &f : l.InitFunctions) {
|
|
|
|
FunctionSymbol *sym = file->getFunctionSymbol(f.Symbol);
|
2019-06-07 06:00:46 +00:00
|
|
|
// comdat exclusions can cause init functions be discarded.
|
2019-07-11 05:40:30 +00:00
|
|
|
if (sym->isDiscarded())
|
2019-06-07 06:00:46 +00:00
|
|
|
continue;
|
2019-07-11 05:40:30 +00:00
|
|
|
assert(sym->isLive());
|
|
|
|
if (*sym->signature != WasmSignature{{}, {}})
|
|
|
|
error("invalid signature for init func: " + toString(*sym));
|
|
|
|
initFunctions.emplace_back(WasmInitEntry{sym, f.Priority});
|
2018-03-02 14:46:54 +00:00
|
|
|
}
|
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-07-11 05:40:30 +00:00
|
|
|
llvm::stable_sort(initFunctions,
|
|
|
|
[](const WasmInitEntry &l, const WasmInitEntry &r) {
|
|
|
|
return l.priority < r.priority;
|
2019-04-23 02:42:06 +00:00
|
|
|
});
|
2018-01-12 18:35:13 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 09:13:09 +00:00
|
|
|
void Writer::createSyntheticSections() {
|
2019-07-11 05:40:30 +00:00
|
|
|
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>();
|
2019-05-21 09:13:09 +00:00
|
|
|
}
|
|
|
|
|
2017-11-17 18:14:09 +00:00
|
|
|
void Writer::run() {
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->relocatable || config->isPic)
|
|
|
|
config->globalBase = 0;
|
2018-02-27 23:58:03 +00:00
|
|
|
|
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.
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->isPic)
|
|
|
|
tableBase = 1;
|
2018-11-15 00:37:21 +00:00
|
|
|
|
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 10:06:03 +00:00
|
|
|
log("-- layoutMemory");
|
|
|
|
layoutMemory();
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->relocatable) {
|
2019-05-23 10:06:03 +00:00
|
|
|
// Create linker synthesized __start_SECNAME/__stop_SECNAME symbols
|
|
|
|
// This has to be done after memory layout is performed.
|
2019-07-11 05:40:30 +00:00
|
|
|
for (const OutputSegment *seg : segments)
|
|
|
|
addStartStopSymbols(seg);
|
2019-05-23 10:06:03 +00:00
|
|
|
}
|
|
|
|
|
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-23 10:06:03 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!config->relocatable) {
|
2019-05-23 10:06:03 +00:00
|
|
|
// Create linker synthesized functions
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->passiveSegments)
|
2019-07-03 22:04:54 +00:00
|
|
|
createInitMemoryFunction();
|
2019-07-11 05:40:30 +00:00
|
|
|
if (config->isPic)
|
2019-04-04 18:40:51 +00:00
|
|
|
createApplyRelocationsFunction();
|
|
|
|
createCallCtorsFunction();
|
|
|
|
}
|
2019-05-23 10:06:03 +00:00
|
|
|
|
|
|
|
log("-- calculateTypes");
|
|
|
|
calculateTypes();
|
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
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (errorHandler().verbose) {
|
|
|
|
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-07-10 09:10:01 +00:00
|
|
|
log("Function Imports : " +
|
2019-07-11 05:40:30 +00:00
|
|
|
Twine(out.importSec->getNumImportedFunctions()));
|
|
|
|
log("Global Imports : " + Twine(out.importSec->getNumImportedGlobals()));
|
|
|
|
log("Event Imports : " + Twine(out.importSec->getNumImportedEvents()));
|
|
|
|
for (ObjFile *file : symtab->objectFiles)
|
|
|
|
file->dumpInfo();
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (Error e = buffer->commit())
|
|
|
|
fatal("failed to write the output file: " + toString(std::move(e)));
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Open a result file.
|
|
|
|
void Writer::openFile() {
|
2019-07-11 05:40:30 +00:00
|
|
|
log("writing: " + config->outputFile);
|
2017-11-17 18:14:09 +00:00
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
|
|
|
|
FileOutputBuffer::create(config->outputFile, fileSize,
|
2017-11-17 18:14:09 +00:00
|
|
|
FileOutputBuffer::F_executable);
|
|
|
|
|
2019-07-11 05:40:30 +00:00
|
|
|
if (!bufferOrErr)
|
|
|
|
error("failed to open " + config->outputFile + ": " +
|
|
|
|
toString(bufferOrErr.takeError()));
|
2017-11-17 18:14:09 +00:00
|
|
|
else
|
2019-07-11 05:40:30 +00:00
|
|
|
buffer = std::move(*bufferOrErr);
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Writer::createHeader() {
|
2019-07-11 05:40:30 +00:00
|
|
|
raw_string_ostream os(header);
|
|
|
|
writeBytes(os, WasmMagic, sizeof(WasmMagic), "wasm magic");
|
|
|
|
writeU32(os, WasmVersion, "wasm version");
|
|
|
|
os.flush();
|
|
|
|
fileSize += header.size();
|
2017-11-17 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lld::wasm::writeResult() { Writer().run(); }
|