1 //===- OutputSections.cpp -------------------------------------------------===//
3 // 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
7 //===----------------------------------------------------------------------===//
9 #include "OutputSections.h"
10 #include "InputChunks.h"
11 #include "InputElement.h"
12 #include "InputFiles.h"
13 #include "OutputSegment.h"
14 #include "WriterUtils.h"
15 #include "lld/Common/ErrorHandler.h"
16 #include "lld/Common/Memory.h"
17 #include "llvm/ADT/Twine.h"
18 #include "llvm/Support/LEB128.h"
19 #include "llvm/Support/Parallel.h"
21 #define DEBUG_TYPE "lld"
24 using namespace llvm::wasm
;
28 // Returns a string, e.g. "FUNCTION(.text)".
29 std::string
toString(const wasm::OutputSection
&sec
) {
30 if (!sec
.name
.empty())
31 return (sec
.getSectionName() + "(" + sec
.name
+ ")").str();
32 return std::string(sec
.getSectionName());
36 static StringRef
sectionTypeToString(uint32_t sectionType
) {
37 switch (sectionType
) {
44 case WASM_SEC_FUNCTION
:
64 case WASM_SEC_DATACOUNT
:
67 fatal("invalid section type");
71 StringRef
OutputSection::getSectionName() const {
72 return sectionTypeToString(type
);
75 void OutputSection::createHeader(size_t bodySize
) {
76 raw_string_ostream
os(header
);
77 debugWrite(os
.tell(), "section type [" + getSectionName() + "]");
78 encodeULEB128(type
, os
);
79 writeUleb128(os
, bodySize
, "section size");
81 log("createHeader: " + toString(*this) + " body=" + Twine(bodySize
) +
82 " total=" + Twine(getSize()));
85 void CodeSection::finalizeContents() {
86 raw_string_ostream
os(codeSectionHeader
);
87 writeUleb128(os
, functions
.size(), "function count");
89 bodySize
= codeSectionHeader
.size();
91 for (InputFunction
*func
: functions
) {
92 func
->outputSec
= this;
93 func
->outSecOff
= bodySize
;
94 func
->calculateSize();
95 // All functions should have a non-empty body at this point
96 assert(func
->getSize());
97 bodySize
+= func
->getSize();
100 createHeader(bodySize
);
103 void CodeSection::writeTo(uint8_t *buf
) {
104 log("writing " + toString(*this) + " offset=" + Twine(offset
) +
105 " size=" + Twine(getSize()));
106 log(" headersize=" + Twine(header
.size()));
107 log(" codeheadersize=" + Twine(codeSectionHeader
.size()));
110 // Write section header
111 memcpy(buf
, header
.data(), header
.size());
112 buf
+= header
.size();
114 // Write code section headers
115 memcpy(buf
, codeSectionHeader
.data(), codeSectionHeader
.size());
117 // Write code section bodies
118 for (const InputChunk
*chunk
: functions
)
122 uint32_t CodeSection::getNumRelocations() const {
124 for (const InputChunk
*func
: functions
)
125 count
+= func
->getNumRelocations();
129 void CodeSection::writeRelocations(raw_ostream
&os
) const {
130 for (const InputChunk
*c
: functions
)
131 c
->writeRelocations(os
);
134 void DataSection::finalizeContents() {
135 raw_string_ostream
os(dataSectionHeader
);
136 unsigned segmentCount
= std::count_if(
137 segments
.begin(), segments
.end(),
138 [](OutputSegment
*segment
) { return segment
->requiredInBinary(); });
140 unsigned activeCount
= std::count_if(
141 segments
.begin(), segments
.end(), [](OutputSegment
*segment
) {
142 return (segment
->initFlags
& WASM_DATA_SEGMENT_IS_PASSIVE
) == 0;
146 assert((config
->sharedMemory
|| !config
->isPic
|| config
->extendedConst
||
148 "output segments should have been combined by now");
150 writeUleb128(os
, segmentCount
, "data segment count");
152 bodySize
= dataSectionHeader
.size();
153 bool is64
= config
->is64
.getValueOr(false);
155 for (OutputSegment
*segment
: segments
) {
156 if (!segment
->requiredInBinary())
158 raw_string_ostream
os(segment
->header
);
159 writeUleb128(os
, segment
->initFlags
, "init flags");
160 if (segment
->initFlags
& WASM_DATA_SEGMENT_HAS_MEMINDEX
)
161 writeUleb128(os
, 0, "memory index");
162 if ((segment
->initFlags
& WASM_DATA_SEGMENT_IS_PASSIVE
) == 0) {
163 if (config
->isPic
&& config
->extendedConst
) {
164 writeU8(os
, WASM_OPCODE_GLOBAL_GET
, "global get");
165 writeUleb128(os
, WasmSym::memoryBase
->getGlobalIndex(),
166 "literal (global index)");
167 if (segment
->startVA
) {
168 writePtrConst(os
, segment
->startVA
, is64
, "offset");
169 writeU8(os
, is64
? WASM_OPCODE_I64_ADD
: WASM_OPCODE_I32_ADD
, "add");
171 writeU8(os
, WASM_OPCODE_END
, "opcode:end");
173 WasmInitExpr initExpr
;
174 initExpr
.Extended
= false;
176 assert(segment
->startVA
== 0);
177 initExpr
.Inst
.Opcode
= WASM_OPCODE_GLOBAL_GET
;
178 initExpr
.Inst
.Value
.Global
= WasmSym::memoryBase
->getGlobalIndex();
180 initExpr
= intConst(segment
->startVA
, is64
);
182 writeInitExpr(os
, initExpr
);
185 writeUleb128(os
, segment
->size
, "segment size");
188 segment
->sectionOffset
= bodySize
;
189 bodySize
+= segment
->header
.size() + segment
->size
;
190 log("Data segment: size=" + Twine(segment
->size
) + ", startVA=" +
191 Twine::utohexstr(segment
->startVA
) + ", name=" + segment
->name
);
193 for (InputChunk
*inputSeg
: segment
->inputSegments
) {
194 inputSeg
->outputSec
= this;
195 inputSeg
->outSecOff
= segment
->sectionOffset
+ segment
->header
.size() +
196 inputSeg
->outputSegmentOffset
;
200 createHeader(bodySize
);
203 void DataSection::writeTo(uint8_t *buf
) {
204 log("writing " + toString(*this) + " offset=" + Twine(offset
) +
205 " size=" + Twine(getSize()) + " body=" + Twine(bodySize
));
208 // Write section header
209 memcpy(buf
, header
.data(), header
.size());
210 buf
+= header
.size();
212 // Write data section headers
213 memcpy(buf
, dataSectionHeader
.data(), dataSectionHeader
.size());
215 for (const OutputSegment
*segment
: segments
) {
216 if (!segment
->requiredInBinary())
218 // Write data segment header
219 uint8_t *segStart
= buf
+ segment
->sectionOffset
;
220 memcpy(segStart
, segment
->header
.data(), segment
->header
.size());
222 // Write segment data payload
223 for (const InputChunk
*chunk
: segment
->inputSegments
)
228 uint32_t DataSection::getNumRelocations() const {
230 for (const OutputSegment
*seg
: segments
)
231 for (const InputChunk
*inputSeg
: seg
->inputSegments
)
232 count
+= inputSeg
->getNumRelocations();
236 void DataSection::writeRelocations(raw_ostream
&os
) const {
237 for (const OutputSegment
*seg
: segments
)
238 for (const InputChunk
*c
: seg
->inputSegments
)
239 c
->writeRelocations(os
);
242 bool DataSection::isNeeded() const {
243 for (const OutputSegment
*seg
: segments
)
244 if (seg
->requiredInBinary())
249 // Lots of duplication here with OutputSegment::finalizeInputSegments
250 void CustomSection::finalizeInputSections() {
251 SyntheticMergedChunk
*mergedSection
= nullptr;
252 std::vector
<InputChunk
*> newSections
;
254 for (InputChunk
*s
: inputSections
) {
256 MergeInputChunk
*ms
= dyn_cast
<MergeInputChunk
>(s
);
258 newSections
.push_back(s
);
262 if (!mergedSection
) {
264 make
<SyntheticMergedChunk
>(name
, 0, WASM_SEG_FLAG_STRINGS
);
265 newSections
.push_back(mergedSection
);
266 mergedSection
->outputSec
= this;
268 mergedSection
->addMergeChunk(ms
);
274 mergedSection
->finalizeContents();
275 inputSections
= newSections
;
278 void CustomSection::finalizeContents() {
279 finalizeInputSections();
281 raw_string_ostream
os(nameData
);
282 encodeULEB128(name
.size(), os
);
286 for (InputChunk
*section
: inputSections
) {
287 assert(!section
->discarded
);
288 section
->outSecOff
= payloadSize
;
289 payloadSize
+= section
->getSize();
292 createHeader(payloadSize
+ nameData
.size());
295 void CustomSection::writeTo(uint8_t *buf
) {
296 log("writing " + toString(*this) + " offset=" + Twine(offset
) +
297 " size=" + Twine(getSize()) + " chunks=" + Twine(inputSections
.size()));
302 // Write section header
303 memcpy(buf
, header
.data(), header
.size());
304 buf
+= header
.size();
305 memcpy(buf
, nameData
.data(), nameData
.size());
306 buf
+= nameData
.size();
308 // Write custom sections payload
309 for (const InputChunk
*section
: inputSections
)
310 section
->writeTo(buf
);
313 uint32_t CustomSection::getNumRelocations() const {
315 for (const InputChunk
*inputSect
: inputSections
)
316 count
+= inputSect
->getNumRelocations();
320 void CustomSection::writeRelocations(raw_ostream
&os
) const {
321 for (const InputChunk
*s
: inputSections
)
322 s
->writeRelocations(os
);