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 (InputChunk *Func : Functions) {
89     Func->OutputOffset = BodySize;
90     BodySize += Func->getSize();
91   }
92 
93   createHeader(BodySize);
94 }
95 
96 void CodeSection::writeTo(uint8_t *Buf) {
97   log("writing " + toString(*this));
98   log(" size=" + Twine(getSize()));
99   log(" headersize=" + Twine(Header.size()));
100   log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
101   Buf += Offset;
102 
103   // Write section header
104   memcpy(Buf, Header.data(), Header.size());
105   Buf += Header.size();
106 
107   // Write code section headers
108   memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
109 
110   // Write code section bodies
111   parallelForEach(Functions,
112                   [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); });
113 }
114 
115 uint32_t CodeSection::numRelocations() const {
116   uint32_t Count = 0;
117   for (const InputChunk *Func : Functions)
118     Count += Func->NumRelocations();
119   return Count;
120 }
121 
122 void CodeSection::writeRelocations(raw_ostream &OS) const {
123   for (const InputChunk *C : Functions)
124     C->writeRelocations(OS);
125 }
126 
127 DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
128     : OutputSection(WASM_SEC_DATA), Segments(Segments) {
129   raw_string_ostream OS(DataSectionHeader);
130 
131   writeUleb128(OS, Segments.size(), "data segment count");
132   OS.flush();
133   BodySize = DataSectionHeader.size();
134 
135   for (OutputSegment *Segment : Segments) {
136     raw_string_ostream OS(Segment->Header);
137     writeUleb128(OS, 0, "memory index");
138     writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
139     writeSleb128(OS, Segment->StartVA, "memory offset");
140     writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
141     writeUleb128(OS, Segment->Size, "segment size");
142     OS.flush();
143 
144     Segment->SectionOffset = BodySize;
145     BodySize += Segment->Header.size() + Segment->Size;
146     log("Data segment: size=" + Twine(Segment->Size));
147 
148     for (InputSegment *InputSeg : Segment->InputSegments)
149       InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
150                                InputSeg->OutputSegmentOffset;
151   }
152 
153   createHeader(BodySize);
154 }
155 
156 void DataSection::writeTo(uint8_t *Buf) {
157   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
158       " body=" + Twine(BodySize));
159   Buf += Offset;
160 
161   // Write section header
162   memcpy(Buf, Header.data(), Header.size());
163   Buf += Header.size();
164 
165   // Write data section headers
166   memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
167 
168   parallelForEach(Segments, [&](const OutputSegment *Segment) {
169     // Write data segment header
170     uint8_t *SegStart = Buf + Segment->SectionOffset;
171     memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
172 
173     // Write segment data payload
174     for (const InputChunk *Chunk : Segment->InputSegments)
175       Chunk->writeTo(Buf);
176   });
177 }
178 
179 uint32_t DataSection::numRelocations() const {
180   uint32_t Count = 0;
181   for (const OutputSegment *Seg : Segments)
182     for (const InputChunk *InputSeg : Seg->InputSegments)
183       Count += InputSeg->NumRelocations();
184   return Count;
185 }
186 
187 void DataSection::writeRelocations(raw_ostream &OS) const {
188   for (const OutputSegment *Seg : Segments)
189     for (const InputChunk *C : Seg->InputSegments)
190       C->writeRelocations(OS);
191 }
192 
193 CustomSection::CustomSection(std::string Name,
194                              ArrayRef<InputSection *> InputSections)
195     : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0),
196       InputSections(InputSections) {
197   raw_string_ostream OS(NameData);
198   encodeULEB128(Name.size(), OS);
199   OS << Name;
200   OS.flush();
201 
202   for (InputSection *Section : InputSections) {
203     Section->OutputOffset = PayloadSize;
204     PayloadSize += Section->getSize();
205   }
206 
207   createHeader(PayloadSize + NameData.size());
208 }
209 
210 void CustomSection::writeTo(uint8_t *Buf) {
211   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
212       " chunks=" + Twine(InputSections.size()));
213 
214   assert(Offset);
215   Buf += Offset;
216 
217   // Write section header
218   memcpy(Buf, Header.data(), Header.size());
219   Buf += Header.size();
220   memcpy(Buf, NameData.data(), NameData.size());
221   Buf += NameData.size();
222 
223   // Write custom sections payload
224   parallelForEach(InputSections,
225                   [&](const InputSection *Section) { Section->writeTo(Buf); });
226 }
227 
228 uint32_t CustomSection::numRelocations() const {
229   uint32_t Count = 0;
230   for (const InputSection *InputSect : InputSections)
231     Count += InputSect->NumRelocations();
232   return Count;
233 }
234 
235 void CustomSection::writeRelocations(raw_ostream &OS) const {
236   for (const InputSection *S : InputSections)
237     S->writeRelocations(OS);
238 }
239