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 Segment->setSectionOffset(BodySize); 144 BodySize += Segment->Header.size() + Segment->Size; 145 log("Data segment: size=" + Twine(Segment->Size)); 146 for (InputSegment *InputSeg : Segment->InputSegments) 147 InputSeg->OutputOffset = Segment->getSectionOffset() + 148 Segment->Header.size() + 149 InputSeg->OutputSegmentOffset; 150 } 151 152 createHeader(BodySize); 153 } 154 155 void DataSection::writeTo(uint8_t *Buf) { 156 log("writing " + toString(*this) + " size=" + Twine(getSize()) + 157 " body=" + Twine(BodySize)); 158 Buf += Offset; 159 160 // Write section header 161 memcpy(Buf, Header.data(), Header.size()); 162 Buf += Header.size(); 163 164 // Write data section headers 165 memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size()); 166 167 parallelForEach(Segments, [&](const OutputSegment *Segment) { 168 // Write data segment header 169 uint8_t *SegStart = Buf + Segment->getSectionOffset(); 170 memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); 171 172 // Write segment data payload 173 for (const InputChunk *Chunk : Segment->InputSegments) 174 Chunk->writeTo(Buf); 175 }); 176 } 177 178 uint32_t DataSection::numRelocations() const { 179 uint32_t Count = 0; 180 for (const OutputSegment *Seg : Segments) 181 for (const InputChunk *InputSeg : Seg->InputSegments) 182 Count += InputSeg->NumRelocations(); 183 return Count; 184 } 185 186 void DataSection::writeRelocations(raw_ostream &OS) const { 187 for (const OutputSegment *Seg : Segments) 188 for (const InputChunk *C : Seg->InputSegments) 189 C->writeRelocations(OS); 190 } 191