1 //===- OutputSegment.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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "OutputSegment.h" 10 #include "ConcatOutputSection.h" 11 #include "InputSection.h" 12 #include "Symbols.h" 13 #include "SyntheticSections.h" 14 15 #include "lld/Common/ErrorHandler.h" 16 #include "lld/Common/Memory.h" 17 #include "llvm/ADT/StringSwitch.h" 18 #include "llvm/BinaryFormat/MachO.h" 19 20 using namespace llvm; 21 using namespace llvm::MachO; 22 using namespace lld; 23 using namespace lld::macho; 24 25 static uint32_t initProt(StringRef name) { 26 auto it = find_if( 27 config->segmentProtections, 28 [&](const SegmentProtection &segprot) { return segprot.name == name; }); 29 if (it != config->segmentProtections.end()) 30 return it->initProt; 31 32 if (name == segment_names::text) 33 return VM_PROT_READ | VM_PROT_EXECUTE; 34 if (name == segment_names::pageZero) 35 return 0; 36 if (name == segment_names::linkEdit) 37 return VM_PROT_READ; 38 return VM_PROT_READ | VM_PROT_WRITE; 39 } 40 41 static uint32_t maxProt(StringRef name) { 42 assert(config->arch() != AK_i386 && 43 "TODO: i386 has different maxProt requirements"); 44 return initProt(name); 45 } 46 47 size_t OutputSegment::numNonHiddenSections() const { 48 size_t count = 0; 49 for (const OutputSection *osec : sections) 50 count += (!osec->isHidden() ? 1 : 0); 51 return count; 52 } 53 54 void OutputSegment::addOutputSection(OutputSection *osec) { 55 inputOrder = std::min(inputOrder, osec->inputOrder); 56 57 osec->parent = this; 58 sections.push_back(osec); 59 60 for (const SectionAlign §Align : config->sectionAlignments) 61 if (sectAlign.segName == name && sectAlign.sectName == osec->name) 62 osec->align = sectAlign.align; 63 } 64 65 template <typename T, typename F> static auto compareByOrder(F ord) { 66 return [=](T a, T b) { return ord(a) < ord(b); }; 67 } 68 69 static int segmentOrder(OutputSegment *seg) { 70 return StringSwitch<int>(seg->name) 71 .Case(segment_names::pageZero, -4) 72 .Case(segment_names::text, -3) 73 .Case(segment_names::dataConst, -2) 74 .Case(segment_names::data, -1) 75 .Case(segment_names::llvm, std::numeric_limits<int>::max() - 1) 76 // Make sure __LINKEDIT is the last segment (i.e. all its hidden 77 // sections must be ordered after other sections). 78 .Case(segment_names::linkEdit, std::numeric_limits<int>::max()) 79 .Default(seg->inputOrder); 80 } 81 82 static int sectionOrder(OutputSection *osec) { 83 StringRef segname = osec->parent->name; 84 // Sections are uniquely identified by their segment + section name. 85 if (segname == segment_names::text) { 86 return StringSwitch<int>(osec->name) 87 .Case(section_names::header, -4) 88 .Case(section_names::text, -3) 89 .Case(section_names::stubs, -2) 90 .Case(section_names::stubHelper, -1) 91 .Case(section_names::unwindInfo, std::numeric_limits<int>::max() - 1) 92 .Case(section_names::ehFrame, std::numeric_limits<int>::max()) 93 .Default(osec->inputOrder); 94 } else if (segname == segment_names::data || 95 segname == segment_names::dataConst) { 96 // For each thread spawned, dyld will initialize its TLVs by copying the 97 // address range from the start of the first thread-local data section to 98 // the end of the last one. We therefore arrange these sections contiguously 99 // to minimize the amount of memory used. Additionally, since zerofill 100 // sections must be at the end of their segments, and since TLV data 101 // sections can be zerofills, we end up putting all TLV data sections at the 102 // end of the segment. 103 switch (sectionType(osec->flags)) { 104 case S_THREAD_LOCAL_VARIABLE_POINTERS: 105 return std::numeric_limits<int>::max() - 3; 106 case S_THREAD_LOCAL_REGULAR: 107 return std::numeric_limits<int>::max() - 2; 108 case S_THREAD_LOCAL_ZEROFILL: 109 return std::numeric_limits<int>::max() - 1; 110 case S_ZEROFILL: 111 return std::numeric_limits<int>::max(); 112 default: 113 return StringSwitch<int>(osec->name) 114 .Case(section_names::got, -3) 115 .Case(section_names::lazySymbolPtr, -2) 116 .Case(section_names::const_, -1) 117 .Default(osec->inputOrder); 118 } 119 } else if (segname == segment_names::linkEdit) { 120 return StringSwitch<int>(osec->name) 121 .Case(section_names::rebase, -10) 122 .Case(section_names::binding, -9) 123 .Case(section_names::weakBinding, -8) 124 .Case(section_names::lazyBinding, -7) 125 .Case(section_names::export_, -6) 126 .Case(section_names::functionStarts, -5) 127 .Case(section_names::dataInCode, -4) 128 .Case(section_names::symbolTable, -3) 129 .Case(section_names::indirectSymbolTable, -2) 130 .Case(section_names::stringTable, -1) 131 .Case(section_names::codeSignature, std::numeric_limits<int>::max()) 132 .Default(osec->inputOrder); 133 } 134 // ZeroFill sections must always be the at the end of their segments: 135 // dyld checks if a segment's file size is smaller than its in-memory 136 // size to detect if a segment has zerofill sections, and if so it maps 137 // the missing tail as zerofill. 138 if (sectionType(osec->flags) == S_ZEROFILL) 139 return std::numeric_limits<int>::max(); 140 return osec->inputOrder; 141 } 142 143 void OutputSegment::sortOutputSections() { 144 // Must be stable_sort() to keep special sections such as 145 // S_THREAD_LOCAL_REGULAR in input order. 146 llvm::stable_sort(sections, compareByOrder<OutputSection *>(sectionOrder)); 147 } 148 149 void OutputSegment::assignAddressesToStartEndSymbols() { 150 for (Defined *d : segmentStartSymbols) 151 d->value = addr; 152 for (Defined *d : segmentEndSymbols) 153 d->value = addr + vmSize; 154 } 155 156 void macho::sortOutputSegments() { 157 llvm::stable_sort(outputSegments, 158 compareByOrder<OutputSegment *>(segmentOrder)); 159 } 160 161 static DenseMap<StringRef, OutputSegment *> nameToOutputSegment; 162 std::vector<OutputSegment *> macho::outputSegments; 163 164 void macho::resetOutputSegments() { 165 outputSegments.clear(); 166 nameToOutputSegment.clear(); 167 } 168 169 static StringRef maybeRenameSegment(StringRef name) { 170 auto newName = config->segmentRenameMap.find(name); 171 if (newName != config->segmentRenameMap.end()) 172 return newName->second; 173 return name; 174 } 175 176 OutputSegment *macho::getOrCreateOutputSegment(StringRef name) { 177 name = maybeRenameSegment(name); 178 179 OutputSegment *&segRef = nameToOutputSegment[name]; 180 if (segRef) 181 return segRef; 182 183 segRef = make<OutputSegment>(); 184 segRef->name = name; 185 segRef->maxProt = maxProt(name); 186 segRef->initProt = initProt(name); 187 188 outputSegments.push_back(segRef); 189 return segRef; 190 } 191