brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 8ccd38f Raw
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