LLVM 24.0.0git
MachOReader.cpp
Go to the documentation of this file.
1//===- MachOReader.cpp ------------------------------------------*- 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 "MachOReader.h"
10#include "MachOObject.h"
12#include "llvm/Object/MachO.h"
13#include <memory>
14
15using namespace llvm;
16using namespace llvm::objcopy;
17using namespace llvm::objcopy::macho;
18
19void MachOReader::readHeader(Object &O) const {
20 O.Header.Magic = MachOObj.getHeader().magic;
21 O.Header.CPUType = MachOObj.getHeader().cputype;
22 O.Header.CPUSubType = MachOObj.getHeader().cpusubtype;
23 O.Header.FileType = MachOObj.getHeader().filetype;
24 O.Header.NCmds = MachOObj.getHeader().ncmds;
25 O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds;
26 O.Header.Flags = MachOObj.getHeader().flags;
27}
28
29template <typename SectionType>
30static Section constructSectionCommon(const SectionType &Sec, uint32_t Index) {
31 StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname)));
32 StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname)));
33 Section S(SegName, SectName);
34 S.Index = Index;
35 S.Addr = Sec.addr;
36 S.Size = Sec.size;
37 S.OriginalOffset = Sec.offset;
38 S.Align = Sec.align;
39 S.RelOff = Sec.reloff;
40 S.NReloc = Sec.nreloc;
41 S.Flags = Sec.flags;
42 S.Reserved1 = Sec.reserved1;
43 S.Reserved2 = Sec.reserved2;
44 S.Reserved3 = 0;
45 return S;
46}
47
49 return constructSectionCommon(Sec, Index);
50}
51
53 Section S = constructSectionCommon(Sec, Index);
54 S.Reserved3 = Sec.reserved3;
55 return S;
56}
57
58template <typename SectionType, typename SegmentType>
61 const object::MachOObjectFile &MachOObj, uint32_t &NextSectionIndex) {
62 std::vector<std::unique_ptr<Section>> Sections;
63 for (auto Curr = reinterpret_cast<const SectionType *>(LoadCmd.Ptr +
64 sizeof(SegmentType)),
65 End = reinterpret_cast<const SectionType *>(LoadCmd.Ptr +
66 LoadCmd.C.cmdsize);
67 Curr < End; ++Curr) {
68 SectionType Sec;
69 memcpy((void *)&Sec, reinterpret_cast<const char *>(Curr),
70 sizeof(SectionType));
71
74
75 Sections.push_back(
76 std::make_unique<Section>(constructSection(Sec, NextSectionIndex)));
77
78 Section &S = *Sections.back();
79
81 MachOObj.getSection(NextSectionIndex++);
82 if (!SecRef)
83 return SecRef.takeError();
84
86 MachOObj.getSectionContents(SecRef->getRawDataRefImpl());
87 if (!Data)
88 return Data.takeError();
89
90 S.Content =
91 StringRef(reinterpret_cast<const char *>(Data->data()), Data->size());
92
93 const uint32_t CPUType = MachOObj.getHeader().cputype;
94 S.Relocations.reserve(S.NReloc);
95 for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
96 RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl());
97 RI != RE; ++RI) {
99 R.Symbol = nullptr; // We'll fill this field later.
100 R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl());
101 R.Scattered = MachOObj.isRelocationScattered(R.Info);
102 unsigned Type = MachOObj.getAnyRelocationType(R.Info);
103 // TODO Support CPU_TYPE_ARM.
104 R.IsAddend = !R.Scattered &&
105 (CPUType == MachO::CPU_TYPE_ARM64 ||
106 CPUType == MachO::CPU_TYPE_ARM64_32) &&
108 R.Extern = !R.Scattered && MachOObj.getPlainRelocationExternal(R.Info);
109 S.Relocations.push_back(R);
110 }
111
112 assert(S.NReloc == S.Relocations.size() &&
113 "Incorrect number of relocations");
114 }
115 return std::move(Sections);
116}
117
118Error MachOReader::readLoadCommands(Object &O) const {
119 // For MachO sections indices start from 1.
120 uint32_t NextSectionIndex = 1;
121 static constexpr char TextSegmentName[] = "__TEXT";
122 for (auto LoadCmd : MachOObj.load_commands()) {
123 LoadCommand LC;
124 switch (LoadCmd.C.cmd) {
125 case MachO::LC_CODE_SIGNATURE:
126 O.CodeSignatureCommandIndex = O.LoadCommands.size();
127 break;
128 case MachO::LC_SEGMENT:
129 // LoadCmd.Ptr might not be aligned temporarily as
130 // MachO::segment_command requires, but the segname char pointer do not
131 // have alignment restrictions.
132 if (StringRef(reinterpret_cast<const char *>(
133 LoadCmd.Ptr + offsetof(MachO::segment_command, segname))) ==
134 TextSegmentName)
135 O.TextSegmentCommandIndex = O.LoadCommands.size();
136
137 if (Expected<std::vector<std::unique_ptr<Section>>> Sections =
139 LoadCmd, MachOObj, NextSectionIndex))
140 LC.Sections = std::move(*Sections);
141 else
142 return Sections.takeError();
143 break;
144 case MachO::LC_SEGMENT_64:
145 // LoadCmd.Ptr might not be aligned temporarily as
146 // MachO::segment_command_64 requires, but the segname char pointer do
147 // not have alignment restrictions.
148 if (StringRef(reinterpret_cast<const char *>(
149 LoadCmd.Ptr + offsetof(MachO::segment_command_64, segname))) ==
150 TextSegmentName)
151 O.TextSegmentCommandIndex = O.LoadCommands.size();
152
153 if (Expected<std::vector<std::unique_ptr<Section>>> Sections =
155 LoadCmd, MachOObj, NextSectionIndex))
156 LC.Sections = std::move(*Sections);
157 else
158 return Sections.takeError();
159 break;
160 case MachO::LC_SYMTAB:
161 O.SymTabCommandIndex = O.LoadCommands.size();
162 break;
163 case MachO::LC_DYSYMTAB:
164 O.DySymTabCommandIndex = O.LoadCommands.size();
165 break;
166 case MachO::LC_DYLD_INFO:
167 case MachO::LC_DYLD_INFO_ONLY:
168 O.DyLdInfoCommandIndex = O.LoadCommands.size();
169 break;
170 case MachO::LC_DATA_IN_CODE:
171 O.DataInCodeCommandIndex = O.LoadCommands.size();
172 break;
173 case MachO::LC_LINKER_OPTIMIZATION_HINT:
174 O.LinkerOptimizationHintCommandIndex = O.LoadCommands.size();
175 break;
176 case MachO::LC_FUNCTION_STARTS:
177 O.FunctionStartsCommandIndex = O.LoadCommands.size();
178 break;
179 case MachO::LC_DYLIB_CODE_SIGN_DRS:
180 O.DylibCodeSignDRsIndex = O.LoadCommands.size();
181 break;
182 case MachO::LC_DYLD_EXPORTS_TRIE:
183 O.ExportsTrieCommandIndex = O.LoadCommands.size();
184 break;
185 case MachO::LC_DYLD_CHAINED_FIXUPS:
186 O.ChainedFixupsCommandIndex = O.LoadCommands.size();
187 break;
188 }
189#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
190 case MachO::LCName: \
191 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
192 sizeof(MachO::LCStruct)); \
193 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
194 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
195 if (LoadCmd.C.cmdsize > sizeof(MachO::LCStruct)) \
196 LC.Payload = ArrayRef<uint8_t>( \
197 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
198 sizeof(MachO::LCStruct), \
199 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
200 break;
201
202 switch (LoadCmd.C.cmd) {
203 default:
204 memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
205 sizeof(MachO::load_command));
206 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
207 MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
208 if (LoadCmd.C.cmdsize > sizeof(MachO::load_command))
209 LC.Payload = ArrayRef<uint8_t>(
210 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
211 sizeof(MachO::load_command),
212 LoadCmd.C.cmdsize - sizeof(MachO::load_command));
213 break;
214#include "llvm/BinaryFormat/MachO.def"
215 }
216 O.LoadCommands.push_back(std::move(LC));
217 }
218 return Error::success();
219}
220
221template <typename nlist_t>
222SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
223 assert(nlist.n_strx < StrTable.size() &&
224 "n_strx exceeds the size of the string table");
225 SymbolEntry SE;
226 SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
227 SE.n_type = nlist.n_type;
228 SE.n_sect = nlist.n_sect;
229 SE.n_desc = nlist.n_desc;
230 SE.n_value = nlist.n_value;
231 return SE;
232}
233
234void MachOReader::readSymbolTable(Object &O) const {
235 StringRef StrTable = MachOObj.getStringTableData();
236 for (auto Symbol : MachOObj.symbols()) {
237 SymbolEntry SE =
238 (MachOObj.is64Bit()
239 ? constructSymbolEntry(StrTable, MachOObj.getSymbol64TableEntry(
240 Symbol.getRawDataRefImpl()))
241 : constructSymbolEntry(StrTable, MachOObj.getSymbolTableEntry(
242 Symbol.getRawDataRefImpl())));
243
244 O.SymTable.Symbols.push_back(std::make_unique<SymbolEntry>(SE));
245 }
246}
247
248void MachOReader::setSymbolInRelocationInfo(Object &O) const {
249 std::vector<const Section *> Sections;
250 for (auto &LC : O.LoadCommands)
251 for (std::unique_ptr<Section> &Sec : LC.Sections)
252 Sections.push_back(Sec.get());
253
254 for (LoadCommand &LC : O.LoadCommands)
255 for (std::unique_ptr<Section> &Sec : LC.Sections)
256 for (auto &Reloc : Sec->Relocations)
257 if (!Reloc.Scattered && !Reloc.IsAddend) {
258 const uint32_t SymbolNum =
259 Reloc.getPlainRelocationSymbolNum(MachOObj.isLittleEndian());
260 if (Reloc.Extern) {
261 Reloc.Symbol = O.SymTable.getSymbolByIndex(SymbolNum);
262 } else {
263 // FIXME: Refactor error handling in MachOReader and report an error
264 // if we encounter an invalid relocation.
265 assert(SymbolNum >= 1 && SymbolNum <= Sections.size() &&
266 "Invalid section index.");
267 Reloc.Sec = Sections[SymbolNum - 1];
268 }
269 }
270}
271
272void MachOReader::readRebaseInfo(Object &O) const {
273 O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
274}
275
276void MachOReader::readBindInfo(Object &O) const {
277 O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
278}
279
280void MachOReader::readWeakBindInfo(Object &O) const {
281 O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
282}
283
284void MachOReader::readLazyBindInfo(Object &O) const {
285 O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
286}
287
288void MachOReader::readExportInfo(Object &O) const {
289 // This information can be in LC_DYLD_INFO or in LC_DYLD_EXPORTS_TRIE
290 ArrayRef<uint8_t> Trie = MachOObj.getDyldInfoExportsTrie();
291 if (Trie.empty())
292 Trie = MachOObj.getDyldExportsTrie();
293 O.Exports.Trie = Trie;
294}
295
296void MachOReader::readLinkData(Object &O, std::optional<size_t> LCIndex,
297 LinkData &LD) const {
298 if (!LCIndex)
299 return;
300 const MachO::linkedit_data_command &LC =
301 O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data;
302 LD.Data =
303 arrayRefFromStringRef(MachOObj.getData().substr(LC.dataoff, LC.datasize));
304}
305
306void MachOReader::readDataInCodeData(Object &O) const {
307 return readLinkData(O, O.DataInCodeCommandIndex, O.DataInCode);
308}
309
310void MachOReader::readLinkerOptimizationHint(Object &O) const {
311 return readLinkData(O, O.LinkerOptimizationHintCommandIndex,
312 O.LinkerOptimizationHint);
313}
314
315void MachOReader::readFunctionStartsData(Object &O) const {
316 return readLinkData(O, O.FunctionStartsCommandIndex, O.FunctionStarts);
317}
318
319void MachOReader::readDylibCodeSignDRs(Object &O) const {
320 return readLinkData(O, O.DylibCodeSignDRsIndex, O.DylibCodeSignDRs);
321}
322
323void MachOReader::readExportsTrie(Object &O) const {
324 return readLinkData(O, O.ExportsTrieCommandIndex, O.ExportsTrie);
325}
326
327void MachOReader::readChainedFixups(Object &O) const {
328 return readLinkData(O, O.ChainedFixupsCommandIndex, O.ChainedFixups);
329}
330
331void MachOReader::readIndirectSymbolTable(Object &O) const {
332 MachO::dysymtab_command DySymTab = MachOObj.getDysymtabLoadCommand();
333 constexpr uint32_t AbsOrLocalMask =
335 for (uint32_t i = 0; i < DySymTab.nindirectsyms; ++i) {
336 uint32_t Index = MachOObj.getIndirectSymbolTableEntry(DySymTab, i);
337 if ((Index & AbsOrLocalMask) != 0)
338 O.IndirectSymTable.Symbols.emplace_back(Index, std::nullopt);
339 else
340 O.IndirectSymTable.Symbols.emplace_back(
341 Index, O.SymTable.getSymbolByIndex(Index));
342 }
343}
344
345void MachOReader::readSwiftVersion(Object &O) const {
346 struct ObjCImageInfo {
347 uint32_t Version;
348 uint32_t Flags;
349 } ImageInfo;
350
351 for (const LoadCommand &LC : O.LoadCommands)
352 for (const std::unique_ptr<Section> &Sec : LC.Sections)
353 if (Sec->Sectname == "__objc_imageinfo" &&
354 (Sec->Segname == "__DATA" || Sec->Segname == "__DATA_CONST" ||
355 Sec->Segname == "__DATA_DIRTY") &&
356 Sec->Content.size() >= sizeof(ObjCImageInfo)) {
357 memcpy(&ImageInfo, Sec->Content.data(), sizeof(ObjCImageInfo));
358 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
359 sys::swapByteOrder(ImageInfo.Version);
360 sys::swapByteOrder(ImageInfo.Flags);
361 }
362 O.SwiftVersion = (ImageInfo.Flags >> 8) & 0xff;
363 return;
364 }
365}
366
368 auto Obj = std::make_unique<Object>();
369 readHeader(*Obj);
370 if (Error E = readLoadCommands(*Obj))
371 return std::move(E);
372 readSymbolTable(*Obj);
373 setSymbolInRelocationInfo(*Obj);
374 readRebaseInfo(*Obj);
375 readBindInfo(*Obj);
376 readWeakBindInfo(*Obj);
377 readLazyBindInfo(*Obj);
378 readExportInfo(*Obj);
379 readDataInCodeData(*Obj);
380 readLinkerOptimizationHint(*Obj);
381 readFunctionStartsData(*Obj);
382 readDylibCodeSignDRs(*Obj);
383 readExportsTrie(*Obj);
384 readChainedFixups(*Obj);
385 readIndirectSymbolTable(*Obj);
386 readSwiftVersion(*Obj);
387 return std::move(Obj);
388}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define offsetof(TYPE, MEMBER)
static Section constructSectionCommon(const SectionType &Sec, uint32_t Index)
static Expected< std::vector< std::unique_ptr< Section > > > extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd, const object::MachOObjectFile &MachOObj, uint32_t &NextSectionIndex)
Section constructSection(const MachO::section &Sec, uint32_t Index)
SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist)
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
constexpr const char * data() const
Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:138
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
Expected< std::unique_ptr< Object > > create() const override
bool isLittleEndian() const
Definition Binary.h:157
Expected< SectionRef > getSection(unsigned SectionIndex) const
relocation_iterator section_rel_begin(DataRefImpl Sec) const override
relocation_iterator section_rel_end(DataRefImpl Sec) const override
unsigned getAnyRelocationType(const MachO::any_relocation_info &RE) const
bool getPlainRelocationExternal(const MachO::any_relocation_info &RE) const
const MachO::mach_header & getHeader() const
MachO::any_relocation_info getRelocation(DataRefImpl Rel) const
bool isRelocationScattered(const MachO::any_relocation_info &RE) const
ArrayRef< uint8_t > getSectionContents(uint64_t Offset, uint64_t Size) const
void swapStruct(fat_header &mh)
Definition MachO.h:1267
constexpr uint32_t INDIRECT_SYMBOL_ABS
Definition MachO.h:219
constexpr uint32_t INDIRECT_SYMBOL_LOCAL
Definition MachO.h:218
@ ARM64_RELOC_ADDEND
Definition MachO.h:472
@ CPU_TYPE_ARM64_32
Definition MachO.h:1704
@ CPU_TYPE_ARM64
Definition MachO.h:1703
constexpr bool IsLittleEndianHost
void swapByteOrder(T &Value)
This is an optimization pass for GlobalISel generic memory operations.
ArrayRef< CharT > arrayRefFromStringRef(StringRef Input)
Construct an array ref of bytes from a string ref.
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
size_t strnlen(const char *S, size_t MaxLen) asm("llvm_zos_strnlen")
MachO::macho_load_command MachOLoadCommand
Definition MachOObject.h:82
std::vector< std::unique_ptr< Section > > Sections
Definition MachOObject.h:93
std::vector< uint8_t > Payload
Definition MachOObject.h:87
std::optional< uint32_t > OriginalOffset
Definition MachOObject.h:47
std::vector< RelocationInfo > Relocations
Definition MachOObject.h:57