brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.8 KiB · 2b2d28e Raw
401 lines · cpp
1//===- InputSection.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 "InputSection.h"10#include "ConcatOutputSection.h"11#include "Config.h"12#include "InputFiles.h"13#include "OutputSegment.h"14#include "Sections.h"15#include "Symbols.h"16#include "SyntheticSections.h"17#include "Target.h"18#include "Writer.h"19 20#include "lld/Common/ErrorHandler.h"21#include "lld/Common/Memory.h"22#include "llvm/Support/xxhash.h"23 24using namespace llvm;25using namespace llvm::MachO;26using namespace llvm::support;27using namespace lld;28using namespace lld::macho;29 30// Verify ConcatInputSection's size on 64-bit builds. The size of std::vector31// can differ based on STL debug levels (e.g. iterator debugging on MSVC's STL),32// so account for that.33static_assert(sizeof(void *) != 8 ||34                  sizeof(ConcatInputSection) == sizeof(std::vector<Reloc>) + 88,35              "Try to minimize ConcatInputSection's size, we create many "36              "instances of it");37 38std::vector<ConcatInputSection *> macho::inputSections;39int macho::inputSectionsOrder = 0;40 41// Call this function to add a new InputSection and have it routed to the42// appropriate container. Depending on its type and current config, it will43// either be added to 'inputSections' vector or to a synthetic section.44void lld::macho::addInputSection(InputSection *inputSection) {45  if (auto *isec = dyn_cast<ConcatInputSection>(inputSection)) {46    if (isec->isCoalescedWeak())47      return;48    if (config->emitRelativeMethodLists &&49        ObjCMethListSection::isMethodList(isec)) {50      if (in.objcMethList->inputOrder == UnspecifiedInputOrder)51        in.objcMethList->inputOrder = inputSectionsOrder++;52      in.objcMethList->addInput(isec);53      isec->parent = in.objcMethList;54      return;55    }56    if (config->emitInitOffsets &&57        sectionType(isec->getFlags()) == S_MOD_INIT_FUNC_POINTERS) {58      in.initOffsets->addInput(isec);59      return;60    }61    isec->outSecOff = inputSectionsOrder++;62    auto *osec = ConcatOutputSection::getOrCreateForInput(isec);63    isec->parent = osec;64    inputSections.push_back(isec);65  } else if (auto *isec = dyn_cast<CStringInputSection>(inputSection)) {66    bool useSectionName = config->separateCstringLiteralSections ||67                          isec->getName() == section_names::objcMethname;68    auto *osec = in.getOrCreateCStringSection(69        useSectionName ? isec->getName() : section_names::cString);70    if (osec->inputOrder == UnspecifiedInputOrder)71      osec->inputOrder = inputSectionsOrder++;72    osec->addInput(isec);73  } else if (auto *isec = dyn_cast<WordLiteralInputSection>(inputSection)) {74    if (in.wordLiteralSection->inputOrder == UnspecifiedInputOrder)75      in.wordLiteralSection->inputOrder = inputSectionsOrder++;76    in.wordLiteralSection->addInput(isec);77  } else {78    llvm_unreachable("unexpected input section kind");79  }80 81  assert(inputSectionsOrder <= UnspecifiedInputOrder);82}83 84uint64_t InputSection::getFileSize() const {85  return isZeroFill(getFlags()) ? 0 : getSize();86}87 88uint64_t InputSection::getVA(uint64_t off) const {89  return parent->addr + getOffset(off);90}91 92static uint64_t resolveSymbolVA(const Symbol *sym, uint8_t type) {93  const RelocAttrs &relocAttrs = target->getRelocAttrs(type);94  if (relocAttrs.hasAttr(RelocAttrBits::BRANCH))95    return sym->resolveBranchVA();96  if (relocAttrs.hasAttr(RelocAttrBits::GOT))97    return sym->resolveGotVA();98  if (relocAttrs.hasAttr(RelocAttrBits::TLV))99    return sym->resolveTlvVA();100  return sym->getVA();101}102 103const Defined *InputSection::getContainingSymbol(uint64_t off) const {104  auto *nextSym = llvm::upper_bound(105      symbols, off, [](uint64_t a, const Defined *b) { return a < b->value; });106  if (nextSym == symbols.begin())107    return nullptr;108  return *std::prev(nextSym);109}110 111std::string InputSection::getLocation(uint64_t off) const {112  // First, try to find a symbol that's near the offset. Use it as a reference113  // point.114  if (auto *sym = getContainingSymbol(off))115    return (toString(getFile()) + ":(symbol " + toString(*sym) + "+0x" +116            Twine::utohexstr(off - sym->value) + ")")117        .str();118 119  // If that fails, use the section itself as a reference point.120  for (const Subsection &subsec : section.subsections) {121    if (subsec.isec == this) {122      off += subsec.offset;123      break;124    }125  }126 127  return (toString(getFile()) + ":(" + getName() + "+0x" +128          Twine::utohexstr(off) + ")")129      .str();130}131 132std::string InputSection::getSourceLocation(uint64_t off) const {133  auto *obj = dyn_cast_or_null<ObjFile>(getFile());134  if (!obj)135    return {};136 137  DWARFCache *dwarf = obj->getDwarf();138  if (!dwarf)139    return std::string();140 141  for (const Subsection &subsec : section.subsections) {142    if (subsec.isec == this) {143      off += subsec.offset;144      break;145    }146  }147 148  auto createMsg = [&](StringRef path, unsigned line) {149    std::string filename = sys::path::filename(path).str();150    std::string lineStr = (":" + Twine(line)).str();151    if (filename == path)152      return filename + lineStr;153    return (filename + lineStr + " (" + path + lineStr + ")").str();154  };155 156  // First, look up a function for a given offset.157  if (std::optional<DILineInfo> li = dwarf->getDILineInfo(158          section.addr + off, object::SectionedAddress::UndefSection))159    return createMsg(li->FileName, li->Line);160 161  // If it failed, look up again as a variable.162  if (const Defined *sym = getContainingSymbol(off)) {163    // Symbols are generally prefixed with an underscore, which is not included164    // in the debug information.165    StringRef symName = sym->getName();166    symName.consume_front("_");167 168    if (std::optional<std::pair<std::string, unsigned>> fileLine =169            dwarf->getVariableLoc(symName))170      return createMsg(fileLine->first, fileLine->second);171  }172 173  // Try to get the source file's name from the DWARF information.174  if (obj->compileUnit)175    return obj->sourceFile();176 177  return {};178}179 180const Reloc *InputSection::getRelocAt(uint32_t off) const {181  auto it = llvm::find_if(182      relocs, [=](const macho::Reloc &r) { return r.offset == off; });183  if (it == relocs.end())184    return nullptr;185  return &*it;186}187 188void ConcatInputSection::foldIdentical(ConcatInputSection *copy,189                                       Symbol::ICFFoldKind foldKind) {190  align = std::max(align, copy->align);191  copy->live = false;192  copy->wasCoalesced = true;193  copy->replacement = this;194  for (auto &copySym : copy->symbols)195    copySym->identicalCodeFoldingKind = foldKind;196 197  symbols.insert(symbols.end(), copy->symbols.begin(), copy->symbols.end());198  copy->symbols.clear();199 200  // Remove duplicate compact unwind info for symbols at the same address.201  if (symbols.empty())202    return;203  for (auto it = symbols.begin() + 1; it != symbols.end(); ++it) {204    assert((*it)->value == 0);205    (*it)->originalUnwindEntry = nullptr;206  }207}208 209void ConcatInputSection::writeTo(uint8_t *buf) {210  assert(!shouldOmitFromOutput());211 212  if (getFileSize() == 0)213    return;214 215  memcpy(buf, data.data(), data.size());216 217  for (size_t i = 0; i < relocs.size(); i++) {218    const Reloc &r = relocs[i];219    uint8_t *loc = buf + r.offset;220    uint64_t referentVA = 0;221 222    const bool needsFixup = config->emitChainedFixups &&223                            target->hasAttr(r.type, RelocAttrBits::UNSIGNED);224    if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) {225      const Symbol *fromSym = cast<Symbol *>(r.referent);226      const Reloc &minuend = relocs[++i];227      uint64_t minuendVA;228      if (const Symbol *toSym = minuend.referent.dyn_cast<Symbol *>())229        minuendVA = toSym->getVA() + minuend.addend;230      else {231        auto *referentIsec = cast<InputSection *>(minuend.referent);232        assert(!::shouldOmitFromOutput(referentIsec));233        minuendVA = referentIsec->getVA(minuend.addend);234      }235      referentVA = minuendVA - fromSym->getVA();236    } else if (auto *referentSym = r.referent.dyn_cast<Symbol *>()) {237      if (target->hasAttr(r.type, RelocAttrBits::LOAD) &&238          !referentSym->isInGot())239        target->relaxGotLoad(loc, r.type);240      // For dtrace symbols, do not handle them as normal undefined symbols241      if (referentSym->getName().starts_with("___dtrace_")) {242        // Change dtrace call site to pre-defined instructions243        target->handleDtraceReloc(referentSym, r, loc);244        continue;245      }246      referentVA = resolveSymbolVA(referentSym, r.type) + r.addend;247 248      if (isThreadLocalVariables(getFlags()) && isa<Defined>(referentSym)) {249        // References from thread-local variable sections are treated as offsets250        // relative to the start of the thread-local data memory area, which251        // is initialized via copying all the TLV data sections (which are all252        // contiguous).253        referentVA -= firstTLVDataSection->addr;254      } else if (needsFixup) {255        writeChainedFixup(loc, referentSym, r.addend);256        continue;257      }258    } else if (auto *referentIsec = r.referent.dyn_cast<InputSection *>()) {259      assert(!::shouldOmitFromOutput(referentIsec));260      referentVA = referentIsec->getVA(r.addend);261 262      if (needsFixup) {263        writeChainedRebase(loc, referentVA);264        continue;265      }266    }267    target->relocateOne(loc, r, referentVA, getVA() + r.offset);268  }269}270 271ConcatInputSection *macho::makeSyntheticInputSection(StringRef segName,272                                                     StringRef sectName,273                                                     uint32_t flags,274                                                     ArrayRef<uint8_t> data,275                                                     uint32_t align) {276  Section &section =277      *make<Section>(/*file=*/nullptr, segName, sectName, flags, /*addr=*/0);278  auto isec = make<ConcatInputSection>(section, data, align);279  // Since this is an explicitly created 'fake' input section,280  // it should not be dead stripped.281  isec->live = true;282  section.subsections.push_back({0, isec});283  return isec;284}285 286void CStringInputSection::splitIntoPieces() {287  size_t off = 0;288  StringRef s = toStringRef(data);289  while (!s.empty()) {290    size_t end = s.find(0);291    if (end == StringRef::npos)292      fatal(getLocation(off) + ": string is not null terminated");293    uint32_t hash = deduplicateLiterals ? xxh3_64bits(s.take_front(end)) : 0;294    pieces.emplace_back(off, hash);295    size_t size = end + 1; // include null terminator296    s = s.substr(size);297    off += size;298  }299}300 301StringPiece &CStringInputSection::getStringPiece(uint64_t off) {302  if (off >= data.size())303    fatal(toString(this) + ": offset is outside the section");304 305  auto it =306      partition_point(pieces, [=](StringPiece p) { return p.inSecOff <= off; });307  return it[-1];308}309 310const StringPiece &CStringInputSection::getStringPiece(uint64_t off) const {311  return const_cast<CStringInputSection *>(this)->getStringPiece(off);312}313 314size_t CStringInputSection::getStringPieceIndex(uint64_t off) const {315  if (off >= data.size())316    fatal(toString(this) + ": offset is outside the section");317 318  auto it =319      partition_point(pieces, [=](StringPiece p) { return p.inSecOff <= off; });320  return std::distance(pieces.begin(), it) - 1;321}322 323uint64_t CStringInputSection::getOffset(uint64_t off) const {324  const StringPiece &piece = getStringPiece(off);325  uint64_t addend = off - piece.inSecOff;326  return piece.outSecOff + addend;327}328 329WordLiteralInputSection::WordLiteralInputSection(const Section &section,330                                                 ArrayRef<uint8_t> data,331                                                 uint32_t align)332    : InputSection(WordLiteralKind, section, data, align) {333  switch (sectionType(getFlags())) {334  case S_4BYTE_LITERALS:335    power2LiteralSize = 2;336    break;337  case S_8BYTE_LITERALS:338    power2LiteralSize = 3;339    break;340  case S_16BYTE_LITERALS:341    power2LiteralSize = 4;342    break;343  default:344    llvm_unreachable("invalid literal section type");345  }346 347  live.resize(data.size() >> power2LiteralSize, !config->deadStrip);348}349 350uint64_t WordLiteralInputSection::getOffset(uint64_t off) const {351  if (off >= data.size())352    fatal(toString(this) + ": offset is outside the section");353 354  auto *osec = cast<WordLiteralSection>(parent);355  const uintptr_t buf = reinterpret_cast<uintptr_t>(data.data());356  switch (sectionType(getFlags())) {357  case S_4BYTE_LITERALS:358    return osec->getLiteral4Offset(buf + (off & ~3LLU)) | (off & 3);359  case S_8BYTE_LITERALS:360    return osec->getLiteral8Offset(buf + (off & ~7LLU)) | (off & 7);361  case S_16BYTE_LITERALS:362    return osec->getLiteral16Offset(buf + (off & ~15LLU)) | (off & 15);363  default:364    llvm_unreachable("invalid literal section type");365  }366}367 368bool macho::isCodeSection(const InputSection *isec) {369  return sections::isCodeSection(isec->getName(), isec->getSegName(),370                                 isec->getFlags());371}372 373bool macho::isCfStringSection(const InputSection *isec) {374  return isec->getName() == section_names::cfString &&375         isec->getSegName() == segment_names::data;376}377 378bool macho::isClassRefsSection(const InputSection *isec) {379  return isec->getName() == section_names::objcClassRefs &&380         isec->getSegName() == segment_names::data;381}382 383bool macho::isSelRefsSection(const InputSection *isec) {384  return isec->getName() == section_names::objcSelrefs &&385         isec->getSegName() == segment_names::data;386}387 388bool macho::isEhFrameSection(const InputSection *isec) {389  return isec->getName() == section_names::ehFrame &&390         isec->getSegName() == segment_names::text;391}392 393bool macho::isGccExceptTabSection(const InputSection *isec) {394  return isec->getName() == section_names::gccExceptTab &&395         isec->getSegName() == segment_names::text;396}397 398std::string lld::toString(const InputSection *isec) {399  return (toString(isec->getFile()) + ":(" + isec->getName() + ")").str();400}401