blob: 519305f64822d246582563e7747b873afa92e0c0 [file] [log] [blame]
Sam Cleggc94d3932017-11-17 18:14:09 +00001//===- OutputSections.cpp -------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Sam Cleggc94d3932017-11-17 18:14:09 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "OutputSections.h"
Sam Clegg5fa274b2018-01-10 01:13:34 +000010#include "InputChunks.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000011#include "InputFiles.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000012#include "OutputSegment.h"
Rui Ueyama4a1b2bb2018-02-28 00:52:42 +000013#include "WriterUtils.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000014#include "lld/Common/ErrorHandler.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000015#include "lld/Common/Threads.h"
16#include "llvm/ADT/Twine.h"
Rui Ueyama11842532018-02-16 20:38:00 +000017#include "llvm/Support/LEB128.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000018
19#define DEBUG_TYPE "lld"
20
21using namespace llvm;
22using namespace llvm::wasm;
Sam Cleggc94d3932017-11-17 18:14:09 +000023
Fangrui Song33c59ab2019-10-10 05:25:39 +000024namespace lld {
25
26// Returns a string, e.g. "FUNCTION(.text)".
27std::string toString(const wasm::OutputSection &sec) {
28 if (!sec.name.empty())
29 return (sec.getSectionName() + "(" + sec.name + ")").str();
Benjamin Krameradcd0262020-01-28 20:23:46 +010030 return std::string(sec.getSectionName());
Fangrui Song33c59ab2019-10-10 05:25:39 +000031}
32
33namespace wasm {
Rui Ueyama136d27a2019-07-11 05:40:30 +000034static StringRef sectionTypeToString(uint32_t sectionType) {
35 switch (sectionType) {
Sam Cleggc94d3932017-11-17 18:14:09 +000036 case WASM_SEC_CUSTOM:
37 return "CUSTOM";
38 case WASM_SEC_TYPE:
39 return "TYPE";
40 case WASM_SEC_IMPORT:
41 return "IMPORT";
42 case WASM_SEC_FUNCTION:
43 return "FUNCTION";
44 case WASM_SEC_TABLE:
45 return "TABLE";
46 case WASM_SEC_MEMORY:
47 return "MEMORY";
48 case WASM_SEC_GLOBAL:
49 return "GLOBAL";
Heejin Ahne915a712018-12-08 06:17:43 +000050 case WASM_SEC_EVENT:
51 return "EVENT";
Sam Cleggc94d3932017-11-17 18:14:09 +000052 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";
Thomas Lively84771e22019-04-19 23:40:36 +000062 case WASM_SEC_DATACOUNT:
63 return "DATACOUNT";
Sam Cleggc94d3932017-11-17 18:14:09 +000064 default:
65 fatal("invalid section type");
66 }
67}
68
Rui Ueyama22c8f332018-02-28 17:33:04 +000069StringRef OutputSection::getSectionName() const {
Rui Ueyama136d27a2019-07-11 05:40:30 +000070 return sectionTypeToString(type);
Sam Clegg0d0dd392017-12-19 17:09:45 +000071}
72
Rui Ueyama136d27a2019-07-11 05:40:30 +000073void OutputSection::createHeader(size_t bodySize) {
74 raw_string_ostream os(header);
75 debugWrite(os.tell(), "section type [" + getSectionName() + "]");
76 encodeULEB128(type, os);
77 writeUleb128(os, bodySize, "section size");
78 os.flush();
79 log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) +
Sam Cleggc94d3932017-11-17 18:14:09 +000080 " total=" + Twine(getSize()));
81}
82
Sam Cleggd029bf02019-05-16 21:36:06 +000083void CodeSection::finalizeContents() {
Rui Ueyama136d27a2019-07-11 05:40:30 +000084 raw_string_ostream os(codeSectionHeader);
85 writeUleb128(os, functions.size(), "function count");
86 os.flush();
87 bodySize = codeSectionHeader.size();
Sam Cleggc94d3932017-11-17 18:14:09 +000088
Rui Ueyama136d27a2019-07-11 05:40:30 +000089 for (InputFunction *func : functions) {
90 func->outputOffset = bodySize;
91 func->calculateSize();
92 bodySize += func->getSize();
Sam Cleggc94d3932017-11-17 18:14:09 +000093 }
94
Rui Ueyama136d27a2019-07-11 05:40:30 +000095 createHeader(bodySize);
Sam Cleggc94d3932017-11-17 18:14:09 +000096}
97
Rui Ueyama136d27a2019-07-11 05:40:30 +000098void CodeSection::writeTo(uint8_t *buf) {
Sam Cleggab2ac292017-12-20 05:14:48 +000099 log("writing " + toString(*this));
Sam Cleggc94d3932017-11-17 18:14:09 +0000100 log(" size=" + Twine(getSize()));
Rui Ueyama136d27a2019-07-11 05:40:30 +0000101 log(" headersize=" + Twine(header.size()));
102 log(" codeheadersize=" + Twine(codeSectionHeader.size()));
103 buf += offset;
Sam Cleggc94d3932017-11-17 18:14:09 +0000104
105 // Write section header
Rui Ueyama136d27a2019-07-11 05:40:30 +0000106 memcpy(buf, header.data(), header.size());
107 buf += header.size();
Sam Cleggc94d3932017-11-17 18:14:09 +0000108
Sam Cleggc94d3932017-11-17 18:14:09 +0000109 // Write code section headers
Rui Ueyama136d27a2019-07-11 05:40:30 +0000110 memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size());
Sam Cleggc94d3932017-11-17 18:14:09 +0000111
112 // Write code section bodies
Rui Ueyama136d27a2019-07-11 05:40:30 +0000113 for (const InputChunk *chunk : functions)
114 chunk->writeTo(buf);
Sam Cleggc94d3932017-11-17 18:14:09 +0000115}
116
Rui Ueyama7e296ad2019-07-10 09:10:01 +0000117uint32_t CodeSection::getNumRelocations() const {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000118 uint32_t count = 0;
119 for (const InputChunk *func : functions)
120 count += func->getNumRelocations();
121 return count;
Sam Cleggc94d3932017-11-17 18:14:09 +0000122}
123
Rui Ueyama136d27a2019-07-11 05:40:30 +0000124void CodeSection::writeRelocations(raw_ostream &os) const {
125 for (const InputChunk *c : functions)
126 c->writeRelocations(os);
Sam Cleggc94d3932017-11-17 18:14:09 +0000127}
128
Sam Cleggd029bf02019-05-16 21:36:06 +0000129void DataSection::finalizeContents() {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000130 raw_string_ostream os(dataSectionHeader);
Thomas Lively190dacc2019-10-15 19:05:11 +0000131 unsigned segmentCount =
132 std::count_if(segments.begin(), segments.end(),
133 [](OutputSegment *segment) { return !segment->isBss; });
Sam Cleggc94d3932017-11-17 18:14:09 +0000134
Thomas Lively190dacc2019-10-15 19:05:11 +0000135 writeUleb128(os, segmentCount, "data segment count");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000136 os.flush();
137 bodySize = dataSectionHeader.size();
Sam Cleggc94d3932017-11-17 18:14:09 +0000138
Rui Ueyama136d27a2019-07-11 05:40:30 +0000139 assert((!config->isPic || segments.size() <= 1) &&
Bill Wendling858e3512019-07-08 22:05:02 +0000140 "Currenly only a single data segment is supported in PIC mode");
Thomas Lively6004d9a2019-07-03 22:04:54 +0000141
Rui Ueyama136d27a2019-07-11 05:40:30 +0000142 for (OutputSegment *segment : segments) {
Thomas Lively190dacc2019-10-15 19:05:11 +0000143 if (segment->isBss)
144 continue;
Rui Ueyama136d27a2019-07-11 05:40:30 +0000145 raw_string_ostream os(segment->header);
146 writeUleb128(os, segment->initFlags, "init flags");
147 if (segment->initFlags & WASM_SEGMENT_HAS_MEMINDEX)
148 writeUleb128(os, 0, "memory index");
149 if ((segment->initFlags & WASM_SEGMENT_IS_PASSIVE) == 0) {
150 WasmInitExpr initExpr;
151 if (config->isPic) {
152 initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
153 initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex();
Thomas Lively6004d9a2019-07-03 22:04:54 +0000154 } else {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000155 initExpr.Opcode = WASM_OPCODE_I32_CONST;
156 initExpr.Value.Int32 = segment->startVA;
Thomas Lively6004d9a2019-07-03 22:04:54 +0000157 }
Rui Ueyama136d27a2019-07-11 05:40:30 +0000158 writeInitExpr(os, initExpr);
Sam Cleggbfb75342018-11-15 00:37:21 +0000159 }
Rui Ueyama136d27a2019-07-11 05:40:30 +0000160 writeUleb128(os, segment->size, "segment size");
161 os.flush();
Rui Ueyamaac95bb12018-04-05 19:37:31 +0000162
Rui Ueyama136d27a2019-07-11 05:40:30 +0000163 segment->sectionOffset = bodySize;
164 bodySize += segment->header.size() + segment->size;
165 log("Data segment: size=" + Twine(segment->size) + ", startVA=" +
166 Twine::utohexstr(segment->startVA) + ", name=" + segment->name);
Rui Ueyamaac95bb12018-04-05 19:37:31 +0000167
Rui Ueyama136d27a2019-07-11 05:40:30 +0000168 for (InputSegment *inputSeg : segment->inputSegments)
169 inputSeg->outputOffset = segment->sectionOffset + segment->header.size() +
170 inputSeg->outputSegmentOffset;
Sam Cleggc94d3932017-11-17 18:14:09 +0000171 }
172
Rui Ueyama136d27a2019-07-11 05:40:30 +0000173 createHeader(bodySize);
Sam Cleggc94d3932017-11-17 18:14:09 +0000174}
175
Rui Ueyama136d27a2019-07-11 05:40:30 +0000176void DataSection::writeTo(uint8_t *buf) {
Sam Cleggab2ac292017-12-20 05:14:48 +0000177 log("writing " + toString(*this) + " size=" + Twine(getSize()) +
Rui Ueyama136d27a2019-07-11 05:40:30 +0000178 " body=" + Twine(bodySize));
179 buf += offset;
Sam Cleggc94d3932017-11-17 18:14:09 +0000180
181 // Write section header
Rui Ueyama136d27a2019-07-11 05:40:30 +0000182 memcpy(buf, header.data(), header.size());
183 buf += header.size();
Sam Cleggc94d3932017-11-17 18:14:09 +0000184
Sam Cleggc94d3932017-11-17 18:14:09 +0000185 // Write data section headers
Rui Ueyama136d27a2019-07-11 05:40:30 +0000186 memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size());
Sam Cleggc94d3932017-11-17 18:14:09 +0000187
Rui Ueyama136d27a2019-07-11 05:40:30 +0000188 for (const OutputSegment *segment : segments) {
Thomas Lively190dacc2019-10-15 19:05:11 +0000189 if (segment->isBss)
190 continue;
Sam Cleggc94d3932017-11-17 18:14:09 +0000191 // Write data segment header
Rui Ueyama136d27a2019-07-11 05:40:30 +0000192 uint8_t *segStart = buf + segment->sectionOffset;
193 memcpy(segStart, segment->header.data(), segment->header.size());
Sam Cleggc94d3932017-11-17 18:14:09 +0000194
195 // Write segment data payload
Rui Ueyama136d27a2019-07-11 05:40:30 +0000196 for (const InputChunk *chunk : segment->inputSegments)
197 chunk->writeTo(buf);
Rui Ueyama5081e412019-04-17 02:12:47 +0000198 }
Sam Clegg5e8cba92017-12-19 20:45:15 +0000199}
Sam Cleggc94d3932017-11-17 18:14:09 +0000200
Rui Ueyama7e296ad2019-07-10 09:10:01 +0000201uint32_t DataSection::getNumRelocations() const {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000202 uint32_t count = 0;
203 for (const OutputSegment *seg : segments)
204 for (const InputChunk *inputSeg : seg->inputSegments)
205 count += inputSeg->getNumRelocations();
206 return count;
Sam Cleggc94d3932017-11-17 18:14:09 +0000207}
208
Rui Ueyama136d27a2019-07-11 05:40:30 +0000209void DataSection::writeRelocations(raw_ostream &os) const {
210 for (const OutputSegment *seg : segments)
211 for (const InputChunk *c : seg->inputSegments)
212 c->writeRelocations(os);
Sam Cleggc94d3932017-11-17 18:14:09 +0000213}
Sam Clegg80ba4382018-04-10 16:12:49 +0000214
Thomas Lively190dacc2019-10-15 19:05:11 +0000215bool DataSection::isNeeded() const {
216 for (const OutputSegment *seg : segments)
217 if (!seg->isBss)
218 return true;
219 return false;
220}
221
Sam Cleggd029bf02019-05-16 21:36:06 +0000222void CustomSection::finalizeContents() {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000223 raw_string_ostream os(nameData);
224 encodeULEB128(name.size(), os);
225 os << name;
226 os.flush();
Sam Clegg80ba4382018-04-10 16:12:49 +0000227
Rui Ueyama136d27a2019-07-11 05:40:30 +0000228 for (InputSection *section : inputSections) {
229 section->outputOffset = payloadSize;
230 section->outputSec = this;
231 payloadSize += section->getSize();
Sam Clegg80ba4382018-04-10 16:12:49 +0000232 }
233
Rui Ueyama136d27a2019-07-11 05:40:30 +0000234 createHeader(payloadSize + nameData.size());
Sam Clegg80ba4382018-04-10 16:12:49 +0000235}
236
Rui Ueyama136d27a2019-07-11 05:40:30 +0000237void CustomSection::writeTo(uint8_t *buf) {
Sam Clegg80ba4382018-04-10 16:12:49 +0000238 log("writing " + toString(*this) + " size=" + Twine(getSize()) +
Rui Ueyama136d27a2019-07-11 05:40:30 +0000239 " chunks=" + Twine(inputSections.size()));
Sam Clegg80ba4382018-04-10 16:12:49 +0000240
Rui Ueyama136d27a2019-07-11 05:40:30 +0000241 assert(offset);
242 buf += offset;
Sam Clegg80ba4382018-04-10 16:12:49 +0000243
244 // Write section header
Rui Ueyama136d27a2019-07-11 05:40:30 +0000245 memcpy(buf, header.data(), header.size());
246 buf += header.size();
247 memcpy(buf, nameData.data(), nameData.size());
248 buf += nameData.size();
Sam Clegg80ba4382018-04-10 16:12:49 +0000249
250 // Write custom sections payload
Rui Ueyama136d27a2019-07-11 05:40:30 +0000251 for (const InputSection *section : inputSections)
252 section->writeTo(buf);
Sam Clegg80ba4382018-04-10 16:12:49 +0000253}
Sam Cleggd177ab22018-05-04 23:14:42 +0000254
Rui Ueyama7e296ad2019-07-10 09:10:01 +0000255uint32_t CustomSection::getNumRelocations() const {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000256 uint32_t count = 0;
257 for (const InputSection *inputSect : inputSections)
258 count += inputSect->getNumRelocations();
259 return count;
Sam Cleggd177ab22018-05-04 23:14:42 +0000260}
261
Rui Ueyama136d27a2019-07-11 05:40:30 +0000262void CustomSection::writeRelocations(raw_ostream &os) const {
263 for (const InputSection *s : inputSections)
264 s->writeRelocations(os);
Sam Cleggd177ab22018-05-04 23:14:42 +0000265}
Fangrui Song33c59ab2019-10-10 05:25:39 +0000266
267} // namespace wasm
268} // namespace lld