1 //===- MachOObject.cpp - Mach-O object file model ---------------*- C++ -*-===//
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 "MachOObject.h"
10 #include "llvm/ADT/SmallPtrSet.h"
11 #include <unordered_set>
12
13 using namespace llvm;
14 using namespace llvm::objcopy::macho;
15
getSymbolByIndex(uint32_t Index) const16 const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {
17 assert(Index < Symbols.size() && "invalid symbol index");
18 return Symbols[Index].get();
19 }
20
getSymbolByIndex(uint32_t Index)21 SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
22 return const_cast<SymbolEntry *>(
23 static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
24 }
25
removeSymbols(function_ref<bool (const std::unique_ptr<SymbolEntry> &)> ToRemove)26 void SymbolTable::removeSymbols(
27 function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
28 llvm::erase_if(Symbols, ToRemove);
29 }
30
updateLoadCommandIndexes()31 void Object::updateLoadCommandIndexes() {
32 static constexpr char TextSegmentName[] = "__TEXT";
33 // Update indices of special load commands
34 for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {
35 LoadCommand &LC = LoadCommands[Index];
36 switch (LC.MachOLoadCommand.load_command_data.cmd) {
37 case MachO::LC_CODE_SIGNATURE:
38 CodeSignatureCommandIndex = Index;
39 break;
40 case MachO::LC_SEGMENT:
41 if (StringRef(LC.MachOLoadCommand.segment_command_data.segname) ==
42 TextSegmentName)
43 TextSegmentCommandIndex = Index;
44 break;
45 case MachO::LC_SEGMENT_64:
46 if (StringRef(LC.MachOLoadCommand.segment_command_64_data.segname) ==
47 TextSegmentName)
48 TextSegmentCommandIndex = Index;
49 break;
50 case MachO::LC_SYMTAB:
51 SymTabCommandIndex = Index;
52 break;
53 case MachO::LC_DYSYMTAB:
54 DySymTabCommandIndex = Index;
55 break;
56 case MachO::LC_DYLD_INFO:
57 case MachO::LC_DYLD_INFO_ONLY:
58 DyLdInfoCommandIndex = Index;
59 break;
60 case MachO::LC_DATA_IN_CODE:
61 DataInCodeCommandIndex = Index;
62 break;
63 case MachO::LC_LINKER_OPTIMIZATION_HINT:
64 LinkerOptimizationHintCommandIndex = Index;
65 break;
66 case MachO::LC_FUNCTION_STARTS:
67 FunctionStartsCommandIndex = Index;
68 break;
69 case MachO::LC_DYLD_CHAINED_FIXUPS:
70 ChainedFixupsCommandIndex = Index;
71 break;
72 case MachO::LC_DYLD_EXPORTS_TRIE:
73 ExportsTrieCommandIndex = Index;
74 break;
75 }
76 }
77 }
78
removeLoadCommands(function_ref<bool (const LoadCommand &)> ToRemove)79 Error Object::removeLoadCommands(
80 function_ref<bool(const LoadCommand &)> ToRemove) {
81 auto It = std::stable_partition(
82 LoadCommands.begin(), LoadCommands.end(),
83 [&](const LoadCommand &LC) { return !ToRemove(LC); });
84 LoadCommands.erase(It, LoadCommands.end());
85
86 updateLoadCommandIndexes();
87 return Error::success();
88 }
89
removeSections(function_ref<bool (const std::unique_ptr<Section> &)> ToRemove)90 Error Object::removeSections(
91 function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {
92 DenseMap<uint32_t, const Section *> OldIndexToSection;
93 uint32_t NextSectionIndex = 1;
94 for (LoadCommand &LC : LoadCommands) {
95 auto It = std::stable_partition(
96 std::begin(LC.Sections), std::end(LC.Sections),
97 [&](const std::unique_ptr<Section> &Sec) { return !ToRemove(Sec); });
98 for (auto I = LC.Sections.begin(), End = It; I != End; ++I) {
99 OldIndexToSection[(*I)->Index] = I->get();
100 (*I)->Index = NextSectionIndex++;
101 }
102 LC.Sections.erase(It, LC.Sections.end());
103 }
104
105 auto IsDead = [&](const std::unique_ptr<SymbolEntry> &S) -> bool {
106 Optional<uint32_t> Section = S->section();
107 return (Section && !OldIndexToSection.count(*Section));
108 };
109
110 SmallPtrSet<const SymbolEntry *, 2> DeadSymbols;
111 for (const std::unique_ptr<SymbolEntry> &Sym : SymTable.Symbols)
112 if (IsDead(Sym))
113 DeadSymbols.insert(Sym.get());
114
115 for (const LoadCommand &LC : LoadCommands)
116 for (const std::unique_ptr<Section> &Sec : LC.Sections)
117 for (const RelocationInfo &R : Sec->Relocations)
118 if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol))
119 return createStringError(std::errc::invalid_argument,
120 "symbol '%s' defined in section with index "
121 "'%u' cannot be removed because it is "
122 "referenced by a relocation in section '%s'",
123 (*R.Symbol)->Name.c_str(),
124 *((*R.Symbol)->section()),
125 Sec->CanonicalName.c_str());
126 SymTable.removeSymbols(IsDead);
127 for (std::unique_ptr<SymbolEntry> &S : SymTable.Symbols)
128 if (S->section())
129 S->n_sect = OldIndexToSection[S->n_sect]->Index;
130 return Error::success();
131 }
132
nextAvailableSegmentAddress() const133 uint64_t Object::nextAvailableSegmentAddress() const {
134 uint64_t HeaderSize =
135 is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
136 uint64_t Addr = HeaderSize + Header.SizeOfCmds;
137 for (const LoadCommand &LC : LoadCommands) {
138 const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
139 switch (MLC.load_command_data.cmd) {
140 case MachO::LC_SEGMENT:
141 Addr = std::max(Addr,
142 static_cast<uint64_t>(MLC.segment_command_data.vmaddr) +
143 MLC.segment_command_data.vmsize);
144 break;
145 case MachO::LC_SEGMENT_64:
146 Addr = std::max(Addr, MLC.segment_command_64_data.vmaddr +
147 MLC.segment_command_64_data.vmsize);
148 break;
149 default:
150 continue;
151 }
152 }
153 return Addr;
154 }
155
156 template <typename SegmentType>
157 static void
constructSegment(SegmentType & Seg,llvm::MachO::LoadCommandType CmdType,StringRef SegName,uint64_t SegVMAddr,uint64_t SegVMSize)158 constructSegment(SegmentType &Seg, llvm::MachO::LoadCommandType CmdType,
159 StringRef SegName, uint64_t SegVMAddr, uint64_t SegVMSize) {
160 assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");
161 memset(&Seg, 0, sizeof(SegmentType));
162 Seg.cmd = CmdType;
163 strncpy(Seg.segname, SegName.data(), SegName.size());
164 Seg.maxprot |=
165 (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
166 Seg.initprot |=
167 (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
168 Seg.vmaddr = SegVMAddr;
169 Seg.vmsize = SegVMSize;
170 }
171
addSegment(StringRef SegName,uint64_t SegVMSize)172 LoadCommand &Object::addSegment(StringRef SegName, uint64_t SegVMSize) {
173 LoadCommand LC;
174 const uint64_t SegVMAddr = nextAvailableSegmentAddress();
175 if (is64Bit())
176 constructSegment(LC.MachOLoadCommand.segment_command_64_data,
177 MachO::LC_SEGMENT_64, SegName, SegVMAddr, SegVMSize);
178 else
179 constructSegment(LC.MachOLoadCommand.segment_command_data,
180 MachO::LC_SEGMENT, SegName, SegVMAddr, SegVMSize);
181
182 LoadCommands.push_back(std::move(LC));
183 return LoadCommands.back();
184 }
185
186 /// Extracts a segment name from a string which is possibly non-null-terminated.
extractSegmentName(const char * SegName)187 static StringRef extractSegmentName(const char *SegName) {
188 return StringRef(SegName,
189 strnlen(SegName, sizeof(MachO::segment_command::segname)));
190 }
191
getSegmentName() const192 Optional<StringRef> LoadCommand::getSegmentName() const {
193 const MachO::macho_load_command &MLC = MachOLoadCommand;
194 switch (MLC.load_command_data.cmd) {
195 case MachO::LC_SEGMENT:
196 return extractSegmentName(MLC.segment_command_data.segname);
197 case MachO::LC_SEGMENT_64:
198 return extractSegmentName(MLC.segment_command_64_data.segname);
199 default:
200 return None;
201 }
202 }
203
getSegmentVMAddr() const204 Optional<uint64_t> LoadCommand::getSegmentVMAddr() const {
205 const MachO::macho_load_command &MLC = MachOLoadCommand;
206 switch (MLC.load_command_data.cmd) {
207 case MachO::LC_SEGMENT:
208 return MLC.segment_command_data.vmaddr;
209 case MachO::LC_SEGMENT_64:
210 return MLC.segment_command_64_data.vmaddr;
211 default:
212 return None;
213 }
214 }
215