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     WasmInitExpr InitExpr;
140     if (Config->Pic) {
141       assert(Segments.size() <= 1 &&
142              "Currenly only a single data segment is supported in PIC mode");
143       InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL;
144       InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
145     } else {
146       InitExpr.Opcode = WASM_OPCODE_I32_CONST;
147       InitExpr.Value.Int32 = Segment->StartVA;
148     }
149     writeInitExpr(OS, InitExpr);
150     writeUleb128(OS, Segment->Size, "segment size");
151     OS.flush();
152 
153     Segment->SectionOffset = BodySize;
154     BodySize += Segment->Header.size() + Segment->Size;
155     log("Data segment: size=" + Twine(Segment->Size));
156 
157     for (InputSegment *InputSeg : Segment->InputSegments)
158       InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
159                                InputSeg->OutputSegmentOffset;
160   }
161 
162   createHeader(BodySize);
163 }
164 
165 void DataSection::writeTo(uint8_t *Buf) {
166   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
167       " body=" + Twine(BodySize));
168   Buf += Offset;
169 
170   // Write section header
171   memcpy(Buf, Header.data(), Header.size());
172   Buf += Header.size();
173 
174   // Write data section headers
175   memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
176 
177   parallelForEach(Segments, [&](const OutputSegment *Segment) {
178     // Write data segment header
179     uint8_t *SegStart = Buf + Segment->SectionOffset;
180     memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
181 
182     // Write segment data payload
183     for (const InputChunk *Chunk : Segment->InputSegments)
184       Chunk->writeTo(Buf);
185   });
186 }
187 
188 uint32_t DataSection::numRelocations() const {
189   uint32_t Count = 0;
190   for (const OutputSegment *Seg : Segments)
191     for (const InputChunk *InputSeg : Seg->InputSegments)
192       Count += InputSeg->NumRelocations();
193   return Count;
194 }
195 
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);
200 }
201 
202 CustomSection::CustomSection(std::string Name,
203                              ArrayRef<InputSection *> InputSections)
204     : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
205       InputSections(InputSections) {
206   raw_string_ostream OS(NameData);
207   encodeULEB128(Name.size(), OS);
208   OS << Name;
209   OS.flush();
210 
211   for (InputSection *Section : InputSections) {
212     Section->OutputOffset = PayloadSize;
213     PayloadSize += Section->getSize();
214   }
215 
216   createHeader(PayloadSize + NameData.size());
217 }
218 
219 void CustomSection::writeTo(uint8_t *Buf) {
220   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
221       " chunks=" + Twine(InputSections.size()));
222 
223   assert(Offset);
224   Buf += Offset;
225 
226   // Write section header
227   memcpy(Buf, Header.data(), Header.size());
228   Buf += Header.size();
229   memcpy(Buf, NameData.data(), NameData.size());
230   Buf += NameData.size();
231 
232   // Write custom sections payload
233   parallelForEach(InputSections,
234                   [&](const InputSection *Section) { Section->writeTo(Buf); });
235 }
236 
237 uint32_t CustomSection::numRelocations() const {
238   uint32_t Count = 0;
239   for (const InputSection *InputSect : InputSections)
240     Count += InputSect->NumRelocations();
241   return Count;
242 }
243 
244 void CustomSection::writeRelocations(raw_ostream &OS) const {
245   for (const InputSection *S : InputSections)
246     S->writeRelocations(OS);
247 }
248