287 lines · cpp
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-exception6//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 20#define DEBUG_TYPE "lld"21 22using namespace llvm;23using namespace llvm::wasm;24 25namespace lld {26 27// Returns a string, e.g. "FUNCTION(.text)".28std::string toString(const wasm::OutputSection &sec) {29 if (!sec.name.empty())30 return (sec.getSectionName() + "(" + sec.name + ")").str();31 return std::string(sec.getSectionName());32}33 34namespace wasm {35StringRef OutputSection::getSectionName() const {36 return sectionTypeToString(type);37}38 39void OutputSection::createHeader(size_t bodySize) {40 raw_string_ostream os(header);41 debugWrite(os.tell(), "section type [" + getSectionName() + "]");42 encodeULEB128(type, os);43 writeUleb128(os, bodySize, "section size");44 log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) +45 " total=" + Twine(getSize()));46}47 48void CodeSection::finalizeContents() {49 raw_string_ostream os(codeSectionHeader);50 writeUleb128(os, functions.size(), "function count");51 bodySize = codeSectionHeader.size();52 53 for (InputFunction *func : functions) {54 func->outputSec = this;55 func->outSecOff = bodySize;56 func->calculateSize();57 // All functions should have a non-empty body at this point58 assert(func->getSize());59 bodySize += func->getSize();60 }61 62 createHeader(bodySize);63}64 65void CodeSection::writeTo(uint8_t *buf) {66 log("writing " + toString(*this) + " offset=" + Twine(offset) +67 " size=" + Twine(getSize()));68 log(" headersize=" + Twine(header.size()));69 log(" codeheadersize=" + Twine(codeSectionHeader.size()));70 buf += offset;71 72 // Write section header73 memcpy(buf, header.data(), header.size());74 buf += header.size();75 76 // Write code section headers77 memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size());78 79 // Write code section bodies80 for (const InputChunk *chunk : functions)81 chunk->writeTo(buf);82}83 84uint32_t CodeSection::getNumRelocations() const {85 uint32_t count = 0;86 for (const InputChunk *func : functions)87 count += func->getNumRelocations();88 return count;89}90 91void CodeSection::writeRelocations(raw_ostream &os) const {92 for (const InputChunk *c : functions)93 c->writeRelocations(os);94}95 96void DataSection::finalizeContents() {97 raw_string_ostream os(dataSectionHeader);98 unsigned segmentCount = llvm::count_if(segments, [](OutputSegment *segment) {99 return segment->requiredInBinary();100 });101#ifndef NDEBUG102 unsigned activeCount = llvm::count_if(segments, [](OutputSegment *segment) {103 return segment->requiredInBinary() &&104 (segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0;105 });106#endif107 108 assert((ctx.arg.sharedMemory || !ctx.isPic || ctx.arg.extendedConst ||109 activeCount <= 1) &&110 "output segments should have been combined by now");111 112 writeUleb128(os, segmentCount, "data segment count");113 bodySize = dataSectionHeader.size();114 bool is64 = ctx.arg.is64.value_or(false);115 116 for (OutputSegment *segment : segments) {117 if (!segment->requiredInBinary())118 continue;119 raw_string_ostream os(segment->header);120 writeUleb128(os, segment->initFlags, "init flags");121 if (segment->initFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX)122 writeUleb128(os, 0, "memory index");123 if ((segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {124 if (ctx.isPic && ctx.arg.extendedConst) {125 writeU8(os, WASM_OPCODE_GLOBAL_GET, "global get");126 writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(),127 "literal (global index)");128 if (segment->startVA) {129 writePtrConst(os, segment->startVA, is64, "offset");130 writeU8(os, is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, "add");131 }132 writeU8(os, WASM_OPCODE_END, "opcode:end");133 } else {134 WasmInitExpr initExpr;135 initExpr.Extended = false;136 if (ctx.isPic) {137 assert(segment->startVA == 0);138 initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET;139 initExpr.Inst.Value.Global = ctx.sym.memoryBase->getGlobalIndex();140 } else {141 initExpr = intConst(segment->startVA, is64);142 }143 writeInitExpr(os, initExpr);144 }145 }146 writeUleb128(os, segment->size, "segment size");147 148 segment->sectionOffset = bodySize;149 bodySize += segment->header.size() + segment->size;150 log("Data segment: size=" + Twine(segment->size) + ", startVA=" +151 Twine::utohexstr(segment->startVA) + ", name=" + segment->name);152 153 for (InputChunk *inputSeg : segment->inputSegments) {154 inputSeg->outputSec = this;155 inputSeg->outSecOff = segment->sectionOffset + segment->header.size() +156 inputSeg->outputSegmentOffset;157 }158 }159 160 createHeader(bodySize);161}162 163void DataSection::writeTo(uint8_t *buf) {164 log("writing " + toString(*this) + " offset=" + Twine(offset) +165 " size=" + Twine(getSize()) + " body=" + Twine(bodySize));166 buf += offset;167 168 // Write section header169 memcpy(buf, header.data(), header.size());170 buf += header.size();171 172 // Write data section headers173 memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size());174 175 for (const OutputSegment *segment : segments) {176 if (!segment->requiredInBinary())177 continue;178 // Write data segment header179 uint8_t *segStart = buf + segment->sectionOffset;180 memcpy(segStart, segment->header.data(), segment->header.size());181 182 // Write segment data payload183 for (const InputChunk *chunk : segment->inputSegments)184 chunk->writeTo(buf);185 }186}187 188uint32_t DataSection::getNumRelocations() const {189 uint32_t count = 0;190 for (const OutputSegment *seg : segments)191 for (const InputChunk *inputSeg : seg->inputSegments)192 count += inputSeg->getNumRelocations();193 return count;194}195 196void 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 202bool DataSection::isNeeded() const {203 for (const OutputSegment *seg : segments)204 if (seg->requiredInBinary())205 return true;206 return false;207}208 209// Lots of duplication here with OutputSegment::finalizeInputSegments210void CustomSection::finalizeInputSections() {211 SyntheticMergedChunk *mergedSection = nullptr;212 std::vector<InputChunk *> newSections;213 214 for (InputChunk *s : inputSections) {215 s->outputSec = this;216 MergeInputChunk *ms = dyn_cast<MergeInputChunk>(s);217 if (!ms) {218 newSections.push_back(s);219 continue;220 }221 222 if (!mergedSection) {223 mergedSection =224 make<SyntheticMergedChunk>(name, 0, WASM_SEG_FLAG_STRINGS);225 newSections.push_back(mergedSection);226 mergedSection->outputSec = this;227 }228 mergedSection->addMergeChunk(ms);229 }230 231 if (!mergedSection)232 return;233 234 mergedSection->finalizeContents();235 inputSections = newSections;236}237 238void CustomSection::finalizeContents() {239 finalizeInputSections();240 241 raw_string_ostream os(nameData);242 encodeULEB128(name.size(), os);243 os << name;244 245 for (InputChunk *section : inputSections) {246 assert(!section->discarded);247 payloadSize = alignTo(payloadSize, section->alignment);248 section->outSecOff = payloadSize;249 payloadSize += section->getSize();250 }251 252 createHeader(payloadSize + nameData.size());253}254 255void CustomSection::writeTo(uint8_t *buf) {256 log("writing " + toString(*this) + " offset=" + Twine(offset) +257 " size=" + Twine(getSize()) + " chunks=" + Twine(inputSections.size()));258 259 assert(offset);260 buf += offset;261 262 // Write section header263 memcpy(buf, header.data(), header.size());264 buf += header.size();265 memcpy(buf, nameData.data(), nameData.size());266 buf += nameData.size();267 268 // Write custom sections payload269 for (const InputChunk *section : inputSections)270 section->writeTo(buf);271}272 273uint32_t CustomSection::getNumRelocations() const {274 uint32_t count = 0;275 for (const InputChunk *inputSect : inputSections)276 count += inputSect->getNumLiveRelocations();277 return count;278}279 280void CustomSection::writeRelocations(raw_ostream &os) const {281 for (const InputChunk *s : inputSections)282 s->writeRelocations(os);283}284 285} // namespace wasm286} // namespace lld287