1 //===- MachOReader.cpp ------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MachOReader.h"
10 #include "../llvm-objcopy.h"
12 #include "llvm/BinaryFormat/MachO.h"
13 #include "llvm/Object/MachO.h"
20 void MachOReader::readHeader(Object
&O
) const {
21 O
.Header
.Magic
= MachOObj
.getHeader().magic
;
22 O
.Header
.CPUType
= MachOObj
.getHeader().cputype
;
23 O
.Header
.CPUSubType
= MachOObj
.getHeader().cpusubtype
;
24 O
.Header
.FileType
= MachOObj
.getHeader().filetype
;
25 O
.Header
.NCmds
= MachOObj
.getHeader().ncmds
;
26 O
.Header
.SizeOfCmds
= MachOObj
.getHeader().sizeofcmds
;
27 O
.Header
.Flags
= MachOObj
.getHeader().flags
;
30 template <typename SectionType
>
31 Section
constructSectionCommon(SectionType Sec
) {
34 StringRef(Sec
.sectname
, strnlen(Sec
.sectname
, sizeof(Sec
.sectname
)))
37 StringRef(Sec
.segname
, strnlen(Sec
.segname
, sizeof(Sec
.sectname
))).str();
40 S
.Offset
= Sec
.offset
;
42 S
.RelOff
= Sec
.reloff
;
43 S
.NReloc
= Sec
.nreloc
;
45 S
.Reserved1
= Sec
.reserved1
;
46 S
.Reserved2
= Sec
.reserved2
;
51 template <typename SectionType
> Section
constructSection(SectionType Sec
);
53 template <> Section
constructSection(MachO::section Sec
) {
54 return constructSectionCommon(Sec
);
57 template <> Section
constructSection(MachO::section_64 Sec
) {
58 Section S
= constructSectionCommon(Sec
);
59 S
.Reserved3
= Sec
.reserved3
;
63 // TODO: get rid of reportError and make MachOReader return Expected<> instead.
64 template <typename SectionType
, typename SegmentType
>
66 extractSections(const object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
67 const object::MachOObjectFile
&MachOObj
,
68 size_t &NextSectionIndex
) {
69 auto End
= LoadCmd
.Ptr
+ LoadCmd
.C
.cmdsize
;
70 const SectionType
*Curr
=
71 reinterpret_cast<const SectionType
*>(LoadCmd
.Ptr
+ sizeof(SegmentType
));
72 std::vector
<Section
> Sections
;
73 for (; reinterpret_cast<const void *>(Curr
) < End
; Curr
++) {
74 if (MachOObj
.isLittleEndian() != sys::IsLittleEndianHost
) {
76 memcpy((void *)&Sec
, Curr
, sizeof(SectionType
));
77 MachO::swapStruct(Sec
);
78 Sections
.push_back(constructSection(Sec
));
80 Sections
.push_back(constructSection(*Curr
));
83 Section
&S
= Sections
.back();
85 Expected
<object::SectionRef
> SecRef
=
86 MachOObj
.getSection(NextSectionIndex
++);
88 reportError(MachOObj
.getFileName(), SecRef
.takeError());
90 if (Expected
<ArrayRef
<uint8_t>> E
=
91 MachOObj
.getSectionContents(SecRef
->getRawDataRefImpl()))
93 StringRef(reinterpret_cast<const char *>(E
->data()), E
->size());
95 reportError(MachOObj
.getFileName(), E
.takeError());
97 S
.Relocations
.reserve(S
.NReloc
);
98 for (auto RI
= MachOObj
.section_rel_begin(SecRef
->getRawDataRefImpl()),
99 RE
= MachOObj
.section_rel_end(SecRef
->getRawDataRefImpl());
102 R
.Symbol
= nullptr; // We'll fill this field later.
103 R
.Info
= MachOObj
.getRelocation(RI
->getRawDataRefImpl());
104 R
.Scattered
= MachOObj
.isRelocationScattered(R
.Info
);
105 S
.Relocations
.push_back(R
);
108 assert(S
.NReloc
== S
.Relocations
.size() &&
109 "Incorrect number of relocations");
114 void MachOReader::readLoadCommands(Object
&O
) const {
115 // For MachO sections indices start from 1.
116 size_t NextSectionIndex
= 1;
117 for (auto LoadCmd
: MachOObj
.load_commands()) {
119 switch (LoadCmd
.C
.cmd
) {
120 case MachO::LC_SEGMENT
:
121 LC
.Sections
= extractSections
<MachO::section
, MachO::segment_command
>(
122 LoadCmd
, MachOObj
, NextSectionIndex
);
124 case MachO::LC_SEGMENT_64
:
126 extractSections
<MachO::section_64
, MachO::segment_command_64
>(
127 LoadCmd
, MachOObj
, NextSectionIndex
);
129 case MachO::LC_SYMTAB
:
130 O
.SymTabCommandIndex
= O
.LoadCommands
.size();
132 case MachO::LC_DYLD_INFO
:
133 case MachO::LC_DYLD_INFO_ONLY
:
134 O
.DyLdInfoCommandIndex
= O
.LoadCommands
.size();
137 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
138 case MachO::LCName: \
139 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
140 sizeof(MachO::LCStruct)); \
141 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
142 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
143 LC.Payload = ArrayRef<uint8_t>( \
144 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
145 sizeof(MachO::LCStruct), \
146 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
149 switch (LoadCmd
.C
.cmd
) {
151 memcpy((void *)&(LC
.MachOLoadCommand
.load_command_data
), LoadCmd
.Ptr
,
152 sizeof(MachO::load_command
));
153 if (MachOObj
.isLittleEndian() != sys::IsLittleEndianHost
)
154 MachO::swapStruct(LC
.MachOLoadCommand
.load_command_data
);
155 LC
.Payload
= ArrayRef
<uint8_t>(
156 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd
.Ptr
)) +
157 sizeof(MachO::load_command
),
158 LoadCmd
.C
.cmdsize
- sizeof(MachO::load_command
));
160 #include "llvm/BinaryFormat/MachO.def"
162 O
.LoadCommands
.push_back(std::move(LC
));
166 template <typename nlist_t
>
167 SymbolEntry
constructSymbolEntry(StringRef StrTable
, const nlist_t
&nlist
) {
168 assert(nlist
.n_strx
< StrTable
.size() &&
169 "n_strx exceeds the size of the string table");
171 SE
.Name
= StringRef(StrTable
.data() + nlist
.n_strx
).str();
172 SE
.n_type
= nlist
.n_type
;
173 SE
.n_sect
= nlist
.n_sect
;
174 SE
.n_desc
= nlist
.n_desc
;
175 SE
.n_value
= nlist
.n_value
;
179 void MachOReader::readSymbolTable(Object
&O
) const {
180 StringRef StrTable
= MachOObj
.getStringTableData();
181 for (auto Symbol
: MachOObj
.symbols()) {
184 ? constructSymbolEntry(
186 MachOObj
.getSymbol64TableEntry(Symbol
.getRawDataRefImpl()))
187 : constructSymbolEntry(
189 MachOObj
.getSymbolTableEntry(Symbol
.getRawDataRefImpl())));
191 O
.SymTable
.Symbols
.push_back(llvm::make_unique
<SymbolEntry
>(SE
));
195 void MachOReader::setSymbolInRelocationInfo(Object
&O
) const {
196 for (auto &LC
: O
.LoadCommands
)
197 for (auto &Sec
: LC
.Sections
)
198 for (auto &Reloc
: Sec
.Relocations
)
199 if (!Reloc
.Scattered
) {
200 auto *Info
= reinterpret_cast<MachO::relocation_info
*>(&Reloc
.Info
);
201 Reloc
.Symbol
= O
.SymTable
.getSymbolByIndex(Info
->r_symbolnum
);
205 void MachOReader::readRebaseInfo(Object
&O
) const {
206 O
.Rebases
.Opcodes
= MachOObj
.getDyldInfoRebaseOpcodes();
209 void MachOReader::readBindInfo(Object
&O
) const {
210 O
.Binds
.Opcodes
= MachOObj
.getDyldInfoBindOpcodes();
213 void MachOReader::readWeakBindInfo(Object
&O
) const {
214 O
.WeakBinds
.Opcodes
= MachOObj
.getDyldInfoWeakBindOpcodes();
217 void MachOReader::readLazyBindInfo(Object
&O
) const {
218 O
.LazyBinds
.Opcodes
= MachOObj
.getDyldInfoLazyBindOpcodes();
221 void MachOReader::readExportInfo(Object
&O
) const {
222 O
.Exports
.Trie
= MachOObj
.getDyldInfoExportsTrie();
225 std::unique_ptr
<Object
> MachOReader::create() const {
226 auto Obj
= llvm::make_unique
<Object
>();
228 readLoadCommands(*Obj
);
229 readSymbolTable(*Obj
);
230 setSymbolInRelocationInfo(*Obj
);
231 readRebaseInfo(*Obj
);
233 readWeakBindInfo(*Obj
);
234 readLazyBindInfo(*Obj
);
235 readExportInfo(*Obj
);
239 } // end namespace macho
240 } // end namespace objcopy
241 } // end namespace llvm