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 
12 #include "InputChunks.h"
13 #include "InputFiles.h"
14 #include "OutputSegment.h"
15 #include "lld/Common/ErrorHandler.h"
16 #include "lld/Common/Threads.h"
17 #include "llvm/ADT/Twine.h"
18 
19 #define DEBUG_TYPE "lld"
20 
21 using namespace llvm;
22 using namespace llvm::wasm;
23 using namespace lld;
24 using namespace lld::wasm;
25 
26 static StringRef sectionTypeToString(uint32_t SectionType) {
27   switch (SectionType) {
28   case WASM_SEC_CUSTOM:
29     return "CUSTOM";
30   case WASM_SEC_TYPE:
31     return "TYPE";
32   case WASM_SEC_IMPORT:
33     return "IMPORT";
34   case WASM_SEC_FUNCTION:
35     return "FUNCTION";
36   case WASM_SEC_TABLE:
37     return "TABLE";
38   case WASM_SEC_MEMORY:
39     return "MEMORY";
40   case WASM_SEC_GLOBAL:
41     return "GLOBAL";
42   case WASM_SEC_EXPORT:
43     return "EXPORT";
44   case WASM_SEC_START:
45     return "START";
46   case WASM_SEC_ELEM:
47     return "ELEM";
48   case WASM_SEC_CODE:
49     return "CODE";
50   case WASM_SEC_DATA:
51     return "DATA";
52   default:
53     fatal("invalid section type");
54   }
55 }
56 
57 std::string lld::toString(const OutputSection &Section) {
58   std::string rtn = Section.getSectionName();
59   if (!Section.Name.empty())
60     rtn += "(" + Section.Name + ")";
61   return rtn;
62 }
63 
64 std::string OutputSection::getSectionName() const {
65   return sectionTypeToString(Type);
66 }
67 
68 std::string SubSection::getSectionName() const {
69   return std::string("subsection <type=") + std::to_string(Type) + ">";
70 }
71 
72 void OutputSection::createHeader(size_t BodySize) {
73   raw_string_ostream OS(Header);
74   debugWrite(OS.tell(), "section type [" + Twine(getSectionName()) + "]");
75   writeUleb128(OS, Type, nullptr);
76   writeUleb128(OS, BodySize, "section size");
77   OS.flush();
78   log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
79       " total=" + Twine(getSize()));
80 }
81 
82 CodeSection::CodeSection(ArrayRef<InputFunction *> Functions)
83     : OutputSection(WASM_SEC_CODE), Functions(Functions) {
84   assert(Functions.size() > 0);
85 
86   raw_string_ostream OS(CodeSectionHeader);
87   writeUleb128(OS, Functions.size(), "function count");
88   OS.flush();
89   BodySize = CodeSectionHeader.size();
90 
91   for (InputChunk *Func : Functions) {
92     Func->setOutputOffset(BodySize);
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   uint8_t *ContentsStart = Buf;
111 
112   // Write code section headers
113   memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
114   Buf += CodeSectionHeader.size();
115 
116   // Write code section bodies
117   parallelForEach(Functions, [ContentsStart](const InputChunk *Chunk) {
118     Chunk->writeTo(ContentsStart);
119   });
120 }
121 
122 uint32_t CodeSection::numRelocations() const {
123   uint32_t Count = 0;
124   for (const InputChunk *Func : Functions)
125     Count += Func->OutRelocations.size();
126   return Count;
127 }
128 
129 void CodeSection::writeRelocations(raw_ostream &OS) const {
130   for (const InputChunk *Func : Functions)
131     for (const OutputRelocation &Reloc : Func->OutRelocations)
132       writeReloc(OS, Reloc);
133 }
134 
135 DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
136     : OutputSection(WASM_SEC_DATA), Segments(Segments) {
137   raw_string_ostream OS(DataSectionHeader);
138 
139   writeUleb128(OS, Segments.size(), "data segment count");
140   OS.flush();
141   BodySize = DataSectionHeader.size();
142 
143   for (OutputSegment *Segment : Segments) {
144     raw_string_ostream OS(Segment->Header);
145     writeUleb128(OS, 0, "memory index");
146     writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
147     writeSleb128(OS, Segment->StartVA, "memory offset");
148     writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
149     writeUleb128(OS, Segment->Size, "segment size");
150     OS.flush();
151     Segment->setSectionOffset(BodySize);
152     BodySize += Segment->Header.size() + Segment->Size;
153     log("Data segment: size=" + Twine(Segment->Size));
154     for (InputSegment *InputSeg : Segment->InputSegments)
155       InputSeg->setOutputOffset(Segment->getSectionOffset() +
156                                 Segment->Header.size() +
157                                 InputSeg->OutputSegmentOffset);
158   }
159 
160   createHeader(BodySize);
161 }
162 
163 void DataSection::writeTo(uint8_t *Buf) {
164   log("writing " + toString(*this) + " size=" + Twine(getSize()) +
165       " body=" + Twine(BodySize));
166   Buf += Offset;
167 
168   // Write section header
169   memcpy(Buf, Header.data(), Header.size());
170   Buf += Header.size();
171 
172   uint8_t *ContentsStart = Buf;
173 
174   // Write data section headers
175   memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
176 
177   parallelForEach(Segments, [ContentsStart](const OutputSegment *Segment) {
178     // Write data segment header
179     uint8_t *SegStart = ContentsStart + Segment->getSectionOffset();
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(ContentsStart);
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->OutRelocations.size();
193   return Count;
194 }
195 
196 void DataSection::writeRelocations(raw_ostream &OS) const {
197   for (const OutputSegment *Seg : Segments)
198     for (const InputChunk *InputSeg : Seg->InputSegments)
199       for (const OutputRelocation &Reloc : InputSeg->OutRelocations)
200         writeReloc(OS, Reloc);
201 }
202