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_EVENT: 44 return "EVENT"; 45 case WASM_SEC_EXPORT: 46 return "EXPORT"; 47 case WASM_SEC_START: 48 return "START"; 49 case WASM_SEC_ELEM: 50 return "ELEM"; 51 case WASM_SEC_CODE: 52 return "CODE"; 53 case WASM_SEC_DATA: 54 return "DATA"; 55 default: 56 fatal("invalid section type"); 57 } 58 } 59 60 // Returns a string, e.g. "FUNCTION(.text)". 61 std::string lld::toString(const OutputSection &Sec) { 62 if (!Sec.Name.empty()) 63 return (Sec.getSectionName() + "(" + Sec.Name + ")").str(); 64 return Sec.getSectionName(); 65 } 66 67 StringRef OutputSection::getSectionName() const { 68 return sectionTypeToString(Type); 69 } 70 71 void OutputSection::createHeader(size_t BodySize) { 72 raw_string_ostream OS(Header); 73 debugWrite(OS.tell(), "section type [" + getSectionName() + "]"); 74 encodeULEB128(Type, OS); 75 writeUleb128(OS, BodySize, "section size"); 76 OS.flush(); 77 log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) + 78 " total=" + Twine(getSize())); 79 } 80 81 CodeSection::CodeSection(ArrayRef<InputFunction *> Functions) 82 : OutputSection(WASM_SEC_CODE), Functions(Functions) { 83 assert(Functions.size() > 0); 84 85 raw_string_ostream OS(CodeSectionHeader); 86 writeUleb128(OS, Functions.size(), "function count"); 87 OS.flush(); 88 BodySize = CodeSectionHeader.size(); 89 90 for (InputFunction *Func : Functions) { 91 Func->OutputOffset = BodySize; 92 Func->calculateSize(); 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 // Write code section headers 111 memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size()); 112 113 // Write code section bodies 114 parallelForEach(Functions, 115 [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); }); 116 } 117 118 uint32_t CodeSection::numRelocations() const { 119 uint32_t Count = 0; 120 for (const InputChunk *Func : Functions) 121 Count += Func->NumRelocations(); 122 return Count; 123 } 124 125 void CodeSection::writeRelocations(raw_ostream &OS) const { 126 for (const InputChunk *C : Functions) 127 C->writeRelocations(OS); 128 } 129 130 DataSection::DataSection(ArrayRef<OutputSegment *> Segments) 131 : OutputSection(WASM_SEC_DATA), Segments(Segments) { 132 raw_string_ostream OS(DataSectionHeader); 133 134 writeUleb128(OS, Segments.size(), "data segment count"); 135 OS.flush(); 136 BodySize = DataSectionHeader.size(); 137 138 for (OutputSegment *Segment : Segments) { 139 raw_string_ostream OS(Segment->Header); 140 writeUleb128(OS, 0, "memory index"); 141 WasmInitExpr InitExpr; 142 if (Config->Pic) { 143 assert(Segments.size() <= 1 && 144 "Currenly only a single data segment is supported in PIC mode"); 145 InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL; 146 InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex(); 147 } else { 148 InitExpr.Opcode = WASM_OPCODE_I32_CONST; 149 InitExpr.Value.Int32 = Segment->StartVA; 150 } 151 writeInitExpr(OS, InitExpr); 152 writeUleb128(OS, Segment->Size, "segment size"); 153 OS.flush(); 154 155 Segment->SectionOffset = BodySize; 156 BodySize += Segment->Header.size() + Segment->Size; 157 log("Data segment: size=" + Twine(Segment->Size)); 158 159 for (InputSegment *InputSeg : Segment->InputSegments) 160 InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() + 161 InputSeg->OutputSegmentOffset; 162 } 163 164 createHeader(BodySize); 165 } 166 167 void DataSection::writeTo(uint8_t *Buf) { 168 log("writing " + toString(*this) + " size=" + Twine(getSize()) + 169 " body=" + Twine(BodySize)); 170 Buf += Offset; 171 172 // Write section header 173 memcpy(Buf, Header.data(), Header.size()); 174 Buf += Header.size(); 175 176 // Write data section headers 177 memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size()); 178 179 parallelForEach(Segments, [&](const OutputSegment *Segment) { 180 // Write data segment header 181 uint8_t *SegStart = Buf + Segment->SectionOffset; 182 memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); 183 184 // Write segment data payload 185 for (const InputChunk *Chunk : Segment->InputSegments) 186 Chunk->writeTo(Buf); 187 }); 188 } 189 190 uint32_t DataSection::numRelocations() const { 191 uint32_t Count = 0; 192 for (const OutputSegment *Seg : Segments) 193 for (const InputChunk *InputSeg : Seg->InputSegments) 194 Count += InputSeg->NumRelocations(); 195 return Count; 196 } 197 198 void DataSection::writeRelocations(raw_ostream &OS) const { 199 for (const OutputSegment *Seg : Segments) 200 for (const InputChunk *C : Seg->InputSegments) 201 C->writeRelocations(OS); 202 } 203 204 CustomSection::CustomSection(std::string Name, 205 ArrayRef<InputSection *> InputSections) 206 : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0), 207 InputSections(InputSections) { 208 raw_string_ostream OS(NameData); 209 encodeULEB128(Name.size(), OS); 210 OS << Name; 211 OS.flush(); 212 213 for (InputSection *Section : InputSections) { 214 Section->OutputOffset = PayloadSize; 215 PayloadSize += Section->getSize(); 216 } 217 218 createHeader(PayloadSize + NameData.size()); 219 } 220 221 void CustomSection::writeTo(uint8_t *Buf) { 222 log("writing " + toString(*this) + " size=" + Twine(getSize()) + 223 " chunks=" + Twine(InputSections.size())); 224 225 assert(Offset); 226 Buf += Offset; 227 228 // Write section header 229 memcpy(Buf, Header.data(), Header.size()); 230 Buf += Header.size(); 231 memcpy(Buf, NameData.data(), NameData.size()); 232 Buf += NameData.size(); 233 234 // Write custom sections payload 235 parallelForEach(InputSections, 236 [&](const InputSection *Section) { Section->writeTo(Buf); }); 237 } 238 239 uint32_t CustomSection::numRelocations() const { 240 uint32_t Count = 0; 241 for (const InputSection *InputSect : InputSections) 242 Count += InputSect->NumRelocations(); 243 return Count; 244 } 245 246 void CustomSection::writeRelocations(raw_ostream &OS) const { 247 for (const InputSection *S : InputSections) 248 S->writeRelocations(OS); 249 } 250