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_EVENT:
44     return "EVENT";
45   case WASM_SEC_EXPORT:
46     return "EXPORT";
47   case WASM_SEC_START:
48     return "START";
49   case WASM_SEC_ELEM:
50     return "ELEM";
51   case WASM_SEC_CODE:
52     return "CODE";
53   case WASM_SEC_DATA:
54     return "DATA";
55   default:
56     fatal("invalid section type");
57   }
58 }
59 
60 // Returns a string, e.g. "FUNCTION(.text)".
61 std::string lld::toString(const OutputSection &Sec) {
62   if (!Sec.Name.empty())
63     return (Sec.getSectionName() + "(" + Sec.Name + ")").str();
64   return Sec.getSectionName();
65 }
66 
67 StringRef OutputSection::getSectionName() const {
68   return sectionTypeToString(Type);
69 }
70 
71 void OutputSection::createHeader(size_t BodySize) {
72   raw_string_ostream OS(Header);
73   debugWrite(OS.tell(), "section type [" + getSectionName() + "]");
74   encodeULEB128(Type, OS);
75   writeUleb128(OS, BodySize, "section size");
76   OS.flush();
77   log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
78       " total=" + Twine(getSize()));
79 }
80 
81 CodeSection::CodeSection(ArrayRef<InputFunction *> Functions)
82     : OutputSection(WASM_SEC_CODE), Functions(Functions) {
83   assert(Functions.size() > 0);
84 
85   raw_string_ostream OS(CodeSectionHeader);
86   writeUleb128(OS, Functions.size(), "function count");
87   OS.flush();
88   BodySize = CodeSectionHeader.size();
89 
90   for (InputFunction *Func : Functions) {
91     Func->OutputOffset = BodySize;
92     Func->calculateSize();
93     BodySize += Func->getSize();
94   }
95 
96   createHeader(BodySize);
97 }
98 
99 void CodeSection::writeTo(uint8_t *Buf) {
100   log("writing " + toString(*this));
101   log(" size=" + Twine(getSize()));
102   log(" headersize=" + Twine(Header.size()));
103   log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
104   Buf += Offset;
105 
106   // Write section header
107   memcpy(Buf, Header.data(), Header.size());
108   Buf += Header.size();
109 
110   // Write code section headers
111   memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
112 
113   // Write code section bodies
114   parallelForEach(Functions,
115                   [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); });
116 }
117 
118 uint32_t CodeSection::numRelocations() const {
119   uint32_t Count = 0;
120   for (const InputChunk *Func : Functions)
121     Count += Func->NumRelocations();
122   return Count;
123 }
124 
125 void CodeSection::writeRelocations(raw_ostream &OS) const {
126   for (const InputChunk *C : Functions)
127     C->writeRelocations(OS);
128 }
129 
130 DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
131     : OutputSection(WASM_SEC_DATA), Segments(Segments) {
132   raw_string_ostream OS(DataSectionHeader);
133 
134   writeUleb128(OS, Segments.size(), "data segment count");
135   OS.flush();
136   BodySize = DataSectionHeader.size();
137 
138   for (OutputSegment *Segment : Segments) {
139     raw_string_ostream OS(Segment->Header);
140     writeUleb128(OS, 0, "memory index");
141     WasmInitExpr InitExpr;
142     if (Config->Pic) {
143       assert(Segments.size() <= 1 &&
144              "Currenly only a single data segment is supported in PIC mode");
145       InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL;
146       InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
147     } else {
148       InitExpr.Opcode = WASM_OPCODE_I32_CONST;
149       InitExpr.Value.Int32 = Segment->StartVA;
150     }
151     writeInitExpr(OS, InitExpr);
152     writeUleb128(OS, Segment->Size, "segment size");
153     OS.flush();
154 
155     Segment->SectionOffset = BodySize;
156     BodySize += Segment->Header.size() + Segment->Size;
157     log("Data segment: size=" + Twine(Segment->Size));
158 
159     for (InputSegment *InputSeg : Segment->InputSegments)
160       InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
161                                InputSeg->OutputSegmentOffset;
162   }
163 
164   createHeader(BodySize);
165 }
166 
167 void DataSection::writeTo(uint8_t *Buf) {
168   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
169       " body=" + Twine(BodySize));
170   Buf += Offset;
171 
172   // Write section header
173   memcpy(Buf, Header.data(), Header.size());
174   Buf += Header.size();
175 
176   // Write data section headers
177   memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
178 
179   parallelForEach(Segments, [&](const OutputSegment *Segment) {
180     // Write data segment header
181     uint8_t *SegStart = Buf + Segment->SectionOffset;
182     memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
183 
184     // Write segment data payload
185     for (const InputChunk *Chunk : Segment->InputSegments)
186       Chunk->writeTo(Buf);
187   });
188 }
189 
190 uint32_t DataSection::numRelocations() const {
191   uint32_t Count = 0;
192   for (const OutputSegment *Seg : Segments)
193     for (const InputChunk *InputSeg : Seg->InputSegments)
194       Count += InputSeg->NumRelocations();
195   return Count;
196 }
197 
198 void DataSection::writeRelocations(raw_ostream &OS) const {
199   for (const OutputSegment *Seg : Segments)
200     for (const InputChunk *C : Seg->InputSegments)
201       C->writeRelocations(OS);
202 }
203 
204 CustomSection::CustomSection(std::string Name,
205                              ArrayRef<InputSection *> InputSections)
206     : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
207       InputSections(InputSections) {
208   raw_string_ostream OS(NameData);
209   encodeULEB128(Name.size(), OS);
210   OS << Name;
211   OS.flush();
212 
213   for (InputSection *Section : InputSections) {
214     Section->OutputOffset = PayloadSize;
215     PayloadSize += Section->getSize();
216   }
217 
218   createHeader(PayloadSize + NameData.size());
219 }
220 
221 void CustomSection::writeTo(uint8_t *Buf) {
222   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
223       " chunks=" + Twine(InputSections.size()));
224 
225   assert(Offset);
226   Buf += Offset;
227 
228   // Write section header
229   memcpy(Buf, Header.data(), Header.size());
230   Buf += Header.size();
231   memcpy(Buf, NameData.data(), NameData.size());
232   Buf += NameData.size();
233 
234   // Write custom sections payload
235   parallelForEach(InputSections,
236                   [&](const InputSection *Section) { Section->writeTo(Buf); });
237 }
238 
239 uint32_t CustomSection::numRelocations() const {
240   uint32_t Count = 0;
241   for (const InputSection *InputSect : InputSections)
242     Count += InputSect->NumRelocations();
243   return Count;
244 }
245 
246 void CustomSection::writeRelocations(raw_ostream &OS) const {
247   for (const InputSection *S : InputSections)
248     S->writeRelocations(OS);
249 }
250