Path: blob/main/contrib/llvm-project/lld/MachO/BPSectionOrderer.cpp
213726 views
//===- BPSectionOrderer.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "BPSectionOrderer.h"9#include "InputSection.h"10#include "Relocations.h"11#include "Symbols.h"12#include "lld/Common/BPSectionOrdererBase.inc"13#include "llvm/ADT/DenseMap.h"14#include "llvm/ADT/StableHashing.h"15#include "llvm/Support/Endian.h"16#include "llvm/Support/xxhash.h"1718#define DEBUG_TYPE "bp-section-orderer"1920using namespace llvm;21using namespace lld::macho;2223namespace {24struct BPOrdererMachO;25}26template <> struct lld::BPOrdererTraits<struct BPOrdererMachO> {27using Section = macho::InputSection;28using Defined = macho::Defined;29};30namespace {31struct BPOrdererMachO : lld::BPOrderer<BPOrdererMachO> {32static uint64_t getSize(const Section &sec) { return sec.getSize(); }33static bool isCodeSection(const Section &sec) {34return macho::isCodeSection(&sec);35}36static ArrayRef<Defined *> getSymbols(const Section &sec) {37return sec.symbols;38}3940// Linkage names can be prefixed with "_" or "l_" on Mach-O. See41// Mangler::getNameWithPrefix() for details.42std::optional<StringRef> static getResolvedLinkageName(llvm::StringRef name) {43if (name.consume_front("_") || name.consume_front("l_"))44return name;45return {};46}4748static void49getSectionHashes(const Section &sec, llvm::SmallVectorImpl<uint64_t> &hashes,50const llvm::DenseMap<const void *, uint64_t> §ionToIdx) {51constexpr unsigned windowSize = 4;5253// Calculate content hashes: k-mers and the last k-1 bytes.54ArrayRef<uint8_t> data = sec.data;55if (data.size() >= windowSize)56for (size_t i = 0; i <= data.size() - windowSize; ++i)57hashes.push_back(llvm::support::endian::read32le(data.data() + i));58for (uint8_t byte : data.take_back(windowSize - 1))59hashes.push_back(byte);6061// Calculate relocation hashes62for (const auto &r : sec.relocs) {63if (r.length == 0 || r.referent.isNull() || r.offset >= data.size())64continue;6566uint64_t relocHash = getRelocHash(r, sectionToIdx);67uint32_t start = (r.offset < windowSize) ? 0 : r.offset - windowSize + 1;68for (uint32_t i = start; i < r.offset + r.length; i++) {69auto window = data.drop_front(i).take_front(windowSize);70hashes.push_back(xxh3_64bits(window) ^ relocHash);71}72}7374llvm::sort(hashes);75hashes.erase(llvm::unique(hashes), hashes.end());76}7778static llvm::StringRef getSymName(const Defined &sym) {79return sym.getName();80}81static uint64_t getSymValue(const Defined &sym) { return sym.value; }82static uint64_t getSymSize(const Defined &sym) { return sym.size; }8384private:85static uint64_t86getRelocHash(const macho::Reloc &reloc,87const llvm::DenseMap<const void *, uint64_t> §ionToIdx) {88auto *isec = reloc.getReferentInputSection();89std::optional<uint64_t> sectionIdx;90if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end())91sectionIdx = it->second;92uint64_t kind = -1, value = 0;93if (isec)94kind = uint64_t(isec->kind());9596if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) {97kind = (kind << 8) | uint8_t(sym->kind());98if (auto *d = llvm::dyn_cast<Defined>(sym))99value = d->value;100}101return llvm::stable_hash_combine(kind, sectionIdx.value_or(0), value,102reloc.addend);103}104};105} // namespace106107DenseMap<const InputSection *, int> lld::macho::runBalancedPartitioning(108StringRef profilePath, bool forFunctionCompression, bool forDataCompression,109bool compressionSortStartupFunctions, bool verbose) {110// Collect candidate sections and associated symbols.111SmallVector<InputSection *> sections;112DenseMap<CachedHashStringRef, std::set<unsigned>> rootSymbolToSectionIdxs;113for (const auto *file : inputFiles) {114for (auto *sec : file->sections) {115for (auto &subsec : sec->subsections) {116auto *isec = subsec.isec;117if (!isec || isec->data.empty() || !isec->data.data())118continue;119// ConcatInputSections are entirely live or dead, so the offset is120// irrelevant.121if (isa<ConcatInputSection>(isec) && !isec->isLive(0))122continue;123size_t idx = sections.size();124sections.emplace_back(isec);125for (auto *sym : BPOrdererMachO::getSymbols(*isec)) {126auto rootName = lld::utils::getRootSymbol(sym->getName());127rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx);128if (auto linkageName =129BPOrdererMachO::getResolvedLinkageName(rootName))130rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert(131idx);132}133}134}135}136137return BPOrdererMachO().computeOrder(profilePath, forFunctionCompression,138forDataCompression,139compressionSortStartupFunctions, verbose,140sections, rootSymbolToSectionIdxs);141}142143144