Index: lld/trunk/wasm/InputChunks.h =================================================================== --- lld/trunk/wasm/InputChunks.h +++ lld/trunk/wasm/InputChunks.h @@ -34,17 +34,30 @@ class InputChunk { public: - InputChunk(const ObjFile &F) : File(F) {} - virtual ~InputChunk() = default; + virtual uint32_t getSize() const = 0; + void copyRelocations(const WasmSection &Section); + void writeTo(uint8_t *SectionStart) const; + + void setOutputOffset(uint32_t Offset) { + OutputOffset = Offset; + calcRelocations(); + } + + uint32_t getOutputOffset() const { return OutputOffset; } + + std::vector OutRelocations; + +protected: + InputChunk(const ObjFile &F) : File(F) {} + virtual ~InputChunk() = default; + void calcRelocations(); 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; + int32_t OutputOffset = 0; const ObjFile &File; }; @@ -69,22 +82,24 @@ void setOutputSegment(const OutputSegment *Segment, uint32_t Offset) { OutputSeg = Segment; - OutputOffset = Offset; + OutputSegmentOffset = 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; } + int32_t OutputSegmentOffset = 0; + protected: + uint32_t getInputSectionOffset() const override { + return Segment.SectionOffset; + } const WasmSegment &Segment; const OutputSegment *OutputSeg = nullptr; }; @@ -99,11 +114,8 @@ uint32_t getSize() const override { return Function.Size; } const uint8_t *getData() const override { - return File.CodeSection->Content.data() + Function.CodeSectionOffset; + return File.CodeSection->Content.data() + getInputSectionOffset(); } - uint32_t getInputSectionOffset() const override { - return Function.CodeSectionOffset; - }; uint32_t getOutputIndex() const { return OutputIndex.getValue(); }; bool hasOutputIndex() const { return OutputIndex.hasValue(); }; @@ -115,6 +127,9 @@ const WasmSignature &Signature; protected: + uint32_t getInputSectionOffset() const override { + return Function.CodeSectionOffset; + } const WasmFunction &Function; llvm::Optional OutputIndex; }; Index: lld/trunk/wasm/InputChunks.cpp =================================================================== --- lld/trunk/wasm/InputChunks.cpp +++ lld/trunk/wasm/InputChunks.cpp @@ -8,17 +8,22 @@ //===----------------------------------------------------------------------===// #include "InputChunks.h" +#include "Config.h" #include "OutputSegment.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" +#include "llvm/Support/LEB128.h" #define DEBUG_TYPE "lld" using namespace llvm; +using namespace llvm::wasm; +using namespace lld; using namespace lld::wasm; uint32_t InputSegment::translateVA(uint32_t Address) const { assert(Address >= startVA() && Address < endVA()); - int32_t Delta = OutputSeg->StartVA + OutputOffset - startVA(); + int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA(); DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta << " Address=" << Address << "\n"); return Address + Delta; @@ -31,3 +36,87 @@ if (R.Offset >= Start && R.Offset < Start + Size) Relocations.push_back(R); } + +static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) { + DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type + << " index=" << Reloc.Reloc.Index << " value=" << Reloc.Value + << " offset=" << Reloc.Reloc.Offset << "\n"); + Buf += Reloc.Reloc.Offset; + int64_t ExistingValue; + switch (Reloc.Reloc.Type) { + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + ExistingValue = decodeULEB128(Buf); + if (ExistingValue != Reloc.Reloc.Index) { + DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n"); + assert(decodeULEB128(Buf) == Reloc.Reloc.Index); + } + LLVM_FALLTHROUGH; + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + encodeULEB128(Reloc.Value, Buf, 5); + break; + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + ExistingValue = decodeSLEB128(Buf); + if (ExistingValue != Reloc.Reloc.Index) { + DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n"); + assert(decodeSLEB128(Buf) == Reloc.Reloc.Index); + } + LLVM_FALLTHROUGH; + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + encodeSLEB128(static_cast(Reloc.Value), Buf, 5); + break; + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + support::endian::write32(Buf, Reloc.Value); + break; + default: + llvm_unreachable("unknown relocation type"); + } +} + +static void applyRelocations(uint8_t *Buf, ArrayRef Relocs) { + if (!Relocs.size()) + return; + log("applyRelocations: count=" + Twine(Relocs.size())); + for (const OutputRelocation &Reloc : Relocs) + applyRelocation(Buf, Reloc); +} + +void InputChunk::writeTo(uint8_t *SectionStart) const { + memcpy(SectionStart + getOutputOffset(), getData(), getSize()); + applyRelocations(SectionStart, OutRelocations); +} + +// Populate OutRelocations based on the input relocations and offset within the +// output section. Calculates the updated index and offset for each relocation +// as well as the value to write out in the final binary. +void InputChunk::calcRelocations() { + int32_t Off = getOutputOffset() - getInputSectionOffset(); + log("calcRelocations: " + File.getName() + " offset=" + Twine(Off)); + for (const WasmRelocation &Reloc : Relocations) { + OutputRelocation NewReloc; + NewReloc.Reloc = Reloc; + assert(Reloc.Offset + Off > 0); + NewReloc.Reloc.Offset += Off; + DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index + << " offset=" << Reloc.Offset + << " newOffset=" << NewReloc.Reloc.Offset << "\n"); + + if (Config->EmitRelocs) + NewReloc.NewIndex = File.calcNewIndex(Reloc); + + switch (Reloc.Type) { + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + NewReloc.Value = File.getRelocatedAddress(Reloc.Index) + Reloc.Addend; + break; + default: + NewReloc.Value = File.calcNewIndex(Reloc); + break; + } + + OutRelocations.emplace_back(NewReloc); + } +} Index: lld/trunk/wasm/InputFiles.h =================================================================== --- lld/trunk/wasm/InputFiles.h +++ lld/trunk/wasm/InputFiles.h @@ -28,6 +28,7 @@ using llvm::object::WasmSymbol; using llvm::wasm::WasmImport; using llvm::wasm::WasmSignature; +using llvm::wasm::WasmRelocation; namespace lld { namespace wasm { @@ -91,11 +92,9 @@ void dumpInfo() const; - uint32_t relocateTypeIndex(uint32_t Original) const; uint32_t relocateFunctionIndex(uint32_t Original) const; - uint32_t relocateGlobalIndex(uint32_t Original) const; - uint32_t relocateTableIndex(uint32_t Original) const; uint32_t getRelocatedAddress(uint32_t Index) const; + uint32_t calcNewIndex(const WasmRelocation &Reloc) const; const WasmSection *CodeSection = nullptr; const WasmSection *DataSection = nullptr; @@ -108,6 +107,10 @@ ArrayRef getTableSymbols() { return TableSymbols; } private: + uint32_t relocateTypeIndex(uint32_t Original) const; + uint32_t relocateGlobalIndex(uint32_t Original) const; + uint32_t relocateTableIndex(uint32_t Original) const; + Symbol *createDefined(const WasmSymbol &Sym, Symbol::Kind Kind, const InputSegment *Segment = nullptr, InputFunction *Function = nullptr, Index: lld/trunk/wasm/InputFiles.cpp =================================================================== --- lld/trunk/wasm/InputFiles.cpp +++ lld/trunk/wasm/InputFiles.cpp @@ -83,6 +83,29 @@ return Index; } +// Relocations contain an index into the function, global or table index +// space of the input file. This function takes a relocation and returns the +// relocated index (i.e. translates from the input index space to the output +// index space). +uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const { + switch (Reloc.Type) { + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + return relocateTypeIndex(Reloc.Index); + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + return relocateFunctionIndex(Reloc.Index); + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + return relocateTableIndex(Reloc.Index); + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + return relocateGlobalIndex(Reloc.Index); + default: + llvm_unreachable("unknown relocation type"); + } +} + void ObjFile::parse() { // Parse a memory buffer as a wasm file. DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); Index: lld/trunk/wasm/OutputSections.cpp =================================================================== --- lld/trunk/wasm/OutputSections.cpp +++ lld/trunk/wasm/OutputSections.cpp @@ -9,16 +9,12 @@ #include "OutputSections.h" -#include "Config.h" #include "InputChunks.h" #include "InputFiles.h" #include "OutputSegment.h" -#include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" #include "lld/Common/Threads.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/LEB128.h" #define DEBUG_TYPE "lld" @@ -27,12 +23,6 @@ using namespace lld; using namespace lld::wasm; -enum class RelocEncoding { - Uleb128, - Sleb128, - I32, -}; - static StringRef sectionTypeToString(uint32_t SectionType) { switch (SectionType) { case WASM_SEC_CUSTOM: @@ -71,110 +61,6 @@ return rtn; } -static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) { - DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type - << " index=" << Reloc.Reloc.Index << " value=" << Reloc.Value - << " offset=" << Reloc.Reloc.Offset << "\n"); - Buf += Reloc.Reloc.Offset; - int64_t ExistingValue; - switch (Reloc.Reloc.Type) { - case R_WEBASSEMBLY_TYPE_INDEX_LEB: - case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - ExistingValue = decodeULEB128(Buf); - if (ExistingValue != Reloc.Reloc.Index) { - DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n"); - assert(decodeULEB128(Buf) == Reloc.Reloc.Index); - } - LLVM_FALLTHROUGH; - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - encodeULEB128(Reloc.Value, Buf, 5); - break; - case R_WEBASSEMBLY_TABLE_INDEX_SLEB: - ExistingValue = decodeSLEB128(Buf); - if (ExistingValue != Reloc.Reloc.Index) { - DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n"); - assert(decodeSLEB128(Buf) == Reloc.Reloc.Index); - } - LLVM_FALLTHROUGH; - case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - encodeSLEB128(static_cast(Reloc.Value), Buf, 5); - break; - case R_WEBASSEMBLY_TABLE_INDEX_I32: - case R_WEBASSEMBLY_MEMORY_ADDR_I32: - support::endian::write32(Buf, Reloc.Value); - break; - default: - llvm_unreachable("unknown relocation type"); - } -} - -static void applyRelocations(uint8_t *Buf, ArrayRef Relocs) { - if (!Relocs.size()) - return; - log("applyRelocations: count=" + Twine(Relocs.size())); - for (const OutputRelocation &Reloc : Relocs) - applyRelocation(Buf, Reloc); -} - -// Relocations contain an index into the function, global or table index -// space of the input file. This function takes a relocation and returns the -// relocated index (i.e. translates from the input index space to the output -// index space). -static uint32_t calcNewIndex(const ObjFile &File, const WasmRelocation &Reloc) { - switch (Reloc.Type) { - case R_WEBASSEMBLY_TYPE_INDEX_LEB: - return File.relocateTypeIndex(Reloc.Index); - case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - return File.relocateFunctionIndex(Reloc.Index); - case R_WEBASSEMBLY_TABLE_INDEX_I32: - case R_WEBASSEMBLY_TABLE_INDEX_SLEB: - return File.relocateTableIndex(Reloc.Index); - case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case R_WEBASSEMBLY_MEMORY_ADDR_I32: - return File.relocateGlobalIndex(Reloc.Index); - default: - llvm_unreachable("unknown relocation type"); - } -} - -// Take a vector of relocations from an input file and create output -// relocations based on them. Calculates the updated index and offset for -// each relocation as well as the value to write out in the final binary. -static void calcRelocations(const ObjFile &File, - ArrayRef Relocs, - std::vector &OutputRelocs, - int32_t OutputOffset) { - log("calcRelocations: " + File.getName() + " offset=" + Twine(OutputOffset)); - for (const WasmRelocation &Reloc : Relocs) { - OutputRelocation NewReloc; - NewReloc.Reloc = Reloc; - assert(Reloc.Offset + OutputOffset > 0); - NewReloc.Reloc.Offset += OutputOffset; - DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index - << " offset=" << Reloc.Offset - << " newOffset=" << NewReloc.Reloc.Offset << "\n"); - - if (Config->EmitRelocs) - NewReloc.NewIndex = calcNewIndex(File, Reloc); - - switch (Reloc.Type) { - case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case R_WEBASSEMBLY_MEMORY_ADDR_I32: - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - NewReloc.Value = File.getRelocatedAddress(Reloc.Index) + Reloc.Addend; - break; - default: - NewReloc.Value = calcNewIndex(File, Reloc); - break; - } - - OutputRelocs.emplace_back(NewReloc); - } -} - std::string OutputSection::getSectionName() const { return sectionTypeToString(Type); } @@ -203,9 +89,7 @@ BodySize = CodeSectionHeader.size(); for (InputChunk *Func : Functions) { - Func->OutputOffset = BodySize; - calcRelocations(Func->File, Func->Relocations, Func->OutRelocations, - Func->OutputOffset - Func->getInputSectionOffset()); + Func->setOutputOffset(BodySize); BodySize += Func->getSize(); } @@ -230,10 +114,8 @@ Buf += CodeSectionHeader.size(); // Write code section bodies - parallelForEach(Functions, [ContentsStart](InputChunk *Func) { - memcpy(ContentsStart + Func->OutputOffset, Func->getData(), - Func->getSize()); - applyRelocations(ContentsStart, Func->OutRelocations); + parallelForEach(Functions, [ContentsStart](const InputChunk *Chunk) { + Chunk->writeTo(ContentsStart); }); } @@ -267,16 +149,12 @@ writeUleb128(OS, Segment->Size, "segment size"); OS.flush(); Segment->setSectionOffset(BodySize); - BodySize += Segment->Header.size(); + BodySize += Segment->Header.size() + Segment->Size; log("Data segment: size=" + Twine(Segment->Size)); - for (InputChunk *InputSeg : Segment->InputSegments) { - uint32_t OutputOffset = Segment->getSectionOffset() + - Segment->Header.size() + InputSeg->OutputOffset; - calcRelocations(InputSeg->File, InputSeg->Relocations, - InputSeg->OutRelocations, - OutputOffset - InputSeg->getInputSectionOffset()); - } - BodySize += Segment->Size; + for (InputSegment *InputSeg : Segment->InputSegments) + InputSeg->setOutputOffset(Segment->getSectionOffset() + + Segment->Header.size() + + InputSeg->OutputSegmentOffset); } createHeader(BodySize); @@ -302,11 +180,8 @@ memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); // Write segment data payload - for (const InputChunk *Input : Segment->InputSegments) { - memcpy(SegStart + Segment->Header.size() + Input->OutputOffset, - Input->getData(), Input->getSize()); - applyRelocations(ContentsStart, Input->OutRelocations); - } + for (const InputChunk *Chunk : Segment->InputSegments) + Chunk->writeTo(ContentsStart); }); }