llvm-project
290 строк · 8.5 Кб
1//===- OutputSections.cpp -------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
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"
20
21#define DEBUG_TYPE "lld"
22
23using namespace llvm;
24using namespace llvm::wasm;
25
26namespace lld {
27
28// Returns a string, e.g. "FUNCTION(.text)".
29std::string toString(const wasm::OutputSection &sec) {
30if (!sec.name.empty())
31return (sec.getSectionName() + "(" + sec.name + ")").str();
32return std::string(sec.getSectionName());
33}
34
35namespace wasm {
36StringRef OutputSection::getSectionName() const {
37return sectionTypeToString(type);
38}
39
40void OutputSection::createHeader(size_t bodySize) {
41raw_string_ostream os(header);
42debugWrite(os.tell(), "section type [" + getSectionName() + "]");
43encodeULEB128(type, os);
44writeUleb128(os, bodySize, "section size");
45os.flush();
46log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) +
47" total=" + Twine(getSize()));
48}
49
50void CodeSection::finalizeContents() {
51raw_string_ostream os(codeSectionHeader);
52writeUleb128(os, functions.size(), "function count");
53os.flush();
54bodySize = codeSectionHeader.size();
55
56for (InputFunction *func : functions) {
57func->outputSec = this;
58func->outSecOff = bodySize;
59func->calculateSize();
60// All functions should have a non-empty body at this point
61assert(func->getSize());
62bodySize += func->getSize();
63}
64
65createHeader(bodySize);
66}
67
68void CodeSection::writeTo(uint8_t *buf) {
69log("writing " + toString(*this) + " offset=" + Twine(offset) +
70" size=" + Twine(getSize()));
71log(" headersize=" + Twine(header.size()));
72log(" codeheadersize=" + Twine(codeSectionHeader.size()));
73buf += offset;
74
75// Write section header
76memcpy(buf, header.data(), header.size());
77buf += header.size();
78
79// Write code section headers
80memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size());
81
82// Write code section bodies
83for (const InputChunk *chunk : functions)
84chunk->writeTo(buf);
85}
86
87uint32_t CodeSection::getNumRelocations() const {
88uint32_t count = 0;
89for (const InputChunk *func : functions)
90count += func->getNumRelocations();
91return count;
92}
93
94void CodeSection::writeRelocations(raw_ostream &os) const {
95for (const InputChunk *c : functions)
96c->writeRelocations(os);
97}
98
99void DataSection::finalizeContents() {
100raw_string_ostream os(dataSectionHeader);
101unsigned segmentCount = llvm::count_if(segments, [](OutputSegment *segment) {
102return segment->requiredInBinary();
103});
104#ifndef NDEBUG
105unsigned activeCount = llvm::count_if(segments, [](OutputSegment *segment) {
106return (segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0;
107});
108#endif
109
110assert((config->sharedMemory || !ctx.isPic || config->extendedConst ||
111activeCount <= 1) &&
112"output segments should have been combined by now");
113
114writeUleb128(os, segmentCount, "data segment count");
115os.flush();
116bodySize = dataSectionHeader.size();
117bool is64 = config->is64.value_or(false);
118
119for (OutputSegment *segment : segments) {
120if (!segment->requiredInBinary())
121continue;
122raw_string_ostream os(segment->header);
123writeUleb128(os, segment->initFlags, "init flags");
124if (segment->initFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX)
125writeUleb128(os, 0, "memory index");
126if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
127if (ctx.isPic && config->extendedConst) {
128writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get");
129writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
130"literal (global index)");
131if (segment->startVA) {
132writePtrConst(os, segment->startVA, is64, "offset");
133writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "add");
134}
135writeU8(os, WASM_OPCODE_END, "opcode:end");
136} else {
137WasmInitExpr initExpr;
138initExpr.Extended = false;
139if (ctx.isPic) {
140assert(segment->startVA == 0);
141initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;
142initExpr.Inst.Value.Global = WasmSym::memoryBase->getGlobalIndex();
143} else {
144initExpr = intConst(segment->startVA, is64);
145}
146writeInitExpr(os, initExpr);
147}
148}
149writeUleb128(os, segment->size, "segment size");
150os.flush();
151
152segment->sectionOffset = bodySize;
153bodySize += segment->header.size() + segment->size;
154log("Data segment: size=" + Twine(segment->size) + ", startVA=" +
155Twine::utohexstr(segment->startVA) + ", name=" + segment->name);
156
157for (InputChunk *inputSeg : segment->inputSegments) {
158inputSeg->outputSec = this;
159inputSeg->outSecOff = segment->sectionOffset + segment->header.size() +
160inputSeg->outputSegmentOffset;
161}
162}
163
164createHeader(bodySize);
165}
166
167void DataSection::writeTo(uint8_t *buf) {
168log("writing " + toString(*this) + " offset=" + Twine(offset) +
169" size=" + Twine(getSize()) + " body=" + Twine(bodySize));
170buf += offset;
171
172// Write section header
173memcpy(buf, header.data(), header.size());
174buf += header.size();
175
176// Write data section headers
177memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size());
178
179for (const OutputSegment *segment : segments) {
180if (!segment->requiredInBinary())
181continue;
182// Write data segment header
183uint8_t *segStart = buf + segment->sectionOffset;
184memcpy(segStart, segment->header.data(), segment->header.size());
185
186// Write segment data payload
187for (const InputChunk *chunk : segment->inputSegments)
188chunk->writeTo(buf);
189}
190}
191
192uint32_t DataSection::getNumRelocations() const {
193uint32_t count = 0;
194for (const OutputSegment *seg : segments)
195for (const InputChunk *inputSeg : seg->inputSegments)
196count += inputSeg->getNumRelocations();
197return count;
198}
199
200void DataSection::writeRelocations(raw_ostream &os) const {
201for (const OutputSegment *seg : segments)
202for (const InputChunk *c : seg->inputSegments)
203c->writeRelocations(os);
204}
205
206bool DataSection::isNeeded() const {
207for (const OutputSegment *seg : segments)
208if (seg->requiredInBinary())
209return true;
210return false;
211}
212
213// Lots of duplication here with OutputSegment::finalizeInputSegments
214void CustomSection::finalizeInputSections() {
215SyntheticMergedChunk *mergedSection = nullptr;
216std::vector<InputChunk *> newSections;
217
218for (InputChunk *s : inputSections) {
219s->outputSec = this;
220MergeInputChunk *ms = dyn_cast<MergeInputChunk>(s);
221if (!ms) {
222newSections.push_back(s);
223continue;
224}
225
226if (!mergedSection) {
227mergedSection =
228make<SyntheticMergedChunk>(name, 0, WASM_SEG_FLAG_STRINGS);
229newSections.push_back(mergedSection);
230mergedSection->outputSec = this;
231}
232mergedSection->addMergeChunk(ms);
233}
234
235if (!mergedSection)
236return;
237
238mergedSection->finalizeContents();
239inputSections = newSections;
240}
241
242void CustomSection::finalizeContents() {
243finalizeInputSections();
244
245raw_string_ostream os(nameData);
246encodeULEB128(name.size(), os);
247os << name;
248os.flush();
249
250for (InputChunk *section : inputSections) {
251assert(!section->discarded);
252section->outSecOff = payloadSize;
253payloadSize += section->getSize();
254}
255
256createHeader(payloadSize + nameData.size());
257}
258
259void CustomSection::writeTo(uint8_t *buf) {
260log("writing " + toString(*this) + " offset=" + Twine(offset) +
261" size=" + Twine(getSize()) + " chunks=" + Twine(inputSections.size()));
262
263assert(offset);
264buf += offset;
265
266// Write section header
267memcpy(buf, header.data(), header.size());
268buf += header.size();
269memcpy(buf, nameData.data(), nameData.size());
270buf += nameData.size();
271
272// Write custom sections payload
273for (const InputChunk *section : inputSections)
274section->writeTo(buf);
275}
276
277uint32_t CustomSection::getNumRelocations() const {
278uint32_t count = 0;
279for (const InputChunk *inputSect : inputSections)
280count += inputSect->getNumRelocations();
281return count;
282}
283
284void CustomSection::writeRelocations(raw_ostream &os) const {
285for (const InputChunk *s : inputSections)
286s->writeRelocations(os);
287}
288
289} // namespace wasm
290} // namespace lld
291