1 //===- OutputSections.cpp -------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "OutputSections.h" 10 #include "InputChunks.h" 11 #include "InputElement.h" 12 #include "InputFiles.h" 13 #include "OutputSegment.h" 14 #include "WriterUtils.h" 15 #include "lld/Common/ErrorHandler.h" 16 #include "lld/Common/Memory.h" 17 #include "llvm/ADT/Twine.h" 18 #include "llvm/Support/LEB128.h" 19 #include "llvm/Support/Parallel.h" 20 21 #define DEBUG_TYPE "lld" 22 23 using namespace llvm; 24 using namespace llvm::wasm; 25 26 namespace lld { 27 28 // Returns a string, e.g. "FUNCTION(.text)". 29 std::string toString(const wasm::OutputSection &sec) { 30 if (!sec.name.empty()) 31 return (sec.getSectionName() + "(" + sec.name + ")").str(); 32 return std::string(sec.getSectionName()); 33 } 34 35 namespace wasm { 36 static StringRef sectionTypeToString(uint32_t sectionType) { 37 switch (sectionType) { 38 case WASM_SEC_CUSTOM: 39 return "CUSTOM"; 40 case WASM_SEC_TYPE: 41 return "TYPE"; 42 case WASM_SEC_IMPORT: 43 return "IMPORT"; 44 case WASM_SEC_FUNCTION: 45 return "FUNCTION"; 46 case WASM_SEC_TABLE: 47 return "TABLE"; 48 case WASM_SEC_MEMORY: 49 return "MEMORY"; 50 case WASM_SEC_GLOBAL: 51 return "GLOBAL"; 52 case WASM_SEC_TAG: 53 return "TAG"; 54 case WASM_SEC_EXPORT: 55 return "EXPORT"; 56 case WASM_SEC_START: 57 return "START"; 58 case WASM_SEC_ELEM: 59 return "ELEM"; 60 case WASM_SEC_CODE: 61 return "CODE"; 62 case WASM_SEC_DATA: 63 return "DATA"; 64 case WASM_SEC_DATACOUNT: 65 return "DATACOUNT"; 66 default: 67 fatal("invalid section type"); 68 } 69 } 70 71 StringRef OutputSection::getSectionName() const { 72 return sectionTypeToString(type); 73 } 74 75 void OutputSection::createHeader(size_t bodySize) { 76 raw_string_ostream os(header); 77 debugWrite(os.tell(), "section type [" + getSectionName() + "]"); 78 encodeULEB128(type, os); 79 writeUleb128(os, bodySize, "section size"); 80 os.flush(); 81 log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) + 82 " total=" + Twine(getSize())); 83 } 84 85 void CodeSection::finalizeContents() { 86 raw_string_ostream os(codeSectionHeader); 87 writeUleb128(os, functions.size(), "function count"); 88 os.flush(); 89 bodySize = codeSectionHeader.size(); 90 91 for (InputFunction *func : functions) { 92 func->outputSec = this; 93 func->outSecOff = bodySize; 94 func->calculateSize(); 95 // All functions should have a non-empty body at this point 96 assert(func->getSize()); 97 bodySize += func->getSize(); 98 } 99 100 createHeader(bodySize); 101 } 102 103 void CodeSection::writeTo(uint8_t *buf) { 104 log("writing " + toString(*this)); 105 log(" size=" + Twine(getSize())); 106 log(" headersize=" + Twine(header.size())); 107 log(" codeheadersize=" + Twine(codeSectionHeader.size())); 108 buf += offset; 109 110 // Write section header 111 memcpy(buf, header.data(), header.size()); 112 buf += header.size(); 113 114 // Write code section headers 115 memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size()); 116 117 // Write code section bodies 118 for (const InputChunk *chunk : functions) 119 chunk->writeTo(buf); 120 } 121 122 uint32_t CodeSection::getNumRelocations() const { 123 uint32_t count = 0; 124 for (const InputChunk *func : functions) 125 count += func->getNumRelocations(); 126 return count; 127 } 128 129 void CodeSection::writeRelocations(raw_ostream &os) const { 130 for (const InputChunk *c : functions) 131 c->writeRelocations(os); 132 } 133 134 void DataSection::finalizeContents() { 135 raw_string_ostream os(dataSectionHeader); 136 unsigned segmentCount = 137 std::count_if(segments.begin(), segments.end(), 138 [](OutputSegment *segment) { return !segment->isBss; }); 139 140 #ifndef NDEBUG 141 unsigned activeCount = std::count_if( 142 segments.begin(), segments.end(), [](OutputSegment *segment) { 143 return (segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0; 144 }); 145 #endif 146 147 assert((config->sharedMemory || !config->isPic || activeCount <= 1) && 148 "output segments should have been combined by now"); 149 150 writeUleb128(os, segmentCount, "data segment count"); 151 os.flush(); 152 bodySize = dataSectionHeader.size(); 153 154 for (OutputSegment *segment : segments) { 155 if (segment->isBss) 156 continue; 157 raw_string_ostream os(segment->header); 158 writeUleb128(os, segment->initFlags, "init flags"); 159 if (segment->initFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX) 160 writeUleb128(os, 0, "memory index"); 161 if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) { 162 WasmInitExpr initExpr; 163 if (config->isPic) { 164 initExpr.Opcode = WASM_OPCODE_GLOBAL_GET; 165 initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex(); 166 } else { 167 initExpr = intConst(segment->startVA, config->is64.getValueOr(false)); 168 } 169 writeInitExpr(os, initExpr); 170 } 171 writeUleb128(os, segment->size, "segment size"); 172 os.flush(); 173 174 segment->sectionOffset = bodySize; 175 bodySize += segment->header.size() + segment->size; 176 log("Data segment: size=" + Twine(segment->size) + ", startVA=" + 177 Twine::utohexstr(segment->startVA) + ", name=" + segment->name); 178 179 for (InputChunk *inputSeg : segment->inputSegments) { 180 inputSeg->outputSec = this; 181 inputSeg->outSecOff = segment->sectionOffset + segment->header.size() + 182 inputSeg->outputSegmentOffset; 183 } 184 } 185 186 createHeader(bodySize); 187 } 188 189 void DataSection::writeTo(uint8_t *buf) { 190 log("writing " + toString(*this) + " size=" + Twine(getSize()) + 191 " body=" + Twine(bodySize)); 192 buf += offset; 193 194 // Write section header 195 memcpy(buf, header.data(), header.size()); 196 buf += header.size(); 197 198 // Write data section headers 199 memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size()); 200 201 for (const OutputSegment *segment : segments) { 202 if (segment->isBss) 203 continue; 204 // Write data segment header 205 uint8_t *segStart = buf + segment->sectionOffset; 206 memcpy(segStart, segment->header.data(), segment->header.size()); 207 208 // Write segment data payload 209 for (const InputChunk *chunk : segment->inputSegments) 210 chunk->writeTo(buf); 211 } 212 } 213 214 uint32_t DataSection::getNumRelocations() const { 215 uint32_t count = 0; 216 for (const OutputSegment *seg : segments) 217 for (const InputChunk *inputSeg : seg->inputSegments) 218 count += inputSeg->getNumRelocations(); 219 return count; 220 } 221 222 void DataSection::writeRelocations(raw_ostream &os) const { 223 for (const OutputSegment *seg : segments) 224 for (const InputChunk *c : seg->inputSegments) 225 c->writeRelocations(os); 226 } 227 228 bool DataSection::isNeeded() const { 229 for (const OutputSegment *seg : segments) 230 if (!seg->isBss) 231 return true; 232 return false; 233 } 234 235 // Lots of duplication here with OutputSegment::finalizeInputSegments 236 void CustomSection::finalizeInputSections() { 237 SyntheticMergedChunk *mergedSection = nullptr; 238 std::vector<InputChunk *> newSections; 239 240 for (InputChunk *s : inputSections) { 241 s->outputSec = this; 242 MergeInputChunk *ms = dyn_cast<MergeInputChunk>(s); 243 if (!ms) { 244 newSections.push_back(s); 245 continue; 246 } 247 248 if (!mergedSection) { 249 mergedSection = 250 make<SyntheticMergedChunk>(name, 0, WASM_SEG_FLAG_STRINGS); 251 newSections.push_back(mergedSection); 252 mergedSection->outputSec = this; 253 } 254 mergedSection->addMergeChunk(ms); 255 } 256 257 if (!mergedSection) 258 return; 259 260 mergedSection->finalizeContents(); 261 inputSections = newSections; 262 } 263 264 void CustomSection::finalizeContents() { 265 finalizeInputSections(); 266 267 raw_string_ostream os(nameData); 268 encodeULEB128(name.size(), os); 269 os << name; 270 os.flush(); 271 272 for (InputChunk *section : inputSections) { 273 assert(!section->discarded); 274 section->outSecOff = payloadSize; 275 payloadSize += section->getSize(); 276 } 277 278 createHeader(payloadSize + nameData.size()); 279 } 280 281 void CustomSection::writeTo(uint8_t *buf) { 282 log("writing " + toString(*this) + " size=" + Twine(getSize()) + 283 " chunks=" + Twine(inputSections.size())); 284 285 assert(offset); 286 buf += offset; 287 288 // Write section header 289 memcpy(buf, header.data(), header.size()); 290 buf += header.size(); 291 memcpy(buf, nameData.data(), nameData.size()); 292 buf += nameData.size(); 293 294 // Write custom sections payload 295 for (const InputChunk *section : inputSections) 296 section->writeTo(buf); 297 } 298 299 uint32_t CustomSection::getNumRelocations() const { 300 uint32_t count = 0; 301 for (const InputChunk *inputSect : inputSections) 302 count += inputSect->getNumRelocations(); 303 return count; 304 } 305 306 void CustomSection::writeRelocations(raw_ostream &os) const { 307 for (const InputChunk *s : inputSections) 308 s->writeRelocations(os); 309 } 310 311 } // namespace wasm 312 } // namespace lld 313