diff options
Diffstat (limited to 'lld/wasm/InputChunks.cpp')
-rw-r--r-- | lld/wasm/InputChunks.cpp | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp index 3c856714b28..077d7ec2ce8 100644 --- a/lld/wasm/InputChunks.cpp +++ b/lld/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 @@ void InputChunk::copyRelocations(const WasmSection &Section) { 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<int32_t>(Reloc.Value), Buf, 5); + break; + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + support::endian::write32<support::little>(Buf, Reloc.Value); + break; + default: + llvm_unreachable("unknown relocation type"); + } +} + +static void applyRelocations(uint8_t *Buf, ArrayRef<OutputRelocation> 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); + } +} |