Index: wasm/InputChunks.h =================================================================== --- wasm/InputChunks.h +++ wasm/InputChunks.h @@ -34,17 +34,30 @@ 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; + + 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 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: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ wasm/InputChunks.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "Config.h" #include "InputChunks.h" #include "OutputSegment.h" #include "lld/Common/LLVM.h" @@ -14,11 +15,12 @@ #define DEBUG_TYPE "lld" using namespace llvm; +using namespace llvm::wasm; 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 +33,36 @@ if (R.Offset >= Start && R.Offset < Start + Size) Relocations.push_back(R); } + +// 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: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ 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: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ 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: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ wasm/OutputSections.cpp @@ -117,62 +117,10 @@ 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); - } +static void writeChunk(const InputChunk &Chunk, uint8_t *SectionStart) { + memcpy(SectionStart + Chunk.getOutputOffset(), Chunk.getData(), + Chunk.getSize()); + applyRelocations(SectionStart, Chunk.OutRelocations); } std::string OutputSection::getSectionName() const { @@ -203,9 +151,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 +176,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) { + writeChunk(*Chunk, ContentsStart); }); } @@ -267,16 +211,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 +242,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) + writeChunk(*Chunk, ContentsStart); }); }