blob: 473b9dc79d5a93231af502ae082c39ca9f9b9930 [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"
Sam Clegg5fa274b2018-01-10 01:13:34 +000013#include "InputChunks.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000014#include "InputFiles.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 Clegg5fa274b2018-01-10 01:13:34 +0000205 for (InputChunk *Func : Functions) {
Sam Clegg8d146bb2018-01-09 23:56:44 +0000206 Func->OutputOffset = BodySize;
207 calcRelocations(Func->File, Func->Relocations, Func->OutRelocations,
Sam Clegg5fa274b2018-01-10 01:13:34 +0000208 Func->OutputOffset - Func->getInputSectionOffset());
209 BodySize += Func->getSize();
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 Clegg5fa274b2018-01-10 01:13:34 +0000233 parallelForEach(Functions, [ContentsStart](InputChunk *Func) {
234 memcpy(ContentsStart + Func->OutputOffset, Func->getData(),
235 Func->getSize());
Sam Clegg8d146bb2018-01-09 23:56:44 +0000236 applyRelocations(ContentsStart, Func->OutRelocations);
Sam Cleggc94d3932017-11-17 18:14:09 +0000237 });
238}
239
240uint32_t CodeSection::numRelocations() const {
241 uint32_t Count = 0;
Sam Clegg5fa274b2018-01-10 01:13:34 +0000242 for (const InputChunk *Func : Functions)
Sam Clegg8d146bb2018-01-09 23:56:44 +0000243 Count += Func->OutRelocations.size();
Sam Cleggc94d3932017-11-17 18:14:09 +0000244 return Count;
245}
246
247void CodeSection::writeRelocations(raw_ostream &OS) const {
Sam Clegg5fa274b2018-01-10 01:13:34 +0000248 for (const InputChunk *Func : Functions)
Sam Clegg8d146bb2018-01-09 23:56:44 +0000249 for (const OutputRelocation &Reloc : Func->OutRelocations)
Sam Cleggc94d3932017-11-17 18:14:09 +0000250 writeReloc(OS, Reloc);
251}
252
Sam Clegg0fb6faa2017-12-08 01:09:21 +0000253DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
Sam Cleggc94d3932017-11-17 18:14:09 +0000254 : OutputSection(WASM_SEC_DATA), Segments(Segments) {
255 raw_string_ostream OS(DataSectionHeader);
256
257 writeUleb128(OS, Segments.size(), "data segment count");
258 OS.flush();
259 BodySize = DataSectionHeader.size();
260
261 for (OutputSegment *Segment : Segments) {
262 raw_string_ostream OS(Segment->Header);
263 writeUleb128(OS, 0, "memory index");
264 writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
265 writeSleb128(OS, Segment->StartVA, "memory offset");
266 writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
267 writeUleb128(OS, Segment->Size, "segment size");
268 OS.flush();
269 Segment->setSectionOffset(BodySize);
270 BodySize += Segment->Header.size();
271 log("Data segment: size=" + Twine(Segment->Size));
Sam Clegg5fa274b2018-01-10 01:13:34 +0000272 for (InputChunk *InputSeg : Segment->InputSegments) {
Sam Cleggc94d3932017-11-17 18:14:09 +0000273 uint32_t OutputOffset = Segment->getSectionOffset() +
Sam Clegg5fa274b2018-01-10 01:13:34 +0000274 Segment->Header.size() + InputSeg->OutputOffset;
Sam Clegg8d146bb2018-01-09 23:56:44 +0000275 calcRelocations(InputSeg->File, InputSeg->Relocations,
Sam Clegg5fa274b2018-01-10 01:13:34 +0000276 InputSeg->OutRelocations,
277 OutputOffset - InputSeg->getInputSectionOffset());
Sam Cleggc94d3932017-11-17 18:14:09 +0000278 }
279 BodySize += Segment->Size;
280 }
281
282 createHeader(BodySize);
283}
284
285void DataSection::writeTo(uint8_t *Buf) {
Sam Cleggab2ac292017-12-20 05:14:48 +0000286 log("writing " + toString(*this) + " size=" + Twine(getSize()) +
Sam Cleggc94d3932017-11-17 18:14:09 +0000287 " body=" + Twine(BodySize));
288 Buf += Offset;
289
290 // Write section header
291 memcpy(Buf, Header.data(), Header.size());
292 Buf += Header.size();
293
294 uint8_t *ContentsStart = Buf;
295
296 // Write data section headers
297 memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
298
299 parallelForEach(Segments, [ContentsStart](const OutputSegment *Segment) {
300 // Write data segment header
301 uint8_t *SegStart = ContentsStart + Segment->getSectionOffset();
302 memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
303
304 // Write segment data payload
Sam Clegg5fa274b2018-01-10 01:13:34 +0000305 for (const InputChunk *Input : Segment->InputSegments) {
306 memcpy(SegStart + Segment->Header.size() + Input->OutputOffset,
307 Input->getData(), Input->getSize());
Sam Clegg5e8cba92017-12-19 20:45:15 +0000308 applyRelocations(ContentsStart, Input->OutRelocations);
Sam Cleggc94d3932017-11-17 18:14:09 +0000309 }
310 });
Sam Clegg5e8cba92017-12-19 20:45:15 +0000311}
Sam Cleggc94d3932017-11-17 18:14:09 +0000312
Sam Clegg5e8cba92017-12-19 20:45:15 +0000313uint32_t DataSection::numRelocations() const {
314 uint32_t Count = 0;
315 for (const OutputSegment *Seg : Segments)
Sam Clegg5fa274b2018-01-10 01:13:34 +0000316 for (const InputChunk *InputSeg : Seg->InputSegments)
Sam Clegg5e8cba92017-12-19 20:45:15 +0000317 Count += InputSeg->OutRelocations.size();
318 return Count;
Sam Cleggc94d3932017-11-17 18:14:09 +0000319}
320
321void DataSection::writeRelocations(raw_ostream &OS) const {
Sam Clegg5e8cba92017-12-19 20:45:15 +0000322 for (const OutputSegment *Seg : Segments)
Sam Clegg5fa274b2018-01-10 01:13:34 +0000323 for (const InputChunk *InputSeg : Seg->InputSegments)
Sam Clegg5e8cba92017-12-19 20:45:15 +0000324 for (const OutputRelocation &Reloc : InputSeg->OutRelocations)
325 writeReloc(OS, Reloc);
Sam Cleggc94d3932017-11-17 18:14:09 +0000326}