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 "InputSection.h"
11 #include "MergedOutputSection.h"
12 #include "SyntheticSections.h"
13 
14 #include "lld/Common/ErrorHandler.h"
15 #include "lld/Common/Memory.h"
16 #include "llvm/BinaryFormat/MachO.h"
17 
18 using namespace llvm;
19 using namespace llvm::MachO;
20 using namespace lld;
21 using namespace lld::macho;
22 
23 static uint32_t initProt(StringRef name) {
24   if (name == segment_names::text)
25     return VM_PROT_READ | VM_PROT_EXECUTE;
26   if (name == segment_names::pageZero)
27     return 0;
28   if (name == segment_names::linkEdit)
29     return VM_PROT_READ;
30   return VM_PROT_READ | VM_PROT_WRITE;
31 }
32 
33 static uint32_t maxProt(StringRef name) {
34   if (name == segment_names::pageZero)
35     return 0;
36   return VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
37 }
38 
39 size_t OutputSegment::numNonHiddenSections() const {
40   size_t count = 0;
41   for (const OutputSegment::SectionMapEntry &i : sections) {
42     OutputSection *os = i.second;
43     count += (os->isHidden() ? 0 : 1);
44   }
45   return count;
46 }
47 
48 void OutputSegment::addOutputSection(OutputSection *os) {
49   os->parent = this;
50   std::pair<SectionMap::iterator, bool> result =
51       sections.insert(SectionMapEntry(os->name, os));
52   if (!result.second) {
53     llvm_unreachable("Attempted to set section, but a section with the same "
54                      "name already exists");
55   }
56 }
57 
58 OutputSection *OutputSegment::getOrCreateOutputSection(StringRef name) {
59   OutputSegment::SectionMap::iterator i = sections.find(name);
60   if (i != sections.end()) {
61     return i->second;
62   }
63 
64   auto *os = make<MergedOutputSection>(name);
65   addOutputSection(os);
66   return os;
67 }
68 
69 void OutputSegment::sortOutputSections(OutputSegmentComparator *comparator) {
70   llvm::stable_sort(sections, *comparator->sectionComparator(this));
71 }
72 
73 OutputSegmentComparator::OutputSegmentComparator() {
74   // This defines the order of segments and the sections within each segment.
75   // Segments that are not mentioned here will end up at defaultPosition;
76   // sections that are not mentioned will end up at the end of the section
77   // list for their given segment.
78   std::vector<std::pair<StringRef, std::vector<StringRef>>> ordering{
79       {segment_names::pageZero, {}},
80       {segment_names::text, {section_names::header}},
81       {defaultPosition, {}},
82       // Make sure __LINKEDIT is the last segment (i.e. all its hidden
83       // sections must be ordered after other sections).
84       {segment_names::linkEdit,
85        {
86            section_names::binding,
87            section_names::export_,
88            section_names::symbolTable,
89            section_names::stringTable,
90        }},
91   };
92 
93   for (uint32_t i = 0, n = ordering.size(); i < n; ++i) {
94     auto &p = ordering[i];
95     StringRef segname = p.first;
96     const std::vector<StringRef> &sectOrdering = p.second;
97     orderMap.insert(std::pair<StringRef, OutputSectionComparator>(
98         segname, OutputSectionComparator(i, sectOrdering)));
99   }
100 
101   // Cache the position for the default comparator since this is the likely
102   // scenario.
103   defaultPositionComparator = &orderMap.find(defaultPosition)->second;
104 }
105 
106 static llvm::DenseMap<StringRef, OutputSegment *> nameToOutputSegment;
107 std::vector<OutputSegment *> macho::outputSegments;
108 
109 OutputSegment *macho::getOutputSegment(StringRef name) {
110   return nameToOutputSegment.lookup(name);
111 }
112 
113 OutputSegment *macho::getOrCreateOutputSegment(StringRef name) {
114   OutputSegment *&segRef = nameToOutputSegment[name];
115   if (segRef != nullptr)
116     return segRef;
117 
118   segRef = make<OutputSegment>();
119   segRef->name = name;
120   segRef->maxProt = maxProt(name);
121   segRef->initProt = initProt(name);
122 
123   outputSegments.push_back(segRef);
124   return segRef;
125 }
126 
127 void macho::sortOutputSegmentsAndSections() {
128   // Sorting only can happen once all outputs have been collected.
129   // Since output sections are grouped by segment, sorting happens
130   // first over all segments, then over sections per segment.
131   auto comparator = OutputSegmentComparator();
132   llvm::stable_sort(outputSegments, comparator);
133 
134   // Now that the output sections are sorted, assign the final
135   // output section indices.
136   uint32_t sectionIndex = 0;
137   for (OutputSegment *seg : outputSegments) {
138     seg->sortOutputSections(&comparator);
139     for (auto &p : seg->getSections()) {
140       OutputSection *section = p.second;
141       if (!section->isHidden()) {
142         section->index = ++sectionIndex;
143       }
144     }
145   }
146 }
147