blob: 150d47a72f3102b4273aa6c2c7d75a2783c5711e [file] [log] [blame]
Sam Cleggc94d3932017-11-17 18:14:09 +00001//===- OutputSections.cpp -------------------------------------------------===//
2//
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
10#include "OutputSections.h"
11
12#include "Config.h"
13#include "InputFiles.h"
Sam Clegg8d146bb2018-01-09 23:56:44 +000014#include "InputFunction.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000015#include "OutputSegment.h"
16#include "SymbolTable.h"
17#include "lld/Common/ErrorHandler.h"
Rui Ueyama2017d522017-11-28 20:39:17 +000018#include "lld/Common/Memory.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000019#include "lld/Common/Threads.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/Support/LEB128.h"
22
23#define DEBUG_TYPE "lld"
24
25using namespace llvm;
26using namespace llvm::wasm;
27using namespace lld;
28using namespace lld::wasm;
29
30enum class RelocEncoding {
31 Uleb128,
32 Sleb128,
33 I32,
34};
35
36static StringRef sectionTypeToString(uint32_t SectionType) {
37 switch (SectionType) {
38 case WASM_SEC_CUSTOM:
39 return "CUSTOM";
40 case WASM_SEC_TYPE:
41 return "TYPE";
42 case WASM_SEC_IMPORT:
43 return "IMPORT";
44 case WASM_SEC_FUNCTION:
45 return "FUNCTION";
46 case WASM_SEC_TABLE:
47 return "TABLE";
48 case WASM_SEC_MEMORY:
49 return "MEMORY";
50 case WASM_SEC_GLOBAL:
51 return "GLOBAL";
52 case WASM_SEC_EXPORT:
53 return "EXPORT";
54 case WASM_SEC_START:
55 return "START";
56 case WASM_SEC_ELEM:
57 return "ELEM";
58 case WASM_SEC_CODE:
59 return "CODE";
60 case WASM_SEC_DATA:
61 return "DATA";
62 default:
63 fatal("invalid section type");
64 }
65}
66
Sam Cleggab2ac292017-12-20 05:14:48 +000067std::string lld::toString(const OutputSection &Section) {
68 std::string rtn = Section.getSectionName();
69 if (!Section.Name.empty())
70 rtn += "(" + Section.Name + ")";
Sam Cleggc94d3932017-11-17 18:14:09 +000071 return rtn;
72}
73
74static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) {
75 DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type
Sam Clegg74fe0ba2017-12-07 01:51:24 +000076 << " index=" << Reloc.Reloc.Index << " value=" << Reloc.Value
77 << " offset=" << Reloc.Reloc.Offset << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +000078 Buf += Reloc.Reloc.Offset;
79 int64_t ExistingValue;
80 switch (Reloc.Reloc.Type) {
81 case R_WEBASSEMBLY_TYPE_INDEX_LEB:
82 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
83 ExistingValue = decodeULEB128(Buf);
84 if (ExistingValue != Reloc.Reloc.Index) {
85 DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n");
86 assert(decodeULEB128(Buf) == Reloc.Reloc.Index);
87 }
88 LLVM_FALLTHROUGH;
89 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
90 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
91 encodeULEB128(Reloc.Value, Buf, 5);
92 break;
93 case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
94 ExistingValue = decodeSLEB128(Buf);
95 if (ExistingValue != Reloc.Reloc.Index) {
96 DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n");
97 assert(decodeSLEB128(Buf) == Reloc.Reloc.Index);
98 }
99 LLVM_FALLTHROUGH;
100 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
101 encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5);
102 break;
103 case R_WEBASSEMBLY_TABLE_INDEX_I32:
104 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
105 support::endian::write32<support::little>(Buf, Reloc.Value);
106 break;
107 default:
108 llvm_unreachable("unknown relocation type");
109 }
110}
111
Sam Cleggca16b732017-12-18 20:20:24 +0000112static void applyRelocations(uint8_t *Buf, ArrayRef<OutputRelocation> Relocs) {
Sam Clegg5e8cba92017-12-19 20:45:15 +0000113 if (!Relocs.size())
114 return;
Sam Cleggc94d3932017-11-17 18:14:09 +0000115 log("applyRelocations: count=" + Twine(Relocs.size()));
Sam Clegg5e8cba92017-12-19 20:45:15 +0000116 for (const OutputRelocation &Reloc : Relocs)
Sam Cleggc94d3932017-11-17 18:14:09 +0000117 applyRelocation(Buf, Reloc);
Sam Cleggc94d3932017-11-17 18:14:09 +0000118}
119
120// Relocations contain an index into the function, global or table index
121// space of the input file. This function takes a relocation and returns the
122// relocated index (i.e. translates from the input index space to the output
123// index space).
124static uint32_t calcNewIndex(const ObjFile &File, const WasmRelocation &Reloc) {
125 switch (Reloc.Type) {
126 case R_WEBASSEMBLY_TYPE_INDEX_LEB:
127 return File.relocateTypeIndex(Reloc.Index);
128 case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
129 return File.relocateFunctionIndex(Reloc.Index);
130 case R_WEBASSEMBLY_TABLE_INDEX_I32:
131 case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
132 return File.relocateTableIndex(Reloc.Index);
133 case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
134 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
135 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
136 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
137 return File.relocateGlobalIndex(Reloc.Index);
138 default:
139 llvm_unreachable("unknown relocation type");
140 }
141}
142
143// Take a vector of relocations from an input file and create output
144// relocations based on them. Calculates the updated index and offset for
145// each relocation as well as the value to write out in the final binary.
146static void calcRelocations(const ObjFile &File,
147 ArrayRef<WasmRelocation> Relocs,
148 std::vector<OutputRelocation> &OutputRelocs,
149 int32_t OutputOffset) {
150 log("calcRelocations: " + File.getName() + " offset=" + Twine(OutputOffset));
151 for (const WasmRelocation &Reloc : Relocs) {
Sam Cleggc94d3932017-11-17 18:14:09 +0000152 OutputRelocation NewReloc;
153 NewReloc.Reloc = Reloc;
Sam Clegg8d146bb2018-01-09 23:56:44 +0000154 assert(Reloc.Offset + OutputOffset > 0);
Sam Cleggc94d3932017-11-17 18:14:09 +0000155 NewReloc.Reloc.Offset += OutputOffset;
Sam Cleggc94d3932017-11-17 18:14:09 +0000156 DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index
Sam Clegg74fe0ba2017-12-07 01:51:24 +0000157 << " offset=" << Reloc.Offset
Sam Cleggc94d3932017-11-17 18:14:09 +0000158 << " newOffset=" << NewReloc.Reloc.Offset << "\n");
159
Sam Clegg74fe0ba2017-12-07 01:51:24 +0000160 if (Config->EmitRelocs)
161 NewReloc.NewIndex = calcNewIndex(File, Reloc);
Sam Clegg74fe0ba2017-12-07 01:51:24 +0000162
Sam Cleggc94d3932017-11-17 18:14:09 +0000163 switch (Reloc.Type) {
164 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
165 case R_WEBASSEMBLY_MEMORY_ADDR_I32:
166 case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
Sam Clegg87e61922018-01-08 23:39:11 +0000167 NewReloc.Value = File.getRelocatedAddress(Reloc.Index) + Reloc.Addend;
Sam Cleggc94d3932017-11-17 18:14:09 +0000168 break;
169 default:
Sam Clegg74fe0ba2017-12-07 01:51:24 +0000170 NewReloc.Value = calcNewIndex(File, Reloc);
171 break;
Sam Cleggc94d3932017-11-17 18:14:09 +0000172 }
173
174 OutputRelocs.emplace_back(NewReloc);
175 }
176}
177
Sam Cleggab2ac292017-12-20 05:14:48 +0000178std::string OutputSection::getSectionName() const {
Sam Clegg0d0dd392017-12-19 17:09:45 +0000179 return sectionTypeToString(Type);
180}
181
Sam Cleggab2ac292017-12-20 05:14:48 +0000182std::string SubSection::getSectionName() const {
Sam Clegg0d0dd392017-12-19 17:09:45 +0000183 return std::string("subsection <type=") + std::to_string(Type) + ">";
184}
185
Sam Cleggc94d3932017-11-17 18:14:09 +0000186void OutputSection::createHeader(size_t BodySize) {
187 raw_string_ostream OS(Header);
Sam Clegg0d0dd392017-12-19 17:09:45 +0000188 debugWrite(OS.tell(), "section type [" + Twine(getSectionName()) + "]");
Sam Cleggc94d3932017-11-17 18:14:09 +0000189 writeUleb128(OS, Type, nullptr);
190 writeUleb128(OS, BodySize, "section size");
191 OS.flush();
Sam Cleggab2ac292017-12-20 05:14:48 +0000192 log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
Sam Cleggc94d3932017-11-17 18:14:09 +0000193 " total=" + Twine(getSize()));
194}
195
Sam Clegg8d146bb2018-01-09 23:56:44 +0000196CodeSection::CodeSection(ArrayRef<InputFunction *> Functions)
197 : OutputSection(WASM_SEC_CODE), Functions(Functions) {
198 assert(Functions.size() > 0);
199
Sam Cleggc94d3932017-11-17 18:14:09 +0000200 raw_string_ostream OS(CodeSectionHeader);
Sam Clegg8d146bb2018-01-09 23:56:44 +0000201 writeUleb128(OS, Functions.size(), "function count");
Sam Cleggc94d3932017-11-17 18:14:09 +0000202 OS.flush();
203 BodySize = CodeSectionHeader.size();
204
Sam Clegg8d146bb2018-01-09 23:56:44 +0000205 for (InputFunction *Func : Functions) {
206 Func->OutputOffset = BodySize;
207 calcRelocations(Func->File, Func->Relocations, Func->OutRelocations,
208 Func->OutputOffset - Func->Function.CodeSectionOffset);
209 BodySize += Func->Function.Size;
Sam Cleggc94d3932017-11-17 18:14:09 +0000210 }
211
212 createHeader(BodySize);
213}
214
215void CodeSection::writeTo(uint8_t *Buf) {
Sam Cleggab2ac292017-12-20 05:14:48 +0000216 log("writing " + toString(*this));
Sam Cleggc94d3932017-11-17 18:14:09 +0000217 log(" size=" + Twine(getSize()));
Sam Clegg8d146bb2018-01-09 23:56:44 +0000218 log(" headersize=" + Twine(Header.size()));
219 log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
Sam Cleggc94d3932017-11-17 18:14:09 +0000220 Buf += Offset;
221
222 // Write section header
223 memcpy(Buf, Header.data(), Header.size());
224 Buf += Header.size();
225
226 uint8_t *ContentsStart = Buf;
227
228 // Write code section headers
229 memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
230 Buf += CodeSectionHeader.size();
231
232 // Write code section bodies
Sam Clegg8d146bb2018-01-09 23:56:44 +0000233 parallelForEach(Functions, [ContentsStart](InputFunction *Func) {
234 ArrayRef<uint8_t> Content(Func->File.CodeSection->Content);
235 memcpy(ContentsStart + Func->OutputOffset,
236 Content.data() + Func->Function.CodeSectionOffset,
237 Func->Function.Size);
238 applyRelocations(ContentsStart, Func->OutRelocations);
Sam Cleggc94d3932017-11-17 18:14:09 +0000239 });
240}
241
242uint32_t CodeSection::numRelocations() const {
243 uint32_t Count = 0;
Sam Clegg8d146bb2018-01-09 23:56:44 +0000244 for (const InputFunction *Func : Functions)
245 Count += Func->OutRelocations.size();
Sam Cleggc94d3932017-11-17 18:14:09 +0000246 return Count;
247}
248
249void CodeSection::writeRelocations(raw_ostream &OS) const {
Sam Clegg8d146bb2018-01-09 23:56:44 +0000250 for (const InputFunction *Func : Functions)
251 for (const OutputRelocation &Reloc : Func->OutRelocations)
Sam Cleggc94d3932017-11-17 18:14:09 +0000252 writeReloc(OS, Reloc);
253}
254
Sam Clegg0fb6faa2017-12-08 01:09:21 +0000255DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
Sam Cleggc94d3932017-11-17 18:14:09 +0000256 : OutputSection(WASM_SEC_DATA), Segments(Segments) {
257 raw_string_ostream OS(DataSectionHeader);
258
259 writeUleb128(OS, Segments.size(), "data segment count");
260 OS.flush();
261 BodySize = DataSectionHeader.size();
262
263 for (OutputSegment *Segment : Segments) {
264 raw_string_ostream OS(Segment->Header);
265 writeUleb128(OS, 0, "memory index");
266 writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
267 writeSleb128(OS, Segment->StartVA, "memory offset");
268 writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
269 writeUleb128(OS, Segment->Size, "segment size");
270 OS.flush();
271 Segment->setSectionOffset(BodySize);
272 BodySize += Segment->Header.size();
273 log("Data segment: size=" + Twine(Segment->Size));
Sam Clegg5e8cba92017-12-19 20:45:15 +0000274 for (InputSegment *InputSeg : Segment->InputSegments) {
Sam Cleggc94d3932017-11-17 18:14:09 +0000275 uint32_t InputOffset = InputSeg->getInputSectionOffset();
276 uint32_t OutputOffset = Segment->getSectionOffset() +
277 Segment->Header.size() +
278 InputSeg->getOutputSegmentOffset();
Sam Clegg8d146bb2018-01-09 23:56:44 +0000279 calcRelocations(InputSeg->File, InputSeg->Relocations,
Sam Clegg5e8cba92017-12-19 20:45:15 +0000280 InputSeg->OutRelocations, OutputOffset - InputOffset);
Sam Cleggc94d3932017-11-17 18:14:09 +0000281 }
282 BodySize += Segment->Size;
283 }
284
285 createHeader(BodySize);
286}
287
288void DataSection::writeTo(uint8_t *Buf) {
Sam Cleggab2ac292017-12-20 05:14:48 +0000289 log("writing " + toString(*this) + " size=" + Twine(getSize()) +
Sam Cleggc94d3932017-11-17 18:14:09 +0000290 " body=" + Twine(BodySize));
291 Buf += Offset;
292
293 // Write section header
294 memcpy(Buf, Header.data(), Header.size());
295 Buf += Header.size();
296
297 uint8_t *ContentsStart = Buf;
298
299 // Write data section headers
300 memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
301
302 parallelForEach(Segments, [ContentsStart](const OutputSegment *Segment) {
303 // Write data segment header
304 uint8_t *SegStart = ContentsStart + Segment->getSectionOffset();
305 memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
306
307 // Write segment data payload
308 for (const InputSegment *Input : Segment->InputSegments) {
Sam Clegg8d146bb2018-01-09 23:56:44 +0000309 ArrayRef<uint8_t> Content(Input->Segment.Data.Content);
Sam Cleggc94d3932017-11-17 18:14:09 +0000310 memcpy(SegStart + Segment->Header.size() +
311 Input->getOutputSegmentOffset(),
312 Content.data(), Content.size());
Sam Clegg5e8cba92017-12-19 20:45:15 +0000313 applyRelocations(ContentsStart, Input->OutRelocations);
Sam Cleggc94d3932017-11-17 18:14:09 +0000314 }
315 });
Sam Clegg5e8cba92017-12-19 20:45:15 +0000316}
Sam Cleggc94d3932017-11-17 18:14:09 +0000317
Sam Clegg5e8cba92017-12-19 20:45:15 +0000318uint32_t DataSection::numRelocations() const {
319 uint32_t Count = 0;
320 for (const OutputSegment *Seg : Segments)
321 for (const InputSegment *InputSeg : Seg->InputSegments)
322 Count += InputSeg->OutRelocations.size();
323 return Count;
Sam Cleggc94d3932017-11-17 18:14:09 +0000324}
325
326void DataSection::writeRelocations(raw_ostream &OS) const {
Sam Clegg5e8cba92017-12-19 20:45:15 +0000327 for (const OutputSegment *Seg : Segments)
328 for (const InputSegment *InputSeg : Seg->InputSegments)
329 for (const OutputRelocation &Reloc : InputSeg->OutRelocations)
330 writeReloc(OS, Reloc);
Sam Cleggc94d3932017-11-17 18:14:09 +0000331}