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_DYSYMTAB
:
133 O
.DySymTabCommandIndex
= O
.LoadCommands
.size();
135 case MachO::LC_DYLD_INFO
:
136 case MachO::LC_DYLD_INFO_ONLY
:
137 O
.DyLdInfoCommandIndex
= O
.LoadCommands
.size();
139 case MachO::LC_DATA_IN_CODE
:
140 O
.DataInCodeCommandIndex
= O
.LoadCommands
.size();
142 case MachO::LC_FUNCTION_STARTS
:
143 O
.FunctionStartsCommandIndex
= O
.LoadCommands
.size();
146 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
147 case MachO::LCName: \
148 memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
149 sizeof(MachO::LCStruct)); \
150 if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
151 MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
152 LC.Payload = ArrayRef<uint8_t>( \
153 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
154 sizeof(MachO::LCStruct), \
155 LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
158 switch (LoadCmd
.C
.cmd
) {
160 memcpy((void *)&(LC
.MachOLoadCommand
.load_command_data
), LoadCmd
.Ptr
,
161 sizeof(MachO::load_command
));
162 if (MachOObj
.isLittleEndian() != sys::IsLittleEndianHost
)
163 MachO::swapStruct(LC
.MachOLoadCommand
.load_command_data
);
164 LC
.Payload
= ArrayRef
<uint8_t>(
165 reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd
.Ptr
)) +
166 sizeof(MachO::load_command
),
167 LoadCmd
.C
.cmdsize
- sizeof(MachO::load_command
));
169 #include "llvm/BinaryFormat/MachO.def"
171 O
.LoadCommands
.push_back(std::move(LC
));
175 template <typename nlist_t
>
176 SymbolEntry
constructSymbolEntry(StringRef StrTable
, const nlist_t
&nlist
) {
177 assert(nlist
.n_strx
< StrTable
.size() &&
178 "n_strx exceeds the size of the string table");
180 SE
.Name
= StringRef(StrTable
.data() + nlist
.n_strx
).str();
181 SE
.n_type
= nlist
.n_type
;
182 SE
.n_sect
= nlist
.n_sect
;
183 SE
.n_desc
= nlist
.n_desc
;
184 SE
.n_value
= nlist
.n_value
;
188 void MachOReader::readSymbolTable(Object
&O
) const {
189 StringRef StrTable
= MachOObj
.getStringTableData();
190 for (auto Symbol
: MachOObj
.symbols()) {
193 ? constructSymbolEntry(
195 MachOObj
.getSymbol64TableEntry(Symbol
.getRawDataRefImpl()))
196 : constructSymbolEntry(
198 MachOObj
.getSymbolTableEntry(Symbol
.getRawDataRefImpl())));
200 O
.SymTable
.Symbols
.push_back(std::make_unique
<SymbolEntry
>(SE
));
204 void MachOReader::setSymbolInRelocationInfo(Object
&O
) const {
205 for (auto &LC
: O
.LoadCommands
)
206 for (auto &Sec
: LC
.Sections
)
207 for (auto &Reloc
: Sec
.Relocations
)
208 if (!Reloc
.Scattered
) {
209 auto *Info
= reinterpret_cast<MachO::relocation_info
*>(&Reloc
.Info
);
210 Reloc
.Symbol
= O
.SymTable
.getSymbolByIndex(Info
->r_symbolnum
);
214 void MachOReader::readRebaseInfo(Object
&O
) const {
215 O
.Rebases
.Opcodes
= MachOObj
.getDyldInfoRebaseOpcodes();
218 void MachOReader::readBindInfo(Object
&O
) const {
219 O
.Binds
.Opcodes
= MachOObj
.getDyldInfoBindOpcodes();
222 void MachOReader::readWeakBindInfo(Object
&O
) const {
223 O
.WeakBinds
.Opcodes
= MachOObj
.getDyldInfoWeakBindOpcodes();
226 void MachOReader::readLazyBindInfo(Object
&O
) const {
227 O
.LazyBinds
.Opcodes
= MachOObj
.getDyldInfoLazyBindOpcodes();
230 void MachOReader::readExportInfo(Object
&O
) const {
231 O
.Exports
.Trie
= MachOObj
.getDyldInfoExportsTrie();
234 void MachOReader::readDataInCodeData(Object
&O
) const {
235 if (!O
.DataInCodeCommandIndex
)
237 const MachO::linkedit_data_command
&LDC
=
238 O
.LoadCommands
[*O
.DataInCodeCommandIndex
]
239 .MachOLoadCommand
.linkedit_data_command_data
;
241 O
.DataInCode
.Data
= arrayRefFromStringRef(
242 MachOObj
.getData().substr(LDC
.dataoff
, LDC
.datasize
));
245 void MachOReader::readFunctionStartsData(Object
&O
) const {
246 if (!O
.FunctionStartsCommandIndex
)
248 const MachO::linkedit_data_command
&LDC
=
249 O
.LoadCommands
[*O
.FunctionStartsCommandIndex
]
250 .MachOLoadCommand
.linkedit_data_command_data
;
252 O
.FunctionStarts
.Data
= arrayRefFromStringRef(
253 MachOObj
.getData().substr(LDC
.dataoff
, LDC
.datasize
));
256 void MachOReader::readIndirectSymbolTable(Object
&O
) const {
257 MachO::dysymtab_command DySymTab
= MachOObj
.getDysymtabLoadCommand();
258 for (uint32_t i
= 0; i
< DySymTab
.nindirectsyms
; ++i
)
259 O
.IndirectSymTable
.Symbols
.push_back(
260 MachOObj
.getIndirectSymbolTableEntry(DySymTab
, i
));
263 std::unique_ptr
<Object
> MachOReader::create() const {
264 auto Obj
= std::make_unique
<Object
>();
266 readLoadCommands(*Obj
);
267 readSymbolTable(*Obj
);
268 setSymbolInRelocationInfo(*Obj
);
269 readRebaseInfo(*Obj
);
271 readWeakBindInfo(*Obj
);
272 readLazyBindInfo(*Obj
);
273 readExportInfo(*Obj
);
274 readDataInCodeData(*Obj
);
275 readFunctionStartsData(*Obj
);
276 readIndirectSymbolTable(*Obj
);
280 } // end namespace macho
281 } // end namespace objcopy
282 } // end namespace llvm