Path: blob/main/contrib/llvm-project/lld/MachO/OutputSegment.cpp
34878 views
//===- OutputSegment.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 "OutputSegment.h"9#include "ConcatOutputSection.h"10#include "InputSection.h"11#include "Symbols.h"12#include "SyntheticSections.h"1314#include "lld/Common/ErrorHandler.h"15#include "lld/Common/Memory.h"16#include "llvm/ADT/StringSwitch.h"17#include "llvm/BinaryFormat/MachO.h"1819using namespace llvm;20using namespace llvm::MachO;21using namespace lld;22using namespace lld::macho;2324static uint32_t initProt(StringRef name) {25auto it = find_if(26config->segmentProtections,27[&](const SegmentProtection &segprot) { return segprot.name == name; });28if (it != config->segmentProtections.end())29return it->initProt;3031if (name == segment_names::text)32return VM_PROT_READ | VM_PROT_EXECUTE;33if (name == segment_names::pageZero)34return 0;35if (name == segment_names::linkEdit)36return VM_PROT_READ;37return VM_PROT_READ | VM_PROT_WRITE;38}3940static uint32_t maxProt(StringRef name) {41assert(config->arch() != AK_i386 &&42"TODO: i386 has different maxProt requirements");43return initProt(name);44}4546static uint32_t flags(StringRef name) {47// If we ever implement shared cache output support, SG_READ_ONLY should not48// be used for dylibs that can be placed in it.49return name == segment_names::dataConst ? (uint32_t)SG_READ_ONLY : 0;50}5152size_t OutputSegment::numNonHiddenSections() const {53size_t count = 0;54for (const OutputSection *osec : sections)55count += (!osec->isHidden() ? 1 : 0);56return count;57}5859void OutputSegment::addOutputSection(OutputSection *osec) {60inputOrder = std::min(inputOrder, osec->inputOrder);6162osec->parent = this;63sections.push_back(osec);6465for (const SectionAlign §Align : config->sectionAlignments)66if (sectAlign.segName == name && sectAlign.sectName == osec->name)67osec->align = sectAlign.align;68}6970template <typename T, typename F> static auto compareByOrder(F ord) {71return [=](T a, T b) { return ord(a) < ord(b); };72}7374static int segmentOrder(OutputSegment *seg) {75return StringSwitch<int>(seg->name)76.Case(segment_names::pageZero, -4)77.Case(segment_names::text, -3)78.Case(segment_names::dataConst, -2)79.Case(segment_names::data, -1)80.Case(segment_names::llvm, std::numeric_limits<int>::max() - 1)81// Make sure __LINKEDIT is the last segment (i.e. all its hidden82// sections must be ordered after other sections).83.Case(segment_names::linkEdit, std::numeric_limits<int>::max())84.Default(seg->inputOrder);85}8687static int sectionOrder(OutputSection *osec) {88StringRef segname = osec->parent->name;89// Sections are uniquely identified by their segment + section name.90if (segname == segment_names::text) {91return StringSwitch<int>(osec->name)92.Case(section_names::header, -6)93.Case(section_names::text, -5)94.Case(section_names::stubs, -4)95.Case(section_names::stubHelper, -3)96.Case(section_names::objcStubs, -2)97.Case(section_names::initOffsets, -1)98.Case(section_names::unwindInfo, std::numeric_limits<int>::max() - 1)99.Case(section_names::ehFrame, std::numeric_limits<int>::max())100.Default(osec->inputOrder);101} else if (segname == segment_names::data ||102segname == segment_names::dataConst) {103// For each thread spawned, dyld will initialize its TLVs by copying the104// address range from the start of the first thread-local data section to105// the end of the last one. We therefore arrange these sections contiguously106// to minimize the amount of memory used. Additionally, since zerofill107// sections must be at the end of their segments, and since TLV data108// sections can be zerofills, we end up putting all TLV data sections at the109// end of the segment.110switch (sectionType(osec->flags)) {111case S_THREAD_LOCAL_VARIABLE_POINTERS:112return std::numeric_limits<int>::max() - 3;113case S_THREAD_LOCAL_REGULAR:114return std::numeric_limits<int>::max() - 2;115case S_THREAD_LOCAL_ZEROFILL:116return std::numeric_limits<int>::max() - 1;117case S_ZEROFILL:118return std::numeric_limits<int>::max();119default:120return StringSwitch<int>(osec->name)121.Case(section_names::got, -3)122.Case(section_names::lazySymbolPtr, -2)123.Case(section_names::const_, -1)124.Default(osec->inputOrder);125}126} else if (segname == segment_names::linkEdit) {127return StringSwitch<int>(osec->name)128.Case(section_names::chainFixups, -11)129.Case(section_names::rebase, -10)130.Case(section_names::binding, -9)131.Case(section_names::weakBinding, -8)132.Case(section_names::lazyBinding, -7)133.Case(section_names::export_, -6)134.Case(section_names::functionStarts, -5)135.Case(section_names::dataInCode, -4)136.Case(section_names::symbolTable, -3)137.Case(section_names::indirectSymbolTable, -2)138.Case(section_names::stringTable, -1)139.Case(section_names::codeSignature, std::numeric_limits<int>::max())140.Default(osec->inputOrder);141}142// ZeroFill sections must always be the at the end of their segments:143// dyld checks if a segment's file size is smaller than its in-memory144// size to detect if a segment has zerofill sections, and if so it maps145// the missing tail as zerofill.146if (sectionType(osec->flags) == S_ZEROFILL)147return std::numeric_limits<int>::max();148return osec->inputOrder;149}150151void OutputSegment::sortOutputSections() {152// Must be stable_sort() to keep special sections such as153// S_THREAD_LOCAL_REGULAR in input order.154llvm::stable_sort(sections, compareByOrder<OutputSection *>(sectionOrder));155}156157void OutputSegment::assignAddressesToStartEndSymbols() {158for (Defined *d : segmentStartSymbols)159d->value = addr;160for (Defined *d : segmentEndSymbols)161d->value = addr + vmSize;162}163164void macho::sortOutputSegments() {165llvm::stable_sort(outputSegments,166compareByOrder<OutputSegment *>(segmentOrder));167}168169static DenseMap<StringRef, OutputSegment *> nameToOutputSegment;170std::vector<OutputSegment *> macho::outputSegments;171172void macho::resetOutputSegments() {173outputSegments.clear();174nameToOutputSegment.clear();175}176177static StringRef maybeRenameSegment(StringRef name) {178auto newName = config->segmentRenameMap.find(name);179if (newName != config->segmentRenameMap.end())180return newName->second;181return name;182}183184OutputSegment *macho::getOrCreateOutputSegment(StringRef name) {185name = maybeRenameSegment(name);186187OutputSegment *&segRef = nameToOutputSegment[name];188if (segRef)189return segRef;190191segRef = make<OutputSegment>();192segRef->name = name;193segRef->maxProt = maxProt(name);194segRef->initProt = initProt(name);195segRef->flags = flags(name);196197outputSegments.push_back(segRef);198return segRef;199}200201202