]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - wasm/OutputSections.cpp
Vendor import of lld trunk r338150:
[FreeBSD/FreeBSD.git] / wasm / OutputSections.cpp
1 //===- 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 #include "InputChunks.h"
12 #include "InputFiles.h"
13 #include "OutputSegment.h"
14 #include "WriterUtils.h"
15 #include "lld/Common/ErrorHandler.h"
16 #include "lld/Common/Threads.h"
17 #include "llvm/ADT/Twine.h"
18 #include "llvm/Support/LEB128.h"
19
20 #define DEBUG_TYPE "lld"
21
22 using namespace llvm;
23 using namespace llvm::wasm;
24 using namespace lld;
25 using namespace lld::wasm;
26
27 static StringRef sectionTypeToString(uint32_t SectionType) {
28   switch (SectionType) {
29   case WASM_SEC_CUSTOM:
30     return "CUSTOM";
31   case WASM_SEC_TYPE:
32     return "TYPE";
33   case WASM_SEC_IMPORT:
34     return "IMPORT";
35   case WASM_SEC_FUNCTION:
36     return "FUNCTION";
37   case WASM_SEC_TABLE:
38     return "TABLE";
39   case WASM_SEC_MEMORY:
40     return "MEMORY";
41   case WASM_SEC_GLOBAL:
42     return "GLOBAL";
43   case WASM_SEC_EXPORT:
44     return "EXPORT";
45   case WASM_SEC_START:
46     return "START";
47   case WASM_SEC_ELEM:
48     return "ELEM";
49   case WASM_SEC_CODE:
50     return "CODE";
51   case WASM_SEC_DATA:
52     return "DATA";
53   default:
54     fatal("invalid section type");
55   }
56 }
57
58 // Returns a string, e.g. "FUNCTION(.text)".
59 std::string lld::toString(const OutputSection &Sec) {
60   if (!Sec.Name.empty())
61     return (Sec.getSectionName() + "(" + Sec.Name + ")").str();
62   return Sec.getSectionName();
63 }
64
65 StringRef OutputSection::getSectionName() const {
66   return sectionTypeToString(Type);
67 }
68
69 void OutputSection::createHeader(size_t BodySize) {
70   raw_string_ostream OS(Header);
71   debugWrite(OS.tell(), "section type [" + getSectionName() + "]");
72   encodeULEB128(Type, OS);
73   writeUleb128(OS, BodySize, "section size");
74   OS.flush();
75   log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
76       " total=" + Twine(getSize()));
77 }
78
79 CodeSection::CodeSection(ArrayRef<InputFunction *> Functions)
80     : OutputSection(WASM_SEC_CODE), Functions(Functions) {
81   assert(Functions.size() > 0);
82
83   raw_string_ostream OS(CodeSectionHeader);
84   writeUleb128(OS, Functions.size(), "function count");
85   OS.flush();
86   BodySize = CodeSectionHeader.size();
87
88   for (InputFunction *Func : Functions) {
89     Func->OutputOffset = BodySize;
90     Func->calculateSize();
91     BodySize += Func->getSize();
92   }
93
94   createHeader(BodySize);
95 }
96
97 void CodeSection::writeTo(uint8_t *Buf) {
98   log("writing " + toString(*this));
99   log(" size=" + Twine(getSize()));
100   log(" headersize=" + Twine(Header.size()));
101   log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
102   Buf += Offset;
103
104   // Write section header
105   memcpy(Buf, Header.data(), Header.size());
106   Buf += Header.size();
107
108   // Write code section headers
109   memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
110
111   // Write code section bodies
112   parallelForEach(Functions,
113                   [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); });
114 }
115
116 uint32_t CodeSection::numRelocations() const {
117   uint32_t Count = 0;
118   for (const InputChunk *Func : Functions)
119     Count += Func->NumRelocations();
120   return Count;
121 }
122
123 void CodeSection::writeRelocations(raw_ostream &OS) const {
124   for (const InputChunk *C : Functions)
125     C->writeRelocations(OS);
126 }
127
128 DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
129     : OutputSection(WASM_SEC_DATA), Segments(Segments) {
130   raw_string_ostream OS(DataSectionHeader);
131
132   writeUleb128(OS, Segments.size(), "data segment count");
133   OS.flush();
134   BodySize = DataSectionHeader.size();
135
136   for (OutputSegment *Segment : Segments) {
137     raw_string_ostream OS(Segment->Header);
138     writeUleb128(OS, 0, "memory index");
139     writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
140     writeSleb128(OS, Segment->StartVA, "memory offset");
141     writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
142     writeUleb128(OS, Segment->Size, "segment size");
143     OS.flush();
144
145     Segment->SectionOffset = BodySize;
146     BodySize += Segment->Header.size() + Segment->Size;
147     log("Data segment: size=" + Twine(Segment->Size));
148
149     for (InputSegment *InputSeg : Segment->InputSegments)
150       InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
151                                InputSeg->OutputSegmentOffset;
152   }
153
154   createHeader(BodySize);
155 }
156
157 void DataSection::writeTo(uint8_t *Buf) {
158   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
159       " body=" + Twine(BodySize));
160   Buf += Offset;
161
162   // Write section header
163   memcpy(Buf, Header.data(), Header.size());
164   Buf += Header.size();
165
166   // Write data section headers
167   memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
168
169   parallelForEach(Segments, [&](const OutputSegment *Segment) {
170     // Write data segment header
171     uint8_t *SegStart = Buf + Segment->SectionOffset;
172     memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
173
174     // Write segment data payload
175     for (const InputChunk *Chunk : Segment->InputSegments)
176       Chunk->writeTo(Buf);
177   });
178 }
179
180 uint32_t DataSection::numRelocations() const {
181   uint32_t Count = 0;
182   for (const OutputSegment *Seg : Segments)
183     for (const InputChunk *InputSeg : Seg->InputSegments)
184       Count += InputSeg->NumRelocations();
185   return Count;
186 }
187
188 void DataSection::writeRelocations(raw_ostream &OS) const {
189   for (const OutputSegment *Seg : Segments)
190     for (const InputChunk *C : Seg->InputSegments)
191       C->writeRelocations(OS);
192 }
193
194 CustomSection::CustomSection(std::string Name,
195                              ArrayRef<InputSection *> InputSections)
196     : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
197       InputSections(InputSections) {
198   raw_string_ostream OS(NameData);
199   encodeULEB128(Name.size(), OS);
200   OS << Name;
201   OS.flush();
202
203   for (InputSection *Section : InputSections) {
204     Section->OutputOffset = PayloadSize;
205     PayloadSize += Section->getSize();
206   }
207
208   createHeader(PayloadSize + NameData.size());
209 }
210
211 void CustomSection::writeTo(uint8_t *Buf) {
212   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
213       " chunks=" + Twine(InputSections.size()));
214
215   assert(Offset);
216   Buf += Offset;
217
218   // Write section header
219   memcpy(Buf, Header.data(), Header.size());
220   Buf += Header.size();
221   memcpy(Buf, NameData.data(), NameData.size());
222   Buf += NameData.size();
223
224   // Write custom sections payload
225   parallelForEach(InputSections,
226                   [&](const InputSection *Section) { Section->writeTo(Buf); });
227 }
228
229 uint32_t CustomSection::numRelocations() const {
230   uint32_t Count = 0;
231   for (const InputSection *InputSect : InputSections)
232     Count += InputSect->NumRelocations();
233   return Count;
234 }
235
236 void CustomSection::writeRelocations(raw_ostream &OS) const {
237   for (const InputSection *S : InputSections)
238     S->writeRelocations(OS);
239 }