summaryrefslogtreecommitdiffstats
path: root/lld/wasm/InputChunks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/wasm/InputChunks.cpp')
-rw-r--r--lld/wasm/InputChunks.cpp91
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);
+ }
+}
OpenPOWER on IntegriCloud