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 } 240