Index: wasm/CMakeLists.txt =================================================================== --- wasm/CMakeLists.txt +++ wasm/CMakeLists.txt @@ -4,8 +4,8 @@ add_lld_library(lldWasm Driver.cpp + InputChunks.cpp InputFiles.cpp - InputSegment.cpp OutputSections.cpp SymbolTable.cpp Symbols.cpp Index: wasm/InputChunks.h =================================================================== --- wasm/InputChunks.h +++ wasm/InputChunks.h @@ -0,0 +1,125 @@ +//===- InputChunks.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An input chunk represents an indivisible blocks of code or data from an input +// file. i.e. a single wasm data segment or a single wasm function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_INPUT_CHUNKS_H +#define LLD_WASM_INPUT_CHUNKS_H + +#include "InputFiles.h" +#include "WriterUtils.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/Wasm.h" + +using llvm::object::WasmSegment; +using llvm::wasm::WasmFunction; +using llvm::wasm::WasmRelocation; +using llvm::wasm::WasmSignature; +using llvm::object::WasmSection; + +namespace lld { +namespace wasm { + +class ObjFile; +class OutputSegment; + +class InputChunk { +public: + InputChunk(const ObjFile &F) : File(F) {} + virtual ~InputChunk() = default; + void copyRelocations(const WasmSection &Section); + + virtual const uint8_t *getData() const = 0; + virtual uint32_t getSize() const = 0; + virtual uint32_t getInputSectionOffset() const = 0; + + int32_t OutputOffset = 0; + std::vector Relocations; + std::vector OutRelocations; + const ObjFile &File; +}; + +// Represents a WebAssembly data segment which can be included as part of +// an output data segments. Note that in WebAssembly, unlike ELF and other +// formats, used the term "data segment" to refer to the continous regions of +// memory that make on the data section. See: +// https://webassembly.github.io/spec/syntax/modules.html#syntax-data +// +// For example, by default, clang will produce a separate data section for +// each global variable. +class InputSegment : public InputChunk { +public: + InputSegment(const WasmSegment &Seg, const ObjFile &F) + : InputChunk(F), Segment(Seg) {} + + // Translate an offset in the input segment to an offset in the output + // segment. + uint32_t translateVA(uint32_t Address) const; + + const OutputSegment *getOutputSegment() const { return OutputSeg; } + + void setOutputSegment(const OutputSegment *Segment, uint32_t Offset) { + OutputSeg = Segment; + OutputOffset = Offset; + } + + const uint8_t *getData() const override { + return Segment.Data.Content.data(); + } + uint32_t getSize() const override { return Segment.Data.Content.size(); } + uint32_t getInputSectionOffset() const override { + return Segment.SectionOffset; + } + uint32_t getAlignment() const { return Segment.Data.Alignment; } + uint32_t startVA() const { return Segment.Data.Offset.Value.Int32; } + uint32_t endVA() const { return startVA() + getSize(); } + StringRef getName() const { return Segment.Data.Name; } + +protected: + const WasmSegment &Segment; + const OutputSegment *OutputSeg = nullptr; +}; + +// Represents a single wasm function within and input file. These are +// combined to create the final output CODE section. +class InputFunction : public InputChunk { +public: + InputFunction(const WasmSignature &S, const WasmFunction &Func, + const ObjFile &F) + : InputChunk(F), Signature(S), Function(Func) {} + + uint32_t getSize() const override { return Function.Size; } + const uint8_t *getData() const override { + return File.CodeSection->Content.data() + Function.CodeSectionOffset; + } + uint32_t getInputSectionOffset() const override { + return Function.CodeSectionOffset; + }; + + uint32_t getOutputIndex() const { return OutputIndex.getValue(); }; + bool hasOutputIndex() const { return OutputIndex.hasValue(); }; + void setOutputIndex(uint32_t Index) { + assert(!hasOutputIndex()); + OutputIndex = Index; + }; + + const WasmSignature &Signature; + +protected: + const WasmFunction &Function; + llvm::Optional OutputIndex; +}; + +} // namespace wasm +} // namespace lld + +#endif // LLD_WASM_INPUT_CHUNKS_H Index: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ wasm/InputChunks.cpp @@ -0,0 +1,33 @@ +//===- InputSegment.cpp ---------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputChunks.h" +#include "OutputSegment.h" +#include "lld/Common/LLVM.h" + +#define DEBUG_TYPE "lld" + +using namespace llvm; +using namespace lld::wasm; + +uint32_t InputSegment::translateVA(uint32_t Address) const { + assert(Address >= startVA() && Address < endVA()); + int32_t Delta = OutputSeg->StartVA + OutputOffset - startVA(); + DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta + << " Address=" << Address << "\n"); + return Address + Delta; +} + +void InputChunk::copyRelocations(const WasmSection &Section) { + size_t Start = getInputSectionOffset(); + size_t Size = getSize(); + for (const WasmRelocation &R : Section.Relocations) + if (R.Offset >= Start && R.Offset < Start + Size) + Relocations.push_back(R); +} Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -98,6 +98,7 @@ uint32_t getRelocatedAddress(uint32_t Index) const; const WasmSection *CodeSection = nullptr; + const WasmSection *DataSection = nullptr; std::vector TypeMap; std::vector Segments; @@ -131,7 +132,6 @@ // List of all indirect symbols indexed by table index space. std::vector TableSymbols; - const WasmSection *DataSection = nullptr; uint32_t NumGlobalImports = 0; uint32_t NumFunctionImports = 0; std::unique_ptr WasmObj; Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -10,8 +10,7 @@ #include "InputFiles.h" #include "Config.h" -#include "InputFunction.h" -#include "InputSegment.h" +#include "InputChunks.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -126,14 +125,6 @@ return nullptr; } -static void copyRelocationsRange(std::vector &To, - ArrayRef From, size_t Start, - size_t Size) { - for (const WasmRelocation &R : From) - if (R.Offset >= Start && R.Offset < Start + Size) - To.push_back(R); -} - // Get the value stored in the wasm global represented by this symbol. // This represents the virtual address of the symbol in the input file. uint32_t ObjFile::getGlobalValue(const WasmSymbol &Sym) const { @@ -175,8 +166,7 @@ for (const WasmSegment &S : WasmObj->dataSegments()) { InputSegment *Seg = make(S, *this); - copyRelocationsRange(Seg->Relocations, DataSection->Relocations, - Seg->getInputSectionOffset(), Seg->getSize()); + Seg->copyRelocations(*DataSection); Segments.emplace_back(Seg); } @@ -186,10 +176,9 @@ for (size_t I = 0; I < Funcs.size(); ++I) { const WasmFunction &Func = Funcs[I]; const WasmSignature &Sig = Types[FuncTypes[I]]; - InputFunction *Function = make(Sig, Func, *this); - copyRelocationsRange(Function->Relocations, CodeSection->Relocations, - Func.CodeSectionOffset, Func.Size); - Functions.emplace_back(Function); + InputFunction *F = make(Sig, Func, *this); + F->copyRelocations(*CodeSection); + Functions.emplace_back(F); } // Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols Index: wasm/InputFunction.h =================================================================== --- wasm/InputFunction.h +++ wasm/InputFunction.h @@ -1,57 +0,0 @@ -//===- InpuFunction.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Represents a WebAssembly function in an input file which could also be -// assigned a function index in the output. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_WASM_INPUT_FUNCTION_H -#define LLD_WASM_INPUT_FUNCTION_H - -#include "WriterUtils.h" -#include "llvm/Object/Wasm.h" - -using llvm::wasm::WasmRelocation; -using llvm::wasm::WasmFunction; - -namespace lld { -namespace wasm { - -class ObjFile; - -class InputFunction { -public: - InputFunction(const WasmSignature &S, const WasmFunction &Func, - const ObjFile &F) - : Signature(S), Function(Func), File(F) {} - - uint32_t getOutputIndex() const { return OutputIndex.getValue(); }; - bool hasOutputIndex() const { return OutputIndex.hasValue(); }; - - void setOutputIndex(uint32_t Index) { - assert(!hasOutputIndex()); - OutputIndex = Index; - }; - - const WasmSignature &Signature; - const WasmFunction &Function; - int32_t OutputOffset = 0; - std::vector Relocations; - std::vector OutRelocations; - const ObjFile &File; - -protected: - llvm::Optional OutputIndex; -}; - -} // namespace wasm -} // namespace lld - -#endif // LLD_WASM_INPUT_FUNCTION_H Index: wasm/InputSegment.h =================================================================== --- wasm/InputSegment.h +++ wasm/InputSegment.h @@ -1,76 +0,0 @@ -//===- InputSegment.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Represents a WebAssembly data segment which can be included as part of -// an output data segments. Note that in WebAssembly, unlike ELF and other -// formats, used the term "data segment" to refer to the continous regions of -// memory that make on the data section. See: -// https://webassembly.github.io/spec/syntax/modules.html#syntax-data -// -// For example, by default, clang will produce a separate data section for -// each global variable. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_WASM_INPUT_SEGMENT_H -#define LLD_WASM_INPUT_SEGMENT_H - -#include "WriterUtils.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/Wasm.h" - -using llvm::object::WasmSegment; -using llvm::wasm::WasmRelocation; - -namespace lld { -namespace wasm { - -class ObjFile; -class OutputSegment; - -class InputSegment { -public: - InputSegment(const WasmSegment &Seg, const ObjFile &F) - : Segment(Seg), File(F) {} - - // Translate an offset in the input segment to an offset in the output - // segment. - uint32_t translateVA(uint32_t Address) const; - - const OutputSegment *getOutputSegment() const { return OutputSeg; } - - uint32_t getOutputSegmentOffset() const { return OutputSegmentOffset; } - - uint32_t getInputSectionOffset() const { return Segment.SectionOffset; } - - void setOutputSegment(const OutputSegment *Segment, uint32_t Offset) { - OutputSeg = Segment; - OutputSegmentOffset = Offset; - } - - uint32_t getSize() const { return Segment.Data.Content.size(); } - uint32_t getAlignment() const { return Segment.Data.Alignment; } - uint32_t startVA() const { return Segment.Data.Offset.Value.Int32; } - uint32_t endVA() const { return startVA() + getSize(); } - StringRef getName() const { return Segment.Data.Name; } - - const WasmSegment &Segment; - const ObjFile &File; - std::vector Relocations; - std::vector OutRelocations; - -protected: - const OutputSegment *OutputSeg = nullptr; - uint32_t OutputSegmentOffset = 0; -}; - -} // namespace wasm -} // namespace lld - -#endif // LLD_WASM_INPUT_SEGMENT_H Index: wasm/InputSegment.cpp =================================================================== --- wasm/InputSegment.cpp +++ wasm/InputSegment.cpp @@ -1,25 +0,0 @@ -//===- InputSegment.cpp ---------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputSegment.h" -#include "OutputSegment.h" -#include "lld/Common/LLVM.h" - -#define DEBUG_TYPE "lld" - -using namespace llvm; -using namespace lld::wasm; - -uint32_t InputSegment::translateVA(uint32_t Address) const { - assert(Address >= startVA() && Address < endVA()); - int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA(); - DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta - << " Address=" << Address << "\n"); - return Address + Delta; -} Index: wasm/OutputSections.h =================================================================== --- wasm/OutputSections.h +++ wasm/OutputSections.h @@ -10,7 +10,7 @@ #ifndef LLD_WASM_OUTPUT_SECTIONS_H #define LLD_WASM_OUTPUT_SECTIONS_H -#include "InputSegment.h" +#include "InputChunks.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/DenseMap.h" @@ -28,7 +28,6 @@ namespace wasm { class OutputSegment; -class InputFunction; class OutputSection { public: Index: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ wasm/OutputSections.cpp @@ -10,8 +10,8 @@ #include "OutputSections.h" #include "Config.h" +#include "InputChunks.h" #include "InputFiles.h" -#include "InputFunction.h" #include "OutputSegment.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" @@ -202,11 +202,11 @@ OS.flush(); BodySize = CodeSectionHeader.size(); - for (InputFunction *Func : Functions) { + for (InputChunk *Func : Functions) { Func->OutputOffset = BodySize; calcRelocations(Func->File, Func->Relocations, Func->OutRelocations, - Func->OutputOffset - Func->Function.CodeSectionOffset); - BodySize += Func->Function.Size; + Func->OutputOffset - Func->getInputSectionOffset()); + BodySize += Func->getSize(); } createHeader(BodySize); @@ -230,24 +230,22 @@ Buf += CodeSectionHeader.size(); // Write code section bodies - parallelForEach(Functions, [ContentsStart](InputFunction *Func) { - ArrayRef Content(Func->File.CodeSection->Content); - memcpy(ContentsStart + Func->OutputOffset, - Content.data() + Func->Function.CodeSectionOffset, - Func->Function.Size); + parallelForEach(Functions, [ContentsStart](InputChunk *Func) { + memcpy(ContentsStart + Func->OutputOffset, Func->getData(), + Func->getSize()); applyRelocations(ContentsStart, Func->OutRelocations); }); } uint32_t CodeSection::numRelocations() const { uint32_t Count = 0; - for (const InputFunction *Func : Functions) + for (const InputChunk *Func : Functions) Count += Func->OutRelocations.size(); return Count; } void CodeSection::writeRelocations(raw_ostream &OS) const { - for (const InputFunction *Func : Functions) + for (const InputChunk *Func : Functions) for (const OutputRelocation &Reloc : Func->OutRelocations) writeReloc(OS, Reloc); } @@ -271,13 +269,12 @@ Segment->setSectionOffset(BodySize); BodySize += Segment->Header.size(); log("Data segment: size=" + Twine(Segment->Size)); - for (InputSegment *InputSeg : Segment->InputSegments) { - uint32_t InputOffset = InputSeg->getInputSectionOffset(); + for (InputChunk *InputSeg : Segment->InputSegments) { uint32_t OutputOffset = Segment->getSectionOffset() + - Segment->Header.size() + - InputSeg->getOutputSegmentOffset(); + Segment->Header.size() + InputSeg->OutputOffset; calcRelocations(InputSeg->File, InputSeg->Relocations, - InputSeg->OutRelocations, OutputOffset - InputOffset); + InputSeg->OutRelocations, + OutputOffset - InputSeg->getInputSectionOffset()); } BodySize += Segment->Size; } @@ -305,11 +302,9 @@ memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); // Write segment data payload - for (const InputSegment *Input : Segment->InputSegments) { - ArrayRef Content(Input->Segment.Data.Content); - memcpy(SegStart + Segment->Header.size() + - Input->getOutputSegmentOffset(), - Content.data(), Content.size()); + for (const InputChunk *Input : Segment->InputSegments) { + memcpy(SegStart + Segment->Header.size() + Input->OutputOffset, + Input->getData(), Input->getSize()); applyRelocations(ContentsStart, Input->OutRelocations); } }); @@ -318,14 +313,14 @@ uint32_t DataSection::numRelocations() const { uint32_t Count = 0; for (const OutputSegment *Seg : Segments) - for (const InputSegment *InputSeg : Seg->InputSegments) + for (const InputChunk *InputSeg : Seg->InputSegments) Count += InputSeg->OutRelocations.size(); return Count; } void DataSection::writeRelocations(raw_ostream &OS) const { for (const OutputSegment *Seg : Segments) - for (const InputSegment *InputSeg : Seg->InputSegments) + for (const InputChunk *InputSeg : Seg->InputSegments) for (const OutputRelocation &Reloc : InputSeg->OutRelocations) writeReloc(OS, Reloc); } Index: wasm/OutputSegment.h =================================================================== --- wasm/OutputSegment.h +++ wasm/OutputSegment.h @@ -10,7 +10,7 @@ #ifndef LLD_WASM_OUTPUT_SEGMENT_H #define LLD_WASM_OUTPUT_SEGMENT_H -#include "InputSegment.h" +#include "InputChunks.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/Wasm.h" Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -10,7 +10,7 @@ #include "SymbolTable.h" #include "Config.h" -#include "InputFunction.h" +#include "InputChunks.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -10,9 +10,8 @@ #include "Symbols.h" #include "Config.h" +#include "InputChunks.h" #include "InputFiles.h" -#include "InputFunction.h" -#include "InputSegment.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -10,7 +10,7 @@ #include "Writer.h" #include "Config.h" -#include "InputFunction.h" +#include "InputChunks.h" #include "OutputSections.h" #include "OutputSegment.h" #include "SymbolTable.h"