blob: 9a058759cf843efcdbbb4040a06bde29518be95b [file] [log] [blame]
Sam Cleggf61910d2018-01-12 22:18:22 +00001//===- InputChunks.cpp ----------------------------------------------------===//
Sam Cleggc94d3932017-11-17 18:14:09 +00002//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Sam Clegg5fa274b2018-01-10 01:13:34 +000010#include "InputChunks.h"
Sam Cleggd96d9352018-01-10 19:22:42 +000011#include "Config.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000012#include "OutputSegment.h"
Rui Ueyamabf450d92018-02-20 04:26:26 +000013#include "WriterUtils.h"
Sam Cleggd96d9352018-01-10 19:22:42 +000014#include "lld/Common/ErrorHandler.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000015#include "lld/Common/LLVM.h"
Sam Cleggd96d9352018-01-10 19:22:42 +000016#include "llvm/Support/LEB128.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000017
18#define DEBUG_TYPE "lld"
19
20using namespace llvm;
Sam Cleggd96d9352018-01-10 19:22:42 +000021using namespace llvm::wasm;
Rui Ueyamae351c3a2018-02-16 20:38:15 +000022using namespace llvm::support::endian;
Sam Cleggd96d9352018-01-10 19:22:42 +000023using namespace lld;
Sam Cleggc94d3932017-11-17 18:14:09 +000024using namespace lld::wasm;
25
Rui Ueyama81bee042018-02-19 22:29:48 +000026std::string lld::toString(const InputChunk *C) {
27 return (toString(C->File) + ":(" + C->getName() + ")").str();
28}
29
Sam Cleggc94d3932017-11-17 18:14:09 +000030uint32_t InputSegment::translateVA(uint32_t Address) const {
31 assert(Address >= startVA() && Address < endVA());
Sam Cleggd96d9352018-01-10 19:22:42 +000032 int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA();
Sam Cleggc94d3932017-11-17 18:14:09 +000033 DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta
34 << " Address=" << Address << "\n");
35 return Address + Delta;
36}
Sam Clegg5fa274b2018-01-10 01:13:34 +000037
38void InputChunk::copyRelocations(const WasmSection &Section) {
Sam Clegg50686852018-01-12 18:35:13 +000039 if (Section.Relocations.empty())
40 return;
Sam Clegg5fa274b2018-01-10 01:13:34 +000041 size_t Start = getInputSectionOffset();
42 size_t Size = getSize();
43 for (const WasmRelocation &R : Section.Relocations)
44 if (R.Offset >= Start && R.Offset < Start + Size)
45 Relocations.push_back(R);
46}
Sam Cleggd96d9352018-01-10 19:22:42 +000047
Rui Ueyamabf450d92018-02-20 04:26:26 +000048// Copy this input chunk to an mmap'ed output file and apply relocations.
49void InputChunk::writeTo(uint8_t *Buf) const {
50 // Copy contents
51 memcpy(Buf + OutputOffset, data().data(), data().size());
Rui Ueyamac06d94a2018-02-19 22:39:52 +000052
Rui Ueyamabf450d92018-02-20 04:26:26 +000053 // Apply relocations
54 if (Relocations.empty())
55 return;
Rui Ueyamac06d94a2018-02-19 22:39:52 +000056
Rui Ueyamabf450d92018-02-20 04:26:26 +000057 DEBUG(dbgs() << "applyRelocations: count=" << Relocations.size() << "\n");
58 int32_t Off = OutputOffset - getInputSectionOffset();
59
60 for (const WasmRelocation &Rel : Relocations) {
61 uint8_t *Loc = Buf + Rel.Offset + Off;
62 uint64_t Value = File->calcNewValue(Rel);
63
64 DEBUG(dbgs() << "write reloc: type=" << Rel.Type << " index=" << Rel.Index
65 << " value=" << Value << " offset=" << Rel.Offset << "\n");
66
67 switch (Rel.Type) {
68 case R_WEBASSEMBLY_TYPE_INDEX_LEB:
69 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
70 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
71 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
72 encodeULEB128(Value, Loc, 5);
73 break;
74 case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
75 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
76 encodeSLEB128(static_cast<int32_t>(Value), Loc, 5);
77 break;
78 case R_WEBASSEMBLY_TABLE_INDEX_I32:
79 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
80 write32le(Loc, Value);
81 break;
82 default:
83 llvm_unreachable("unknown relocation type");
Sam Cleggd96d9352018-01-10 19:22:42 +000084 }
Sam Cleggd96d9352018-01-10 19:22:42 +000085 }
86}
87
Rui Ueyamabf450d92018-02-20 04:26:26 +000088// Copy relocation entries to a given output stream.
89// This function is used only when a user passes "-r". For a regular link,
90// we consume relocations instead of copying them to an output file.
91void InputChunk::writeRelocations(raw_ostream &OS) const {
Sam Clegg50686852018-01-12 18:35:13 +000092 if (Relocations.empty())
93 return;
Rui Ueyamabf450d92018-02-20 04:26:26 +000094
95 int32_t Off = OutputOffset - getInputSectionOffset();
96 DEBUG(dbgs() << "writeRelocations: " << File->getName()
Sam Clegg7ed293e2018-01-12 00:34:04 +000097 << " offset=" << Twine(Off) << "\n");
Sam Cleggd96d9352018-01-10 19:22:42 +000098
Rui Ueyamabf450d92018-02-20 04:26:26 +000099 for (const WasmRelocation &Rel : Relocations) {
100 writeUleb128(OS, Rel.Type, "reloc type");
101 writeUleb128(OS, Rel.Offset + Off, "reloc offset");
102 writeUleb128(OS, File->calcNewIndex(Rel), "reloc index");
Sam Cleggd96d9352018-01-10 19:22:42 +0000103
Rui Ueyamabf450d92018-02-20 04:26:26 +0000104 switch (Rel.Type) {
105 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
106 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
107 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
108 writeUleb128(OS, Rel.Addend, "reloc addend");
109 break;
110 }
Sam Cleggd96d9352018-01-10 19:22:42 +0000111 }
112}
Sam Clegg50686852018-01-12 18:35:13 +0000113
114void InputFunction::setOutputIndex(uint32_t Index) {
Sam Cleggfadf5182018-01-28 19:57:03 +0000115 DEBUG(dbgs() << "InputFunction::setOutputIndex: " << getName() << " -> " << Index << "\n");
Sam Clegg50686852018-01-12 18:35:13 +0000116 assert(!hasOutputIndex());
117 OutputIndex = Index;
Eric Christopher9ea500b2018-01-13 00:44:45 +0000118}
Sam Clegg67abf532018-01-24 21:45:25 +0000119
120void InputFunction::setTableIndex(uint32_t Index) {
Sam Cleggfadf5182018-01-28 19:57:03 +0000121 DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> " << Index << "\n");
Sam Clegg67abf532018-01-24 21:45:25 +0000122 assert(!hasTableIndex());
123 TableIndex = Index;
124}