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 StringRef
OutputSection::getSectionName() const {
37 return sectionTypeToString(type
);
40 void OutputSection::createHeader(size_t bodySize
) {
41 raw_string_ostream
os(header
);
42 debugWrite(os
.tell(), "section type [" + getSectionName() + "]");
43 encodeULEB128(type
, os
);
44 writeUleb128(os
, bodySize
, "section size");
45 log("createHeader: " + toString(*this) + " body=" + Twine(bodySize
) +
46 " total=" + Twine(getSize()));
49 void CodeSection::finalizeContents() {
50 raw_string_ostream
os(codeSectionHeader
);
51 writeUleb128(os
, functions
.size(), "function count");
52 bodySize
= codeSectionHeader
.size();
54 for (InputFunction
*func
: functions
) {
55 func
->outputSec
= this;
56 func
->outSecOff
= bodySize
;
57 func
->calculateSize();
58 // All functions should have a non-empty body at this point
59 assert(func
->getSize());
60 bodySize
+= func
->getSize();
63 createHeader(bodySize
);
66 void CodeSection::writeTo(uint8_t *buf
) {
67 log("writing " + toString(*this) + " offset=" + Twine(offset
) +
68 " size=" + Twine(getSize()));
69 log(" headersize=" + Twine(header
.size()));
70 log(" codeheadersize=" + Twine(codeSectionHeader
.size()));
73 // Write section header
74 memcpy(buf
, header
.data(), header
.size());
77 // Write code section headers
78 memcpy(buf
, codeSectionHeader
.data(), codeSectionHeader
.size());
80 // Write code section bodies
81 for (const InputChunk
*chunk
: functions
)
85 uint32_t CodeSection::getNumRelocations() const {
87 for (const InputChunk
*func
: functions
)
88 count
+= func
->getNumRelocations();
92 void CodeSection::writeRelocations(raw_ostream
&os
) const {
93 for (const InputChunk
*c
: functions
)
94 c
->writeRelocations(os
);
97 void DataSection::finalizeContents() {
98 raw_string_ostream
os(dataSectionHeader
);
99 unsigned segmentCount
= llvm::count_if(segments
, [](OutputSegment
*segment
) {
100 return segment
->requiredInBinary();
103 unsigned activeCount
= llvm::count_if(segments
, [](OutputSegment
*segment
) {
104 return (segment
->initFlags
& WASM_DATA_SEGMENT_IS_PASSIVE
) == 0;
108 assert((config
->sharedMemory
|| !ctx
.isPic
|| config
->extendedConst
||
110 "output segments should have been combined by now");
112 writeUleb128(os
, segmentCount
, "data segment count");
113 bodySize
= dataSectionHeader
.size();
114 bool is64
= config
->is64
.value_or(false);
116 for (OutputSegment
*segment
: segments
) {
117 if (!segment
->requiredInBinary())
119 raw_string_ostream
os(segment
->header
);
120 writeUleb128(os
, segment
->initFlags
, "init flags");
121 if (segment
->initFlags
& WASM_DATA_SEGMENT_HAS_MEMINDEX
)
122 writeUleb128(os
, 0, "memory index");
123 if ((segment
->initFlags
& WASM_DATA_SEGMENT_IS_PASSIVE
) == 0) {
124 if (ctx
.isPic
&& config
->extendedConst
) {
125 writeU8(os
, WASM_OPCODE_GLOBAL_GET
, "global get");
126 writeUleb128(os
, WasmSym::memoryBase
->getGlobalIndex(),
127 "literal (global index)");
128 if (segment
->startVA
) {
129 writePtrConst(os
, segment
->startVA
, is64
, "offset");
130 writeU8(os
, is64
? WASM_OPCODE_I64_ADD
: WASM_OPCODE_I32_ADD
, "add");
132 writeU8(os
, WASM_OPCODE_END
, "opcode:end");
134 WasmInitExpr initExpr
;
135 initExpr
.Extended
= false;
137 assert(segment
->startVA
== 0);
138 initExpr
.Inst
.Opcode
= WASM_OPCODE_GLOBAL_GET
;
139 initExpr
.Inst
.Value
.Global
= WasmSym::memoryBase
->getGlobalIndex();
141 initExpr
= intConst(segment
->startVA
, is64
);
143 writeInitExpr(os
, initExpr
);
146 writeUleb128(os
, segment
->size
, "segment size");
148 segment
->sectionOffset
= bodySize
;
149 bodySize
+= segment
->header
.size() + segment
->size
;
150 log("Data segment: size=" + Twine(segment
->size
) + ", startVA=" +
151 Twine::utohexstr(segment
->startVA
) + ", name=" + segment
->name
);
153 for (InputChunk
*inputSeg
: segment
->inputSegments
) {
154 inputSeg
->outputSec
= this;
155 inputSeg
->outSecOff
= segment
->sectionOffset
+ segment
->header
.size() +
156 inputSeg
->outputSegmentOffset
;
160 createHeader(bodySize
);
163 void DataSection::writeTo(uint8_t *buf
) {
164 log("writing " + toString(*this) + " offset=" + Twine(offset
) +
165 " size=" + Twine(getSize()) + " body=" + Twine(bodySize
));
168 // Write section header
169 memcpy(buf
, header
.data(), header
.size());
170 buf
+= header
.size();
172 // Write data section headers
173 memcpy(buf
, dataSectionHeader
.data(), dataSectionHeader
.size());
175 for (const OutputSegment
*segment
: segments
) {
176 if (!segment
->requiredInBinary())
178 // Write data segment header
179 uint8_t *segStart
= buf
+ segment
->sectionOffset
;
180 memcpy(segStart
, segment
->header
.data(), segment
->header
.size());
182 // Write segment data payload
183 for (const InputChunk
*chunk
: segment
->inputSegments
)
188 uint32_t DataSection::getNumRelocations() const {
190 for (const OutputSegment
*seg
: segments
)
191 for (const InputChunk
*inputSeg
: seg
->inputSegments
)
192 count
+= inputSeg
->getNumRelocations();
196 void DataSection::writeRelocations(raw_ostream
&os
) const {
197 for (const OutputSegment
*seg
: segments
)
198 for (const InputChunk
*c
: seg
->inputSegments
)
199 c
->writeRelocations(os
);
202 bool DataSection::isNeeded() const {
203 for (const OutputSegment
*seg
: segments
)
204 if (seg
->requiredInBinary())
209 // Lots of duplication here with OutputSegment::finalizeInputSegments
210 void CustomSection::finalizeInputSections() {
211 SyntheticMergedChunk
*mergedSection
= nullptr;
212 std::vector
<InputChunk
*> newSections
;
214 for (InputChunk
*s
: inputSections
) {
216 MergeInputChunk
*ms
= dyn_cast
<MergeInputChunk
>(s
);
218 newSections
.push_back(s
);
222 if (!mergedSection
) {
224 make
<SyntheticMergedChunk
>(name
, 0, WASM_SEG_FLAG_STRINGS
);
225 newSections
.push_back(mergedSection
);
226 mergedSection
->outputSec
= this;
228 mergedSection
->addMergeChunk(ms
);
234 mergedSection
->finalizeContents();
235 inputSections
= newSections
;
238 void CustomSection::finalizeContents() {
239 finalizeInputSections();
241 raw_string_ostream
os(nameData
);
242 encodeULEB128(name
.size(), os
);
245 for (InputChunk
*section
: inputSections
) {
246 assert(!section
->discarded
);
247 payloadSize
= alignTo(payloadSize
, section
->alignment
);
248 section
->outSecOff
= payloadSize
;
249 payloadSize
+= section
->getSize();
252 createHeader(payloadSize
+ nameData
.size());
255 void CustomSection::writeTo(uint8_t *buf
) {
256 log("writing " + toString(*this) + " offset=" + Twine(offset
) +
257 " size=" + Twine(getSize()) + " chunks=" + Twine(inputSections
.size()));
262 // Write section header
263 memcpy(buf
, header
.data(), header
.size());
264 buf
+= header
.size();
265 memcpy(buf
, nameData
.data(), nameData
.size());
266 buf
+= nameData
.size();
268 // Write custom sections payload
269 for (const InputChunk
*section
: inputSections
)
270 section
->writeTo(buf
);
273 uint32_t CustomSection::getNumRelocations() const {
275 for (const InputChunk
*inputSect
: inputSections
)
276 count
+= inputSect
->getNumRelocations();
280 void CustomSection::writeRelocations(raw_ostream
&os
) const {
281 for (const InputChunk
*s
: inputSections
)
282 s
->writeRelocations(os
);