16acd3003SFangrui Song //===- OutputSegment.cpp --------------------------------------------------===//
26acd3003SFangrui Song //
36acd3003SFangrui Song // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46acd3003SFangrui Song // See https://llvm.org/LICENSE.txt for license information.
56acd3003SFangrui Song // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66acd3003SFangrui Song //
76acd3003SFangrui Song //===----------------------------------------------------------------------===//
86acd3003SFangrui Song 
96acd3003SFangrui Song #include "OutputSegment.h"
1033706191SJez Ng #include "ConcatOutputSection.h"
116f63216cSJez Ng #include "InputSection.h"
1280caa1ebSNico Weber #include "Symbols.h"
136cb07313SKellie Medlin #include "SyntheticSections.h"
146f63216cSJez Ng 
156cb07313SKellie Medlin #include "lld/Common/ErrorHandler.h"
166acd3003SFangrui Song #include "lld/Common/Memory.h"
177599e98aSJez Ng #include "llvm/ADT/StringSwitch.h"
186f63216cSJez Ng #include "llvm/BinaryFormat/MachO.h"
196acd3003SFangrui Song 
206acd3003SFangrui Song using namespace llvm;
216f63216cSJez Ng using namespace llvm::MachO;
226acd3003SFangrui Song using namespace lld;
236acd3003SFangrui Song using namespace lld::macho;
246acd3003SFangrui Song 
initProt(StringRef name)256f63216cSJez Ng static uint32_t initProt(StringRef name) {
26a43f588eSJez Ng   auto it = find_if(
27a43f588eSJez Ng       config->segmentProtections,
28a43f588eSJez Ng       [&](const SegmentProtection &segprot) { return segprot.name == name; });
29a43f588eSJez Ng   if (it != config->segmentProtections.end())
30a43f588eSJez Ng     return it->initProt;
31a43f588eSJez Ng 
326f63216cSJez Ng   if (name == segment_names::text)
336f63216cSJez Ng     return VM_PROT_READ | VM_PROT_EXECUTE;
346f63216cSJez Ng   if (name == segment_names::pageZero)
356f63216cSJez Ng     return 0;
366f63216cSJez Ng   if (name == segment_names::linkEdit)
376f63216cSJez Ng     return VM_PROT_READ;
386f63216cSJez Ng   return VM_PROT_READ | VM_PROT_WRITE;
396f63216cSJez Ng }
406f63216cSJez Ng 
maxProt(StringRef name)416f63216cSJez Ng static uint32_t maxProt(StringRef name) {
42ed4a4e33SJez Ng   assert(config->arch() != AK_i386 &&
436cf24432SJez Ng          "TODO: i386 has different maxProt requirements");
446cf24432SJez Ng   return initProt(name);
456f63216cSJez Ng }
466f63216cSJez Ng 
numNonHiddenSections() const476cb07313SKellie Medlin size_t OutputSegment::numNonHiddenSections() const {
486cb07313SKellie Medlin   size_t count = 0;
49a1705336SGreg McGary   for (const OutputSection *osec : sections)
503646ee50SJez Ng     count += (!osec->isHidden() ? 1 : 0);
516cb07313SKellie Medlin   return count;
526cb07313SKellie Medlin }
536cb07313SKellie Medlin 
addOutputSection(OutputSection * osec)543646ee50SJez Ng void OutputSegment::addOutputSection(OutputSection *osec) {
55fcab06bdSJez Ng   inputOrder = std::min(inputOrder, osec->inputOrder);
56fcab06bdSJez Ng 
573646ee50SJez Ng   osec->parent = this;
583646ee50SJez Ng   sections.push_back(osec);
599ab49ae5SNico Weber 
609ab49ae5SNico Weber   for (const SectionAlign &sectAlign : config->sectionAlignments)
619ab49ae5SNico Weber     if (sectAlign.segName == name && sectAlign.sectName == osec->name)
629ab49ae5SNico Weber       osec->align = sectAlign.align;
636f63216cSJez Ng }
646f63216cSJez Ng 
compareByOrder(F ord)657599e98aSJez Ng template <typename T, typename F> static auto compareByOrder(F ord) {
667599e98aSJez Ng   return [=](T a, T b) { return ord(a) < ord(b); };
677599e98aSJez Ng }
687599e98aSJez Ng 
segmentOrder(OutputSegment * seg)697599e98aSJez Ng static int segmentOrder(OutputSegment *seg) {
707599e98aSJez Ng   return StringSwitch<int>(seg->name)
717599e98aSJez Ng       .Case(segment_names::pageZero, -4)
727599e98aSJez Ng       .Case(segment_names::text, -3)
737599e98aSJez Ng       .Case(segment_names::dataConst, -2)
747599e98aSJez Ng       .Case(segment_names::data, -1)
757599e98aSJez Ng       .Case(segment_names::llvm, std::numeric_limits<int>::max() - 1)
767599e98aSJez Ng       // Make sure __LINKEDIT is the last segment (i.e. all its hidden
777599e98aSJez Ng       // sections must be ordered after other sections).
787599e98aSJez Ng       .Case(segment_names::linkEdit, std::numeric_limits<int>::max())
797599e98aSJez Ng       .Default(seg->inputOrder);
807599e98aSJez Ng }
817599e98aSJez Ng 
sectionOrder(OutputSection * osec)827599e98aSJez Ng static int sectionOrder(OutputSection *osec) {
837599e98aSJez Ng   StringRef segname = osec->parent->name;
847599e98aSJez Ng   // Sections are uniquely identified by their segment + section name.
857599e98aSJez Ng   if (segname == segment_names::text) {
867599e98aSJez Ng     return StringSwitch<int>(osec->name)
877599e98aSJez Ng         .Case(section_names::header, -4)
887599e98aSJez Ng         .Case(section_names::text, -3)
897599e98aSJez Ng         .Case(section_names::stubs, -2)
907599e98aSJez Ng         .Case(section_names::stubHelper, -1)
917599e98aSJez Ng         .Case(section_names::unwindInfo, std::numeric_limits<int>::max() - 1)
927599e98aSJez Ng         .Case(section_names::ehFrame, std::numeric_limits<int>::max())
937599e98aSJez Ng         .Default(osec->inputOrder);
947599e98aSJez Ng   } else if (segname == segment_names::data ||
957599e98aSJez Ng              segname == segment_names::dataConst) {
967599e98aSJez Ng     // For each thread spawned, dyld will initialize its TLVs by copying the
977599e98aSJez Ng     // address range from the start of the first thread-local data section to
987599e98aSJez Ng     // the end of the last one. We therefore arrange these sections contiguously
997599e98aSJez Ng     // to minimize the amount of memory used. Additionally, since zerofill
1007599e98aSJez Ng     // sections must be at the end of their segments, and since TLV data
1017599e98aSJez Ng     // sections can be zerofills, we end up putting all TLV data sections at the
1027599e98aSJez Ng     // end of the segment.
1037599e98aSJez Ng     switch (sectionType(osec->flags)) {
104c931e12bSNico Weber     case S_THREAD_LOCAL_VARIABLE_POINTERS:
105c931e12bSNico Weber       return std::numeric_limits<int>::max() - 3;
1067599e98aSJez Ng     case S_THREAD_LOCAL_REGULAR:
1077599e98aSJez Ng       return std::numeric_limits<int>::max() - 2;
1087599e98aSJez Ng     case S_THREAD_LOCAL_ZEROFILL:
1097599e98aSJez Ng       return std::numeric_limits<int>::max() - 1;
1107599e98aSJez Ng     case S_ZEROFILL:
1117599e98aSJez Ng       return std::numeric_limits<int>::max();
1127599e98aSJez Ng     default:
1137599e98aSJez Ng       return StringSwitch<int>(osec->name)
1147599e98aSJez Ng           .Case(section_names::got, -3)
1157599e98aSJez Ng           .Case(section_names::lazySymbolPtr, -2)
1167599e98aSJez Ng           .Case(section_names::const_, -1)
1177599e98aSJez Ng           .Default(osec->inputOrder);
1187599e98aSJez Ng     }
1197599e98aSJez Ng   } else if (segname == segment_names::linkEdit) {
1207599e98aSJez Ng     return StringSwitch<int>(osec->name)
121560636e5SJez Ng         .Case(section_names::rebase, -10)
122560636e5SJez Ng         .Case(section_names::binding, -9)
123560636e5SJez Ng         .Case(section_names::weakBinding, -8)
124560636e5SJez Ng         .Case(section_names::lazyBinding, -7)
125560636e5SJez Ng         .Case(section_names::export_, -6)
126560636e5SJez Ng         .Case(section_names::functionStarts, -5)
127560636e5SJez Ng         .Case(section_names::dataInCode, -4)
1287599e98aSJez Ng         .Case(section_names::symbolTable, -3)
1297599e98aSJez Ng         .Case(section_names::indirectSymbolTable, -2)
1307599e98aSJez Ng         .Case(section_names::stringTable, -1)
1317599e98aSJez Ng         .Case(section_names::codeSignature, std::numeric_limits<int>::max())
1327599e98aSJez Ng         .Default(osec->inputOrder);
1337599e98aSJez Ng   }
134e6cb55d5SNico Weber   // ZeroFill sections must always be the at the end of their segments:
135e6cb55d5SNico Weber   // dyld checks if a segment's file size is smaller than its in-memory
136e6cb55d5SNico Weber   // size to detect if a segment has zerofill sections, and if so it maps
137e6cb55d5SNico Weber   // the missing tail as zerofill.
1387599e98aSJez Ng   if (sectionType(osec->flags) == S_ZEROFILL)
1397599e98aSJez Ng     return std::numeric_limits<int>::max();
1407599e98aSJez Ng   return osec->inputOrder;
1417599e98aSJez Ng }
1427599e98aSJez Ng 
sortOutputSections()1437599e98aSJez Ng void OutputSegment::sortOutputSections() {
144f1969b74SNico Weber   // Must be stable_sort() to keep special sections such as
145f1969b74SNico Weber   // S_THREAD_LOCAL_REGULAR in input order.
146f1969b74SNico Weber   llvm::stable_sort(sections, compareByOrder<OutputSection *>(sectionOrder));
1477599e98aSJez Ng }
1487599e98aSJez Ng 
assignAddressesToStartEndSymbols()14980caa1ebSNico Weber void OutputSegment::assignAddressesToStartEndSymbols() {
15080caa1ebSNico Weber   for (Defined *d : segmentStartSymbols)
15180caa1ebSNico Weber     d->value = addr;
15280caa1ebSNico Weber   for (Defined *d : segmentEndSymbols)
15380caa1ebSNico Weber     d->value = addr + vmSize;
15480caa1ebSNico Weber }
15580caa1ebSNico Weber 
sortOutputSegments()1567599e98aSJez Ng void macho::sortOutputSegments() {
15704f5eb40SNico Weber   llvm::stable_sort(outputSegments,
15804f5eb40SNico Weber                     compareByOrder<OutputSegment *>(segmentOrder));
1597599e98aSJez Ng }
1607599e98aSJez Ng 
161e98b441aSJez Ng static DenseMap<StringRef, OutputSegment *> nameToOutputSegment;
1626acd3003SFangrui Song std::vector<OutputSegment *> macho::outputSegments;
1636acd3003SFangrui Song 
resetOutputSegments()164*0f6d720fSShoaib Meenai void macho::resetOutputSegments() {
165*0f6d720fSShoaib Meenai   outputSegments.clear();
166*0f6d720fSShoaib Meenai   nameToOutputSegment.clear();
167*0f6d720fSShoaib Meenai }
168*0f6d720fSShoaib Meenai 
maybeRenameSegment(StringRef name)169afdeb432SNico Weber static StringRef maybeRenameSegment(StringRef name) {
170afdeb432SNico Weber   auto newName = config->segmentRenameMap.find(name);
171afdeb432SNico Weber   if (newName != config->segmentRenameMap.end())
172afdeb432SNico Weber     return newName->second;
173afdeb432SNico Weber   return name;
174afdeb432SNico Weber }
175afdeb432SNico Weber 
getOrCreateOutputSegment(StringRef name)1766f63216cSJez Ng OutputSegment *macho::getOrCreateOutputSegment(StringRef name) {
177afdeb432SNico Weber   name = maybeRenameSegment(name);
178afdeb432SNico Weber 
1796f63216cSJez Ng   OutputSegment *&segRef = nameToOutputSegment[name];
1809c702814SJez Ng   if (segRef)
1816f63216cSJez Ng     return segRef;
1826f63216cSJez Ng 
1836f63216cSJez Ng   segRef = make<OutputSegment>();
1846f63216cSJez Ng   segRef->name = name;
1856f63216cSJez Ng   segRef->maxProt = maxProt(name);
1866f63216cSJez Ng   segRef->initProt = initProt(name);
1876f63216cSJez Ng 
1886f63216cSJez Ng   outputSegments.push_back(segRef);
1896f63216cSJez Ng   return segRef;
1906acd3003SFangrui Song }
191