1c94d393aSSam Clegg //===- OutputSections.cpp -------------------------------------------------===// 2c94d393aSSam Clegg // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c94d393aSSam Clegg // 7c94d393aSSam Clegg //===----------------------------------------------------------------------===// 8c94d393aSSam Clegg 9c94d393aSSam Clegg #include "OutputSections.h" 105fa274beSSam Clegg #include "InputChunks.h" 113a293cbfSWouter van Oortmerssen #include "InputElement.h" 12c94d393aSSam Clegg #include "InputFiles.h" 13c94d393aSSam Clegg #include "OutputSegment.h" 144a1b2bbcSRui Ueyama #include "WriterUtils.h" 15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h" 1645b7cf99SSam Clegg #include "lld/Common/Memory.h" 17c94d393aSSam Clegg #include "llvm/ADT/Twine.h" 1811842538SRui Ueyama #include "llvm/Support/LEB128.h" 19932f0276SReid Kleckner #include "llvm/Support/Parallel.h" 20c94d393aSSam Clegg 21c94d393aSSam Clegg #define DEBUG_TYPE "lld" 22c94d393aSSam Clegg 23c94d393aSSam Clegg using namespace llvm; 24c94d393aSSam Clegg using namespace llvm::wasm; 25c94d393aSSam Clegg 2633c59abfSFangrui Song namespace lld { 2733c59abfSFangrui Song 2833c59abfSFangrui Song // Returns a string, e.g. "FUNCTION(.text)". 2933c59abfSFangrui Song std::string toString(const wasm::OutputSection &sec) { 3033c59abfSFangrui Song if (!sec.name.empty()) 3133c59abfSFangrui Song return (sec.getSectionName() + "(" + sec.name + ")").str(); 32adcd0268SBenjamin Kramer return std::string(sec.getSectionName()); 3333c59abfSFangrui Song } 3433c59abfSFangrui Song 3533c59abfSFangrui Song namespace wasm { 3622c8f33aSRui Ueyama StringRef OutputSection::getSectionName() const { 37136d27abSRui Ueyama return sectionTypeToString(type); 380d0dd391SSam Clegg } 390d0dd391SSam Clegg 40136d27abSRui Ueyama void OutputSection::createHeader(size_t bodySize) { 41136d27abSRui Ueyama raw_string_ostream os(header); 42136d27abSRui Ueyama debugWrite(os.tell(), "section type [" + getSectionName() + "]"); 43136d27abSRui Ueyama encodeULEB128(type, os); 44136d27abSRui Ueyama writeUleb128(os, bodySize, "section size"); 45136d27abSRui Ueyama log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) + 46c94d393aSSam Clegg " total=" + Twine(getSize())); 47c94d393aSSam Clegg } 48c94d393aSSam Clegg 49d029bf0fSSam Clegg void CodeSection::finalizeContents() { 50136d27abSRui Ueyama raw_string_ostream os(codeSectionHeader); 51136d27abSRui Ueyama writeUleb128(os, functions.size(), "function count"); 52136d27abSRui Ueyama bodySize = codeSectionHeader.size(); 53c94d393aSSam Clegg 54136d27abSRui Ueyama for (InputFunction *func : functions) { 55cc2da555SSam Clegg func->outputSec = this; 5614ffbb84SSam Clegg func->outSecOff = bodySize; 57136d27abSRui Ueyama func->calculateSize(); 58701fa0b5SSam Clegg // All functions should have a non-empty body at this point 59701fa0b5SSam Clegg assert(func->getSize()); 60136d27abSRui Ueyama bodySize += func->getSize(); 61c94d393aSSam Clegg } 62c94d393aSSam Clegg 63136d27abSRui Ueyama createHeader(bodySize); 64c94d393aSSam Clegg } 65c94d393aSSam Clegg 66136d27abSRui Ueyama void CodeSection::writeTo(uint8_t *buf) { 673a7bcba3SSam Clegg log("writing " + toString(*this) + " offset=" + Twine(offset) + 683a7bcba3SSam Clegg " size=" + Twine(getSize())); 69136d27abSRui Ueyama log(" headersize=" + Twine(header.size())); 70136d27abSRui Ueyama log(" codeheadersize=" + Twine(codeSectionHeader.size())); 71136d27abSRui Ueyama buf += offset; 72c94d393aSSam Clegg 73c94d393aSSam Clegg // Write section header 74136d27abSRui Ueyama memcpy(buf, header.data(), header.size()); 75136d27abSRui Ueyama buf += header.size(); 76c94d393aSSam Clegg 77c94d393aSSam Clegg // Write code section headers 78136d27abSRui Ueyama memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size()); 79c94d393aSSam Clegg 80c94d393aSSam Clegg // Write code section bodies 81136d27abSRui Ueyama for (const InputChunk *chunk : functions) 82136d27abSRui Ueyama chunk->writeTo(buf); 83c94d393aSSam Clegg } 84c94d393aSSam Clegg 857e296adeSRui Ueyama uint32_t CodeSection::getNumRelocations() const { 86136d27abSRui Ueyama uint32_t count = 0; 87136d27abSRui Ueyama for (const InputChunk *func : functions) 88136d27abSRui Ueyama count += func->getNumRelocations(); 89136d27abSRui Ueyama return count; 90c94d393aSSam Clegg } 91c94d393aSSam Clegg 92136d27abSRui Ueyama void CodeSection::writeRelocations(raw_ostream &os) const { 93136d27abSRui Ueyama for (const InputChunk *c : functions) 94136d27abSRui Ueyama c->writeRelocations(os); 95c94d393aSSam Clegg } 96c94d393aSSam Clegg 97d029bf0fSSam Clegg void DataSection::finalizeContents() { 98136d27abSRui Ueyama raw_string_ostream os(dataSectionHeader); 993850edd9SKazu Hirata unsigned segmentCount = llvm::count_if(segments, [](OutputSegment *segment) { 1003850edd9SKazu Hirata return segment->requiredInBinary(); 1013850edd9SKazu Hirata }); 102a28a4662SSam Clegg #ifndef NDEBUG 1033850edd9SKazu Hirata unsigned activeCount = llvm::count_if(segments, [](OutputSegment *segment) { 104831a143eSAndy Wingo return (segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0; 105a28a4662SSam Clegg }); 106a28a4662SSam Clegg #endif 107a28a4662SSam Clegg 108*3792b362SFangrui Song assert((ctx.arg.sharedMemory || !ctx.isPic || ctx.arg.extendedConst || 1094690bf2eSSam Clegg activeCount <= 1) && 1108544b40bSSam Clegg "output segments should have been combined by now"); 111a28a4662SSam Clegg 112190dacc3SThomas Lively writeUleb128(os, segmentCount, "data segment count"); 113136d27abSRui Ueyama bodySize = dataSectionHeader.size(); 114*3792b362SFangrui Song bool is64 = ctx.arg.is64.value_or(false); 115c94d393aSSam Clegg 116136d27abSRui Ueyama for (OutputSegment *segment : segments) { 1171eb79e73SSam Clegg if (!segment->requiredInBinary()) 118190dacc3SThomas Lively continue; 119136d27abSRui Ueyama raw_string_ostream os(segment->header); 120136d27abSRui Ueyama writeUleb128(os, segment->initFlags, "init flags"); 121831a143eSAndy Wingo if (segment->initFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX) 122136d27abSRui Ueyama writeUleb128(os, 0, "memory index"); 123831a143eSAndy Wingo if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) { 124*3792b362SFangrui Song if (ctx.isPic && ctx.arg.extendedConst) { 1254690bf2eSSam Clegg writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get"); 1264690bf2eSSam Clegg writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), 1274690bf2eSSam Clegg "literal (global index)"); 1284690bf2eSSam Clegg if (segment->startVA) { 1294690bf2eSSam Clegg writePtrConst(os, segment->startVA, is64, "offset"); 1304690bf2eSSam Clegg writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "add"); 1314690bf2eSSam Clegg } 1324690bf2eSSam Clegg writeU8(os, WASM_OPCODE_END, "opcode:end"); 1334690bf2eSSam Clegg } else { 134136d27abSRui Ueyama WasmInitExpr initExpr; 1359504ab32SSam Clegg initExpr.Extended = false; 136184c22ddSSam Clegg if (ctx.isPic) { 1374690bf2eSSam Clegg assert(segment->startVA == 0); 1389504ab32SSam Clegg initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET; 1399504ab32SSam Clegg initExpr.Inst.Value.Global = WasmSym::memoryBase->getGlobalIndex(); 140bfb75348SSam Clegg } else { 1414690bf2eSSam Clegg initExpr = intConst(segment->startVA, is64); 142bfb75348SSam Clegg } 143136d27abSRui Ueyama writeInitExpr(os, initExpr); 1446004d9a1SThomas Lively } 1454690bf2eSSam Clegg } 146136d27abSRui Ueyama writeUleb128(os, segment->size, "segment size"); 147ac95bb1dSRui Ueyama 148136d27abSRui Ueyama segment->sectionOffset = bodySize; 149136d27abSRui Ueyama bodySize += segment->header.size() + segment->size; 150136d27abSRui Ueyama log("Data segment: size=" + Twine(segment->size) + ", startVA=" + 151136d27abSRui Ueyama Twine::utohexstr(segment->startVA) + ", name=" + segment->name); 152ac95bb1dSRui Ueyama 1535a9b25e1SSam Clegg for (InputChunk *inputSeg : segment->inputSegments) { 154cc2da555SSam Clegg inputSeg->outputSec = this; 15514ffbb84SSam Clegg inputSeg->outSecOff = segment->sectionOffset + segment->header.size() + 156136d27abSRui Ueyama inputSeg->outputSegmentOffset; 157c94d393aSSam Clegg } 158cc2da555SSam Clegg } 159c94d393aSSam Clegg 160136d27abSRui Ueyama createHeader(bodySize); 161c94d393aSSam Clegg } 162c94d393aSSam Clegg 163136d27abSRui Ueyama void DataSection::writeTo(uint8_t *buf) { 1643a7bcba3SSam Clegg log("writing " + toString(*this) + " offset=" + Twine(offset) + 1653a7bcba3SSam Clegg " size=" + Twine(getSize()) + " body=" + Twine(bodySize)); 166136d27abSRui Ueyama buf += offset; 167c94d393aSSam Clegg 168c94d393aSSam Clegg // Write section header 169136d27abSRui Ueyama memcpy(buf, header.data(), header.size()); 170136d27abSRui Ueyama buf += header.size(); 171c94d393aSSam Clegg 172c94d393aSSam Clegg // Write data section headers 173136d27abSRui Ueyama memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size()); 174c94d393aSSam Clegg 175136d27abSRui Ueyama for (const OutputSegment *segment : segments) { 1761eb79e73SSam Clegg if (!segment->requiredInBinary()) 177190dacc3SThomas Lively continue; 178c94d393aSSam Clegg // Write data segment header 179136d27abSRui Ueyama uint8_t *segStart = buf + segment->sectionOffset; 180136d27abSRui Ueyama memcpy(segStart, segment->header.data(), segment->header.size()); 181c94d393aSSam Clegg 182c94d393aSSam Clegg // Write segment data payload 183136d27abSRui Ueyama for (const InputChunk *chunk : segment->inputSegments) 184136d27abSRui Ueyama chunk->writeTo(buf); 1855081e41bSRui Ueyama } 1865e8cba9eSSam Clegg } 187c94d393aSSam Clegg 1887e296adeSRui Ueyama uint32_t DataSection::getNumRelocations() const { 189136d27abSRui Ueyama uint32_t count = 0; 190136d27abSRui Ueyama for (const OutputSegment *seg : segments) 191136d27abSRui Ueyama for (const InputChunk *inputSeg : seg->inputSegments) 192136d27abSRui Ueyama count += inputSeg->getNumRelocations(); 193136d27abSRui Ueyama return count; 194c94d393aSSam Clegg } 195c94d393aSSam Clegg 196136d27abSRui Ueyama void DataSection::writeRelocations(raw_ostream &os) const { 197136d27abSRui Ueyama for (const OutputSegment *seg : segments) 198136d27abSRui Ueyama for (const InputChunk *c : seg->inputSegments) 199136d27abSRui Ueyama c->writeRelocations(os); 200c94d393aSSam Clegg } 20180ba4387SSam Clegg 202190dacc3SThomas Lively bool DataSection::isNeeded() const { 203190dacc3SThomas Lively for (const OutputSegment *seg : segments) 2041eb79e73SSam Clegg if (seg->requiredInBinary()) 205190dacc3SThomas Lively return true; 206190dacc3SThomas Lively return false; 207190dacc3SThomas Lively } 208190dacc3SThomas Lively 20945b7cf99SSam Clegg // Lots of duplication here with OutputSegment::finalizeInputSegments 21045b7cf99SSam Clegg void CustomSection::finalizeInputSections() { 21145b7cf99SSam Clegg SyntheticMergedChunk *mergedSection = nullptr; 21245b7cf99SSam Clegg std::vector<InputChunk *> newSections; 21345b7cf99SSam Clegg 21445b7cf99SSam Clegg for (InputChunk *s : inputSections) { 215356b85edSSam Clegg s->outputSec = this; 21645b7cf99SSam Clegg MergeInputChunk *ms = dyn_cast<MergeInputChunk>(s); 21745b7cf99SSam Clegg if (!ms) { 21845b7cf99SSam Clegg newSections.push_back(s); 21945b7cf99SSam Clegg continue; 22045b7cf99SSam Clegg } 22145b7cf99SSam Clegg 22245b7cf99SSam Clegg if (!mergedSection) { 22345b7cf99SSam Clegg mergedSection = 22445b7cf99SSam Clegg make<SyntheticMergedChunk>(name, 0, WASM_SEG_FLAG_STRINGS); 22545b7cf99SSam Clegg newSections.push_back(mergedSection); 226356b85edSSam Clegg mergedSection->outputSec = this; 22745b7cf99SSam Clegg } 22845b7cf99SSam Clegg mergedSection->addMergeChunk(ms); 22945b7cf99SSam Clegg } 23045b7cf99SSam Clegg 23145b7cf99SSam Clegg if (!mergedSection) 23245b7cf99SSam Clegg return; 23345b7cf99SSam Clegg 23445b7cf99SSam Clegg mergedSection->finalizeContents(); 23545b7cf99SSam Clegg inputSections = newSections; 23645b7cf99SSam Clegg } 23745b7cf99SSam Clegg 238d029bf0fSSam Clegg void CustomSection::finalizeContents() { 23945b7cf99SSam Clegg finalizeInputSections(); 24045b7cf99SSam Clegg 241136d27abSRui Ueyama raw_string_ostream os(nameData); 242136d27abSRui Ueyama encodeULEB128(name.size(), os); 243136d27abSRui Ueyama os << name; 24480ba4387SSam Clegg 24545b7cf99SSam Clegg for (InputChunk *section : inputSections) { 246dd6412c0SDerek Schuff assert(!section->discarded); 247d4efc3e0SYuta Saito payloadSize = alignTo(payloadSize, section->alignment); 24814ffbb84SSam Clegg section->outSecOff = payloadSize; 249136d27abSRui Ueyama payloadSize += section->getSize(); 25080ba4387SSam Clegg } 25180ba4387SSam Clegg 252136d27abSRui Ueyama createHeader(payloadSize + nameData.size()); 25380ba4387SSam Clegg } 25480ba4387SSam Clegg 255136d27abSRui Ueyama void CustomSection::writeTo(uint8_t *buf) { 2563a7bcba3SSam Clegg log("writing " + toString(*this) + " offset=" + Twine(offset) + 2573a7bcba3SSam Clegg " size=" + Twine(getSize()) + " chunks=" + Twine(inputSections.size())); 25880ba4387SSam Clegg 259136d27abSRui Ueyama assert(offset); 260136d27abSRui Ueyama buf += offset; 26180ba4387SSam Clegg 26280ba4387SSam Clegg // Write section header 263136d27abSRui Ueyama memcpy(buf, header.data(), header.size()); 264136d27abSRui Ueyama buf += header.size(); 265136d27abSRui Ueyama memcpy(buf, nameData.data(), nameData.size()); 266136d27abSRui Ueyama buf += nameData.size(); 26780ba4387SSam Clegg 26880ba4387SSam Clegg // Write custom sections payload 26945b7cf99SSam Clegg for (const InputChunk *section : inputSections) 270136d27abSRui Ueyama section->writeTo(buf); 27180ba4387SSam Clegg } 272d177ab2aSSam Clegg 2737e296adeSRui Ueyama uint32_t CustomSection::getNumRelocations() const { 274136d27abSRui Ueyama uint32_t count = 0; 27545b7cf99SSam Clegg for (const InputChunk *inputSect : inputSections) 276136d27abSRui Ueyama count += inputSect->getNumRelocations(); 277136d27abSRui Ueyama return count; 278d177ab2aSSam Clegg } 279d177ab2aSSam Clegg 280136d27abSRui Ueyama void CustomSection::writeRelocations(raw_ostream &os) const { 28145b7cf99SSam Clegg for (const InputChunk *s : inputSections) 282136d27abSRui Ueyama s->writeRelocations(os); 283d177ab2aSSam Clegg } 28433c59abfSFangrui Song 28533c59abfSFangrui Song } // namespace wasm 28633c59abfSFangrui Song } // namespace lld 287