Index: lld/wasm/InputChunks.h =================================================================== --- lld/wasm/InputChunks.h +++ lld/wasm/InputChunks.h @@ -27,6 +27,10 @@ using llvm::wasm::WasmSignature; using llvm::object::WasmSection; +namespace llvm { +class raw_ostream; +} + namespace lld { namespace wasm { @@ -45,10 +49,7 @@ void writeTo(uint8_t *SectionStart) const; - void setOutputOffset(uint32_t Offset) { - OutputOffset = Offset; - calcRelocations(); - } + void setOutputOffset(uint32_t Offset) { OutputOffset = Offset; } uint32_t getOutputOffset() const { return OutputOffset; } ArrayRef getRelocations() const { return Relocations; } @@ -56,7 +57,9 @@ virtual StringRef getComdat() const = 0; virtual StringRef getName() const = 0; - std::vector OutRelocations; + size_t NumRelocations() const { return Relocations.size(); } + void writeRelocations(llvm::raw_ostream &OS) const; + ObjFile *File; // Signals that the section is part of the output. The garbage collector, @@ -68,7 +71,6 @@ InputChunk(ObjFile *F, Kind K) : File(F), Live(!Config->GcSections), SectionKind(K) {} virtual ~InputChunk() = default; - void calcRelocations(); virtual ArrayRef data() const = 0; virtual uint32_t getInputSectionOffset() const = 0; Index: lld/wasm/InputChunks.cpp =================================================================== --- lld/wasm/InputChunks.cpp +++ lld/wasm/InputChunks.cpp @@ -10,6 +10,7 @@ #include "InputChunks.h" #include "Config.h" #include "OutputSegment.h" +#include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "llvm/Support/LEB128.h" @@ -44,76 +45,70 @@ 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; - - switch (Reloc.Reloc.Type) { - case R_WEBASSEMBLY_TYPE_INDEX_LEB: - case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - // Additional check to verify that the existing value that the location - // matches our expectations. - if (decodeULEB128(Buf) != Reloc.Reloc.Index) { - DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n"); - assert(decodeULEB128(Buf) == Reloc.Reloc.Index); - } - LLVM_FALLTHROUGH; - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - encodeULEB128(Reloc.Value, Buf, 5); - break; - case R_WEBASSEMBLY_TABLE_INDEX_SLEB: - 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: - write32le(Buf, Reloc.Value); - break; - default: - llvm_unreachable("unknown relocation type"); - } -} - -// Copy this input chunk to an mmap'ed output file. +// Copy this input chunk to an mmap'ed output file and apply relocations. void InputChunk::writeTo(uint8_t *Buf) const { // Copy contents memcpy(Buf + getOutputOffset(), data().data(), data().size()); // Apply relocations - if (OutRelocations.empty()) + if (Relocations.empty()) return; - DEBUG(dbgs() << "applyRelocations: count=" << OutRelocations.size() << "\n"); - for (const OutputRelocation &Reloc : OutRelocations) - applyRelocation(Buf, Reloc); + + DEBUG(dbgs() << "applyRelocations: count=" << Relocations.size() << "\n"); + int32_t Off = getOutputOffset() - getInputSectionOffset(); + + for (const WasmRelocation &Rel : Relocations) { + uint8_t *Loc = Buf + Rel.Offset + Off; + uint64_t Value = File->calcNewValue(Rel); + + DEBUG(dbgs() << "write reloc: type=" << Rel.Type << " index=" << Rel.Index + << " value=" << Value << " offset=" << Rel.Offset << "\n"); + + switch (Rel.Type) { + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + encodeULEB128(Value, Loc, 5); + break; + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + encodeSLEB128(static_cast(Value), Loc, 5); + break; + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + write32le(Loc, Value); + break; + default: + llvm_unreachable("unknown relocation type"); + } + } } -// 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() { +// Copy relocation entries to a given output stream. +// This function is not invoked when we are doing a regular link because +// we consume relocations instead of copying them to an output file. +// So, this function is used only when a user passes "-r". +void InputChunk::writeRelocations(raw_ostream &OS) const { if (Relocations.empty()) return; + int32_t Off = getOutputOffset() - getInputSectionOffset(); - DEBUG(dbgs() << "calcRelocations: " << File->getName() + DEBUG(dbgs() << "writeRelocations: " << File->getName() << " offset=" << Twine(Off) << "\n"); - 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->Relocatable) - NewReloc.NewIndex = File->calcNewIndex(Reloc); - - NewReloc.Value = File->calcNewValue(Reloc); - OutRelocations.emplace_back(NewReloc); + + for (const WasmRelocation &Rel : Relocations) { + writeUleb128(OS, Rel.Type, "reloc type"); + writeUleb128(OS, Rel.Offset + Off, "reloc offset"); + writeUleb128(OS, File->calcNewIndex(Rel), "reloc index"); + + switch (Rel.Type) { + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + writeUleb128(OS, Rel.Addend, "reloc addend"); + break; + } } } Index: lld/wasm/OutputSections.cpp =================================================================== --- lld/wasm/OutputSections.cpp +++ lld/wasm/OutputSections.cpp @@ -123,14 +123,13 @@ uint32_t CodeSection::numRelocations() const { uint32_t Count = 0; for (const InputChunk *Func : Functions) - Count += Func->OutRelocations.size(); + Count += Func->NumRelocations(); return Count; } void CodeSection::writeRelocations(raw_ostream &OS) const { - for (const InputChunk *Func : Functions) - for (const OutputRelocation &Reloc : Func->OutRelocations) - writeReloc(OS, Reloc); + for (const InputChunk *C : Functions) + C->writeRelocations(OS); } DataSection::DataSection(ArrayRef Segments) @@ -190,13 +189,12 @@ uint32_t Count = 0; for (const OutputSegment *Seg : Segments) for (const InputChunk *InputSeg : Seg->InputSegments) - Count += InputSeg->OutRelocations.size(); + Count += InputSeg->NumRelocations(); return Count; } void DataSection::writeRelocations(raw_ostream &OS) const { for (const OutputSegment *Seg : Segments) - for (const InputChunk *InputSeg : Seg->InputSegments) - for (const OutputRelocation &Reloc : InputSeg->OutRelocations) - writeReloc(OS, Reloc); + for (const InputChunk *C : Seg->InputSegments) + C->writeRelocations(OS); }