mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-24 14:20:17 +00:00
[WebAssembly] Add InputChunk as common base class for InputSegment and InputFunction. NFC.
Differential Revision: https://reviews.llvm.org/D41419 llvm-svn: 322148
This commit is contained in:
parent
050b4b05a0
commit
5fa274bea4
@ -4,8 +4,8 @@ add_public_tablegen_target(WasmOptionsTableGen)
|
||||
|
||||
add_lld_library(lldWasm
|
||||
Driver.cpp
|
||||
InputChunks.cpp
|
||||
InputFiles.cpp
|
||||
InputSegment.cpp
|
||||
OutputSections.cpp
|
||||
SymbolTable.cpp
|
||||
Symbols.cpp
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "InputSegment.h"
|
||||
#include "InputChunks.h"
|
||||
#include "OutputSegment.h"
|
||||
#include "lld/Common/LLVM.h"
|
||||
|
||||
@ -18,8 +18,16 @@ using namespace lld::wasm;
|
||||
|
||||
uint32_t InputSegment::translateVA(uint32_t Address) const {
|
||||
assert(Address >= startVA() && Address < endVA());
|
||||
int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA();
|
||||
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);
|
||||
}
|
125
lld/wasm/InputChunks.h
Normal file
125
lld/wasm/InputChunks.h
Normal file
@ -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<WasmRelocation> Relocations;
|
||||
std::vector<OutputRelocation> 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<uint32_t> OutputIndex;
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_WASM_INPUT_CHUNKS_H
|
@ -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 @@ InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void copyRelocationsRange(std::vector<WasmRelocation> &To,
|
||||
ArrayRef<WasmRelocation> 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 @@ void ObjFile::initializeSymbols() {
|
||||
|
||||
for (const WasmSegment &S : WasmObj->dataSegments()) {
|
||||
InputSegment *Seg = make<InputSegment>(S, *this);
|
||||
copyRelocationsRange(Seg->Relocations, DataSection->Relocations,
|
||||
Seg->getInputSectionOffset(), Seg->getSize());
|
||||
Seg->copyRelocations(*DataSection);
|
||||
Segments.emplace_back(Seg);
|
||||
}
|
||||
|
||||
@ -186,10 +176,9 @@ void ObjFile::initializeSymbols() {
|
||||
for (size_t I = 0; I < Funcs.size(); ++I) {
|
||||
const WasmFunction &Func = Funcs[I];
|
||||
const WasmSignature &Sig = Types[FuncTypes[I]];
|
||||
InputFunction *Function = make<InputFunction>(Sig, Func, *this);
|
||||
copyRelocationsRange(Function->Relocations, CodeSection->Relocations,
|
||||
Func.CodeSectionOffset, Func.Size);
|
||||
Functions.emplace_back(Function);
|
||||
InputFunction *F = make<InputFunction>(Sig, Func, *this);
|
||||
F->copyRelocations(*CodeSection);
|
||||
Functions.emplace_back(F);
|
||||
}
|
||||
|
||||
// Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols
|
||||
|
@ -98,6 +98,7 @@ public:
|
||||
uint32_t getRelocatedAddress(uint32_t Index) const;
|
||||
|
||||
const WasmSection *CodeSection = nullptr;
|
||||
const WasmSection *DataSection = nullptr;
|
||||
|
||||
std::vector<uint32_t> TypeMap;
|
||||
std::vector<InputSegment *> Segments;
|
||||
@ -131,7 +132,6 @@ private:
|
||||
// List of all indirect symbols indexed by table index space.
|
||||
std::vector<Symbol *> TableSymbols;
|
||||
|
||||
const WasmSection *DataSection = nullptr;
|
||||
uint32_t NumGlobalImports = 0;
|
||||
uint32_t NumFunctionImports = 0;
|
||||
std::unique_ptr<WasmObjectFile> WasmObj;
|
||||
|
@ -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<WasmRelocation> Relocations;
|
||||
std::vector<OutputRelocation> OutRelocations;
|
||||
const ObjFile &File;
|
||||
|
||||
protected:
|
||||
llvm::Optional<uint32_t> OutputIndex;
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_WASM_INPUT_FUNCTION_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<WasmRelocation> Relocations;
|
||||
std::vector<OutputRelocation> OutRelocations;
|
||||
|
||||
protected:
|
||||
const OutputSegment *OutputSeg = nullptr;
|
||||
uint32_t OutputSegmentOffset = 0;
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_WASM_INPUT_SEGMENT_H
|
@ -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 @@ CodeSection::CodeSection(ArrayRef<InputFunction *> Functions)
|
||||
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 @@ void CodeSection::writeTo(uint8_t *Buf) {
|
||||
Buf += CodeSectionHeader.size();
|
||||
|
||||
// Write code section bodies
|
||||
parallelForEach(Functions, [ContentsStart](InputFunction *Func) {
|
||||
ArrayRef<uint8_t> 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 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
|
||||
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 @@ void DataSection::writeTo(uint8_t *Buf) {
|
||||
memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
|
||||
|
||||
// Write segment data payload
|
||||
for (const InputSegment *Input : Segment->InputSegments) {
|
||||
ArrayRef<uint8_t> 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 @@ void DataSection::writeTo(uint8_t *Buf) {
|
||||
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);
|
||||
}
|
||||
|
@ -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 @@ std::string toString(const wasm::OutputSection &Section);
|
||||
namespace wasm {
|
||||
|
||||
class OutputSegment;
|
||||
class InputFunction;
|
||||
|
||||
class OutputSection {
|
||||
public:
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user