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 WasmInitExpr InitExpr; 140 if (Config->Pic) { 141 assert(Segments.size() <= 1 && 142 "Currenly only a single data segment is supported in PIC mode"); 143 InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL; 144 InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex(); 145 } else { 146 InitExpr.Opcode = WASM_OPCODE_I32_CONST; 147 InitExpr.Value.Int32 = Segment->StartVA; 148 } 149 writeInitExpr(OS, InitExpr); 150 writeUleb128(OS, Segment->Size, "segment size"); 151 OS.flush(); 152 153 Segment->SectionOffset = BodySize; 154 BodySize += Segment->Header.size() + Segment->Size; 155 log("Data segment: size=" + Twine(Segment->Size)); 156 157 for (InputSegment *InputSeg : Segment->InputSegments) 158 InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() + 159 InputSeg->OutputSegmentOffset; 160 } 161 162 createHeader(BodySize); 163 } 164 165 void DataSection::writeTo(uint8_t *Buf) { 166 log("writing " + toString(*this) + " size=" + Twine(getSize()) + 167 " body=" + Twine(BodySize)); 168 Buf += Offset; 169 170 // Write section header 171 memcpy(Buf, Header.data(), Header.size()); 172 Buf += Header.size(); 173 174 // Write data section headers 175 memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size()); 176 177 parallelForEach(Segments, [&](const OutputSegment *Segment) { 178 // Write data segment header 179 uint8_t *SegStart = Buf + Segment->SectionOffset; 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(Buf); 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->NumRelocations(); 193 return Count; 194 } 195 196 void DataSection::writeRelocations(raw_ostream &OS) const { 197 for (const OutputSegment *Seg : Segments) 198 for (const InputChunk *C : Seg->InputSegments) 199 C->writeRelocations(OS); 200 } 201 202 CustomSection::CustomSection(std::string Name, 203 ArrayRef<InputSection *> InputSections) 204 : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0), 205 InputSections(InputSections) { 206 raw_string_ostream OS(NameData); 207 encodeULEB128(Name.size(), OS); 208 OS << Name; 209 OS.flush(); 210 211 for (InputSection *Section : InputSections) { 212 Section->OutputOffset = PayloadSize; 213 PayloadSize += Section->getSize(); 214 } 215 216 createHeader(PayloadSize + NameData.size()); 217 } 218 219 void CustomSection::writeTo(uint8_t *Buf) { 220 log("writing " + toString(*this) + " size=" + Twine(getSize()) + 221 " chunks=" + Twine(InputSections.size())); 222 223 assert(Offset); 224 Buf += Offset; 225 226 // Write section header 227 memcpy(Buf, Header.data(), Header.size()); 228 Buf += Header.size(); 229 memcpy(Buf, NameData.data(), NameData.size()); 230 Buf += NameData.size(); 231 232 // Write custom sections payload 233 parallelForEach(InputSections, 234 [&](const InputSection *Section) { Section->writeTo(Buf); }); 235 } 236 237 uint32_t CustomSection::numRelocations() const { 238 uint32_t Count = 0; 239 for (const InputSection *InputSect : InputSections) 240 Count += InputSect->NumRelocations(); 241 return Count; 242 } 243 244 void CustomSection::writeRelocations(raw_ostream &OS) const { 245 for (const InputSection *S : InputSections) 246 S->writeRelocations(OS); 247 } 248