1 //===- MachOWriter.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 "MachOWriter.h"
10 #include "MachOLayoutBuilder.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/BinaryFormat/MachO.h"
14 #include "llvm/Object/MachO.h"
15 #include "llvm/Support/Errc.h"
16 #include "llvm/Support/ErrorHandling.h"
23 size_t MachOWriter::headerSize() const {
24 return Is64Bit
? sizeof(MachO::mach_header_64
) : sizeof(MachO::mach_header
);
27 size_t MachOWriter::loadCommandsSize() const { return O
.Header
.SizeOfCmds
; }
29 size_t MachOWriter::symTableSize() const {
30 return O
.SymTable
.Symbols
.size() *
31 (Is64Bit
? sizeof(MachO::nlist_64
) : sizeof(MachO::nlist
));
34 size_t MachOWriter::totalSize() const {
35 // Going from tail to head and looking for an appropriate "anchor" to
36 // calculate the total size assuming that all the offsets are either valid
37 // ("true") or 0 (0 indicates that the corresponding part is missing).
39 SmallVector
<size_t, 7> Ends
;
40 if (O
.SymTabCommandIndex
) {
41 const MachO::symtab_command
&SymTabCommand
=
42 O
.LoadCommands
[*O
.SymTabCommandIndex
]
43 .MachOLoadCommand
.symtab_command_data
;
44 if (SymTabCommand
.symoff
)
45 Ends
.push_back(SymTabCommand
.symoff
+ symTableSize());
46 if (SymTabCommand
.stroff
)
47 Ends
.push_back(SymTabCommand
.stroff
+ SymTabCommand
.strsize
);
49 if (O
.DyLdInfoCommandIndex
) {
50 const MachO::dyld_info_command
&DyLdInfoCommand
=
51 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
52 .MachOLoadCommand
.dyld_info_command_data
;
53 if (DyLdInfoCommand
.rebase_off
) {
54 assert((DyLdInfoCommand
.rebase_size
== O
.Rebases
.Opcodes
.size()) &&
55 "Incorrect rebase opcodes size");
56 Ends
.push_back(DyLdInfoCommand
.rebase_off
+ DyLdInfoCommand
.rebase_size
);
58 if (DyLdInfoCommand
.bind_off
) {
59 assert((DyLdInfoCommand
.bind_size
== O
.Binds
.Opcodes
.size()) &&
60 "Incorrect bind opcodes size");
61 Ends
.push_back(DyLdInfoCommand
.bind_off
+ DyLdInfoCommand
.bind_size
);
63 if (DyLdInfoCommand
.weak_bind_off
) {
64 assert((DyLdInfoCommand
.weak_bind_size
== O
.WeakBinds
.Opcodes
.size()) &&
65 "Incorrect weak bind opcodes size");
66 Ends
.push_back(DyLdInfoCommand
.weak_bind_off
+
67 DyLdInfoCommand
.weak_bind_size
);
69 if (DyLdInfoCommand
.lazy_bind_off
) {
70 assert((DyLdInfoCommand
.lazy_bind_size
== O
.LazyBinds
.Opcodes
.size()) &&
71 "Incorrect lazy bind opcodes size");
72 Ends
.push_back(DyLdInfoCommand
.lazy_bind_off
+
73 DyLdInfoCommand
.lazy_bind_size
);
75 if (DyLdInfoCommand
.export_off
) {
76 assert((DyLdInfoCommand
.export_size
== O
.Exports
.Trie
.size()) &&
77 "Incorrect trie size");
78 Ends
.push_back(DyLdInfoCommand
.export_off
+ DyLdInfoCommand
.export_size
);
82 if (O
.DySymTabCommandIndex
) {
83 const MachO::dysymtab_command
&DySymTabCommand
=
84 O
.LoadCommands
[*O
.DySymTabCommandIndex
]
85 .MachOLoadCommand
.dysymtab_command_data
;
87 if (DySymTabCommand
.indirectsymoff
)
88 Ends
.push_back(DySymTabCommand
.indirectsymoff
+
89 sizeof(uint32_t) * O
.IndirectSymTable
.Symbols
.size());
92 if (O
.DataInCodeCommandIndex
) {
93 const MachO::linkedit_data_command
&LinkEditDataCommand
=
94 O
.LoadCommands
[*O
.DataInCodeCommandIndex
]
95 .MachOLoadCommand
.linkedit_data_command_data
;
97 if (LinkEditDataCommand
.dataoff
)
98 Ends
.push_back(LinkEditDataCommand
.dataoff
+
99 LinkEditDataCommand
.datasize
);
102 if (O
.FunctionStartsCommandIndex
) {
103 const MachO::linkedit_data_command
&LinkEditDataCommand
=
104 O
.LoadCommands
[*O
.FunctionStartsCommandIndex
]
105 .MachOLoadCommand
.linkedit_data_command_data
;
107 if (LinkEditDataCommand
.dataoff
)
108 Ends
.push_back(LinkEditDataCommand
.dataoff
+
109 LinkEditDataCommand
.datasize
);
112 // Otherwise, use the last section / reloction.
113 for (const auto &LC
: O
.LoadCommands
)
114 for (const auto &S
: LC
.Sections
) {
115 Ends
.push_back(S
.Offset
+ S
.Size
);
117 Ends
.push_back(S
.RelOff
+
118 S
.NReloc
* sizeof(MachO::any_relocation_info
));
122 return *std::max_element(Ends
.begin(), Ends
.end());
124 // Otherwise, we have only Mach header and load commands.
125 return headerSize() + loadCommandsSize();
128 void MachOWriter::writeHeader() {
129 MachO::mach_header_64 Header
;
131 Header
.magic
= O
.Header
.Magic
;
132 Header
.cputype
= O
.Header
.CPUType
;
133 Header
.cpusubtype
= O
.Header
.CPUSubType
;
134 Header
.filetype
= O
.Header
.FileType
;
135 Header
.ncmds
= O
.Header
.NCmds
;
136 Header
.sizeofcmds
= O
.Header
.SizeOfCmds
;
137 Header
.flags
= O
.Header
.Flags
;
138 Header
.reserved
= O
.Header
.Reserved
;
140 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
141 MachO::swapStruct(Header
);
144 Is64Bit
? sizeof(MachO::mach_header_64
) : sizeof(MachO::mach_header
);
145 memcpy(B
.getBufferStart(), &Header
, HeaderSize
);
148 void MachOWriter::writeLoadCommands() {
149 uint8_t *Begin
= B
.getBufferStart() + headerSize();
150 for (const auto &LC
: O
.LoadCommands
) {
151 // Construct a load command.
152 MachO::macho_load_command MLC
= LC
.MachOLoadCommand
;
153 switch (MLC
.load_command_data
.cmd
) {
154 case MachO::LC_SEGMENT
:
155 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
156 MachO::swapStruct(MLC
.segment_command_data
);
157 memcpy(Begin
, &MLC
.segment_command_data
, sizeof(MachO::segment_command
));
158 Begin
+= sizeof(MachO::segment_command
);
160 for (const auto &Sec
: LC
.Sections
)
161 writeSectionInLoadCommand
<MachO::section
>(Sec
, Begin
);
163 case MachO::LC_SEGMENT_64
:
164 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
165 MachO::swapStruct(MLC
.segment_command_64_data
);
166 memcpy(Begin
, &MLC
.segment_command_64_data
,
167 sizeof(MachO::segment_command_64
));
168 Begin
+= sizeof(MachO::segment_command_64
);
170 for (const auto &Sec
: LC
.Sections
)
171 writeSectionInLoadCommand
<MachO::section_64
>(Sec
, Begin
);
175 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
176 case MachO::LCName: \
177 assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
178 MLC.load_command_data.cmdsize); \
179 if (IsLittleEndian != sys::IsLittleEndianHost) \
180 MachO::swapStruct(MLC.LCStruct##_data); \
181 memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
182 Begin += sizeof(MachO::LCStruct); \
183 memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
184 Begin += LC.Payload.size(); \
187 // Copy the load command as it is.
188 switch (MLC
.load_command_data
.cmd
) {
190 assert(sizeof(MachO::load_command
) + LC
.Payload
.size() ==
191 MLC
.load_command_data
.cmdsize
);
192 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
193 MachO::swapStruct(MLC
.load_command_data
);
194 memcpy(Begin
, &MLC
.load_command_data
, sizeof(MachO::load_command
));
195 Begin
+= sizeof(MachO::load_command
);
196 memcpy(Begin
, LC
.Payload
.data(), LC
.Payload
.size());
197 Begin
+= LC
.Payload
.size();
199 #include "llvm/BinaryFormat/MachO.def"
204 template <typename StructType
>
205 void MachOWriter::writeSectionInLoadCommand(const Section
&Sec
, uint8_t *&Out
) {
207 assert(Sec
.Segname
.size() <= sizeof(Temp
.segname
) && "too long segment name");
208 assert(Sec
.Sectname
.size() <= sizeof(Temp
.sectname
) &&
209 "too long section name");
210 memset(&Temp
, 0, sizeof(StructType
));
211 memcpy(Temp
.segname
, Sec
.Segname
.data(), Sec
.Segname
.size());
212 memcpy(Temp
.sectname
, Sec
.Sectname
.data(), Sec
.Sectname
.size());
213 Temp
.addr
= Sec
.Addr
;
214 Temp
.size
= Sec
.Size
;
215 Temp
.offset
= Sec
.Offset
;
216 Temp
.align
= Sec
.Align
;
217 Temp
.reloff
= Sec
.RelOff
;
218 Temp
.nreloc
= Sec
.NReloc
;
219 Temp
.flags
= Sec
.Flags
;
220 Temp
.reserved1
= Sec
.Reserved1
;
221 Temp
.reserved2
= Sec
.Reserved2
;
223 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
224 MachO::swapStruct(Temp
);
225 memcpy(Out
, &Temp
, sizeof(StructType
));
226 Out
+= sizeof(StructType
);
229 void MachOWriter::writeSections() {
230 for (const auto &LC
: O
.LoadCommands
)
231 for (const auto &Sec
: LC
.Sections
) {
232 if (Sec
.isVirtualSection())
235 assert(Sec
.Offset
&& "Section offset can not be zero");
236 assert((Sec
.Size
== Sec
.Content
.size()) && "Incorrect section size");
237 memcpy(B
.getBufferStart() + Sec
.Offset
, Sec
.Content
.data(),
239 for (size_t Index
= 0; Index
< Sec
.Relocations
.size(); ++Index
) {
240 auto RelocInfo
= Sec
.Relocations
[Index
];
241 if (!RelocInfo
.Scattered
) {
243 reinterpret_cast<MachO::relocation_info
*>(&RelocInfo
.Info
);
244 Info
->r_symbolnum
= RelocInfo
.Symbol
->Index
;
247 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
249 reinterpret_cast<MachO::any_relocation_info
&>(RelocInfo
.Info
));
250 memcpy(B
.getBufferStart() + Sec
.RelOff
+
251 Index
* sizeof(MachO::any_relocation_info
),
252 &RelocInfo
.Info
, sizeof(RelocInfo
.Info
));
257 template <typename NListType
>
258 void writeNListEntry(const SymbolEntry
&SE
, bool IsLittleEndian
, char *&Out
,
261 ListEntry
.n_strx
= Nstrx
;
262 ListEntry
.n_type
= SE
.n_type
;
263 ListEntry
.n_sect
= SE
.n_sect
;
264 ListEntry
.n_desc
= SE
.n_desc
;
265 ListEntry
.n_value
= SE
.n_value
;
267 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
268 MachO::swapStruct(ListEntry
);
269 memcpy(Out
, reinterpret_cast<const char *>(&ListEntry
), sizeof(NListType
));
270 Out
+= sizeof(NListType
);
273 void MachOWriter::writeStringTable() {
274 if (!O
.SymTabCommandIndex
)
276 const MachO::symtab_command
&SymTabCommand
=
277 O
.LoadCommands
[*O
.SymTabCommandIndex
]
278 .MachOLoadCommand
.symtab_command_data
;
280 uint8_t *StrTable
= (uint8_t *)B
.getBufferStart() + SymTabCommand
.stroff
;
281 LayoutBuilder
.getStringTableBuilder().write(StrTable
);
284 void MachOWriter::writeSymbolTable() {
285 if (!O
.SymTabCommandIndex
)
287 const MachO::symtab_command
&SymTabCommand
=
288 O
.LoadCommands
[*O
.SymTabCommandIndex
]
289 .MachOLoadCommand
.symtab_command_data
;
291 char *SymTable
= (char *)B
.getBufferStart() + SymTabCommand
.symoff
;
292 for (auto Iter
= O
.SymTable
.Symbols
.begin(), End
= O
.SymTable
.Symbols
.end();
293 Iter
!= End
; Iter
++) {
294 SymbolEntry
*Sym
= Iter
->get();
295 uint32_t Nstrx
= LayoutBuilder
.getStringTableBuilder().getOffset(Sym
->Name
);
298 writeNListEntry
<MachO::nlist_64
>(*Sym
, IsLittleEndian
, SymTable
, Nstrx
);
300 writeNListEntry
<MachO::nlist
>(*Sym
, IsLittleEndian
, SymTable
, Nstrx
);
304 void MachOWriter::writeRebaseInfo() {
305 if (!O
.DyLdInfoCommandIndex
)
307 const MachO::dyld_info_command
&DyLdInfoCommand
=
308 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
309 .MachOLoadCommand
.dyld_info_command_data
;
310 char *Out
= (char *)B
.getBufferStart() + DyLdInfoCommand
.rebase_off
;
311 assert((DyLdInfoCommand
.rebase_size
== O
.Rebases
.Opcodes
.size()) &&
312 "Incorrect rebase opcodes size");
313 memcpy(Out
, O
.Rebases
.Opcodes
.data(), O
.Rebases
.Opcodes
.size());
316 void MachOWriter::writeBindInfo() {
317 if (!O
.DyLdInfoCommandIndex
)
319 const MachO::dyld_info_command
&DyLdInfoCommand
=
320 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
321 .MachOLoadCommand
.dyld_info_command_data
;
322 char *Out
= (char *)B
.getBufferStart() + DyLdInfoCommand
.bind_off
;
323 assert((DyLdInfoCommand
.bind_size
== O
.Binds
.Opcodes
.size()) &&
324 "Incorrect bind opcodes size");
325 memcpy(Out
, O
.Binds
.Opcodes
.data(), O
.Binds
.Opcodes
.size());
328 void MachOWriter::writeWeakBindInfo() {
329 if (!O
.DyLdInfoCommandIndex
)
331 const MachO::dyld_info_command
&DyLdInfoCommand
=
332 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
333 .MachOLoadCommand
.dyld_info_command_data
;
334 char *Out
= (char *)B
.getBufferStart() + DyLdInfoCommand
.weak_bind_off
;
335 assert((DyLdInfoCommand
.weak_bind_size
== O
.WeakBinds
.Opcodes
.size()) &&
336 "Incorrect weak bind opcodes size");
337 memcpy(Out
, O
.WeakBinds
.Opcodes
.data(), O
.WeakBinds
.Opcodes
.size());
340 void MachOWriter::writeLazyBindInfo() {
341 if (!O
.DyLdInfoCommandIndex
)
343 const MachO::dyld_info_command
&DyLdInfoCommand
=
344 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
345 .MachOLoadCommand
.dyld_info_command_data
;
346 char *Out
= (char *)B
.getBufferStart() + DyLdInfoCommand
.lazy_bind_off
;
347 assert((DyLdInfoCommand
.lazy_bind_size
== O
.LazyBinds
.Opcodes
.size()) &&
348 "Incorrect lazy bind opcodes size");
349 memcpy(Out
, O
.LazyBinds
.Opcodes
.data(), O
.LazyBinds
.Opcodes
.size());
352 void MachOWriter::writeExportInfo() {
353 if (!O
.DyLdInfoCommandIndex
)
355 const MachO::dyld_info_command
&DyLdInfoCommand
=
356 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
357 .MachOLoadCommand
.dyld_info_command_data
;
358 char *Out
= (char *)B
.getBufferStart() + DyLdInfoCommand
.export_off
;
359 assert((DyLdInfoCommand
.export_size
== O
.Exports
.Trie
.size()) &&
360 "Incorrect export trie size");
361 memcpy(Out
, O
.Exports
.Trie
.data(), O
.Exports
.Trie
.size());
364 void MachOWriter::writeIndirectSymbolTable() {
365 if (!O
.DySymTabCommandIndex
)
368 const MachO::dysymtab_command
&DySymTabCommand
=
369 O
.LoadCommands
[*O
.DySymTabCommandIndex
]
370 .MachOLoadCommand
.dysymtab_command_data
;
372 char *Out
= (char *)B
.getBufferStart() + DySymTabCommand
.indirectsymoff
;
373 assert((DySymTabCommand
.nindirectsyms
== O
.IndirectSymTable
.Symbols
.size()) &&
374 "Incorrect indirect symbol table size");
375 memcpy(Out
, O
.IndirectSymTable
.Symbols
.data(),
376 sizeof(uint32_t) * O
.IndirectSymTable
.Symbols
.size());
379 void MachOWriter::writeDataInCodeData() {
380 if (!O
.DataInCodeCommandIndex
)
382 const MachO::linkedit_data_command
&LinkEditDataCommand
=
383 O
.LoadCommands
[*O
.DataInCodeCommandIndex
]
384 .MachOLoadCommand
.linkedit_data_command_data
;
385 char *Out
= (char *)B
.getBufferStart() + LinkEditDataCommand
.dataoff
;
386 assert((LinkEditDataCommand
.datasize
== O
.DataInCode
.Data
.size()) &&
387 "Incorrect data in code data size");
388 memcpy(Out
, O
.DataInCode
.Data
.data(), O
.DataInCode
.Data
.size());
391 void MachOWriter::writeFunctionStartsData() {
392 if (!O
.FunctionStartsCommandIndex
)
394 const MachO::linkedit_data_command
&LinkEditDataCommand
=
395 O
.LoadCommands
[*O
.FunctionStartsCommandIndex
]
396 .MachOLoadCommand
.linkedit_data_command_data
;
397 char *Out
= (char *)B
.getBufferStart() + LinkEditDataCommand
.dataoff
;
398 assert((LinkEditDataCommand
.datasize
== O
.FunctionStarts
.Data
.size()) &&
399 "Incorrect function starts data size");
400 memcpy(Out
, O
.FunctionStarts
.Data
.data(), O
.FunctionStarts
.Data
.size());
403 void MachOWriter::writeTail() {
404 typedef void (MachOWriter::*WriteHandlerType
)(void);
405 typedef std::pair
<uint64_t, WriteHandlerType
> WriteOperation
;
406 SmallVector
<WriteOperation
, 7> Queue
;
408 if (O
.SymTabCommandIndex
) {
409 const MachO::symtab_command
&SymTabCommand
=
410 O
.LoadCommands
[*O
.SymTabCommandIndex
]
411 .MachOLoadCommand
.symtab_command_data
;
412 if (SymTabCommand
.symoff
)
413 Queue
.push_back({SymTabCommand
.symoff
, &MachOWriter::writeSymbolTable
});
414 if (SymTabCommand
.stroff
)
415 Queue
.push_back({SymTabCommand
.stroff
, &MachOWriter::writeStringTable
});
418 if (O
.DyLdInfoCommandIndex
) {
419 const MachO::dyld_info_command
&DyLdInfoCommand
=
420 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
421 .MachOLoadCommand
.dyld_info_command_data
;
422 if (DyLdInfoCommand
.rebase_off
)
424 {DyLdInfoCommand
.rebase_off
, &MachOWriter::writeRebaseInfo
});
425 if (DyLdInfoCommand
.bind_off
)
426 Queue
.push_back({DyLdInfoCommand
.bind_off
, &MachOWriter::writeBindInfo
});
427 if (DyLdInfoCommand
.weak_bind_off
)
429 {DyLdInfoCommand
.weak_bind_off
, &MachOWriter::writeWeakBindInfo
});
430 if (DyLdInfoCommand
.lazy_bind_off
)
432 {DyLdInfoCommand
.lazy_bind_off
, &MachOWriter::writeLazyBindInfo
});
433 if (DyLdInfoCommand
.export_off
)
435 {DyLdInfoCommand
.export_off
, &MachOWriter::writeExportInfo
});
438 if (O
.DySymTabCommandIndex
) {
439 const MachO::dysymtab_command
&DySymTabCommand
=
440 O
.LoadCommands
[*O
.DySymTabCommandIndex
]
441 .MachOLoadCommand
.dysymtab_command_data
;
443 if (DySymTabCommand
.indirectsymoff
)
444 Queue
.emplace_back(DySymTabCommand
.indirectsymoff
,
445 &MachOWriter::writeIndirectSymbolTable
);
448 if (O
.DataInCodeCommandIndex
) {
449 const MachO::linkedit_data_command
&LinkEditDataCommand
=
450 O
.LoadCommands
[*O
.DataInCodeCommandIndex
]
451 .MachOLoadCommand
.linkedit_data_command_data
;
453 if (LinkEditDataCommand
.dataoff
)
454 Queue
.emplace_back(LinkEditDataCommand
.dataoff
,
455 &MachOWriter::writeDataInCodeData
);
458 if (O
.FunctionStartsCommandIndex
) {
459 const MachO::linkedit_data_command
&LinkEditDataCommand
=
460 O
.LoadCommands
[*O
.FunctionStartsCommandIndex
]
461 .MachOLoadCommand
.linkedit_data_command_data
;
463 if (LinkEditDataCommand
.dataoff
)
464 Queue
.emplace_back(LinkEditDataCommand
.dataoff
,
465 &MachOWriter::writeFunctionStartsData
);
468 llvm::sort(Queue
, [](const WriteOperation
&LHS
, const WriteOperation
&RHS
) {
469 return LHS
.first
< RHS
.first
;
472 for (auto WriteOp
: Queue
)
473 (this->*WriteOp
.second
)();
476 Error
MachOWriter::finalize() { return LayoutBuilder
.layout(); }
478 Error
MachOWriter::write() {
479 if (Error E
= B
.allocate(totalSize()))
481 memset(B
.getBufferStart(), 0, totalSize());
489 } // end namespace macho
490 } // end namespace objcopy
491 } // end namespace llvm