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