28size_t MachOWriter::headerSize()
const {
34size_t MachOWriter::symTableSize()
const {
48 .MachOLoadCommand.symtab_command_data;
57 .MachOLoadCommand.dyld_info_command_data;
60 "Incorrect rebase opcodes size");
65 "Incorrect bind opcodes size");
70 "Incorrect weak bind opcodes size");
76 "Incorrect lazy bind opcodes size");
82 "Incorrect trie size");
90 .MachOLoadCommand.dysymtab_command_data;
97 for (std::optional<size_t> LinkEditDataCommandIndex :
102 if (LinkEditDataCommandIndex) {
105 .MachOLoadCommand.linkedit_data_command_data;
106 if (LinkEditDataCommand.
dataoff)
113 for (
const std::unique_ptr<Section> &S : LC.
Sections) {
114 if (!S->hasValidOffset()) {
115 assert((S->Offset == 0) &&
"Skipped section's offset must be zero");
116 assert((S->isVirtualSection() || S->Size == 0) &&
117 "Non-zero-fill sections with zero offset must have zero size");
120 assert((S->Offset != 0) &&
121 "Non-zero-fill section's offset cannot be zero");
132 return headerSize() + loadCommandsSize();
135void MachOWriter::writeHeader() {
152 memcpy(Buf->getBufferStart(), &Header, HeaderSize);
155void MachOWriter::writeLoadCommands() {
157 reinterpret_cast<uint8_t *
>(Buf->getBufferStart()) + headerSize();
161 switch (MLC.load_command_data.cmd) {
162 case MachO::LC_SEGMENT:
168 for (
const std::unique_ptr<Section> &Sec : LC.
Sections)
169 writeSectionInLoadCommand<MachO::section>(*Sec, Begin);
171 case MachO::LC_SEGMENT_64:
174 memcpy(Begin, &MLC.segment_command_64_data,
178 for (
const std::unique_ptr<Section> &Sec : LC.
Sections)
179 writeSectionInLoadCommand<MachO::section_64>(*Sec, Begin);
183#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
184 case MachO::LCName: \
185 assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
186 MLC.load_command_data.cmdsize); \
187 if (IsLittleEndian != sys::IsLittleEndianHost) \
188 MachO::swapStruct(MLC.LCStruct##_data); \
189 memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
190 Begin += sizeof(MachO::LCStruct); \
191 if (!LC.Payload.empty()) \
192 memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
193 Begin += LC.Payload.size(); \
197 switch (MLC.load_command_data.cmd) {
200 MLC.load_command_data.cmdsize);
209#include "llvm/BinaryFormat/MachO.def"
214template <
typename StructType>
215void MachOWriter::writeSectionInLoadCommand(
const Section &Sec, uint8_t *&Out) {
217 assert(Sec.
Segname.size() <=
sizeof(Temp.segname) &&
"too long segment name");
219 "too long section name");
223 Temp.addr = Sec.
Addr;
224 Temp.size = Sec.
Size;
226 Temp.align = Sec.
Align;
229 Temp.flags = Sec.
Flags;
239void MachOWriter::writeSections() {
241 for (
const std::unique_ptr<Section> &Sec : LC.
Sections) {
242 if (!Sec->hasValidOffset()) {
243 assert((Sec->Offset == 0) &&
"Skipped section's offset must be zero");
244 assert((Sec->isVirtualSection() || Sec->Size == 0) &&
245 "Non-zero-fill sections with zero offset must have zero size");
249 assert(Sec->Offset &&
"Section offset can not be zero");
250 assert((Sec->Size == Sec->Content.size()) &&
"Incorrect section size");
251 memcpy(Buf->getBufferStart() + Sec->Offset, Sec->Content.data(),
252 Sec->Content.size());
258 : (*RelocInfo.
Sec)->Index;
264 memcpy(Buf->getBufferStart() + Sec->RelOff +
266 &RelocInfo.
Info,
sizeof(RelocInfo.
Info));
271template <
typename NListType>
275 ListEntry.n_strx = Nstrx;
276 ListEntry.n_type = SE.
n_type;
277 ListEntry.n_sect = SE.
n_sect;
278 ListEntry.n_desc = SE.
n_desc;
279 ListEntry.n_value = SE.
n_value;
283 memcpy(Out,
reinterpret_cast<const char *
>(&ListEntry),
sizeof(NListType));
284 Out +=
sizeof(NListType);
287void MachOWriter::writeStringTable() {
292 .MachOLoadCommand.symtab_command_data;
294 uint8_t *StrTable = (uint8_t *)Buf->getBufferStart() + SymTabCommand.
stroff;
298void MachOWriter::writeSymbolTable() {
303 .MachOLoadCommand.symtab_command_data;
305 char *SymTable = (
char *)Buf->getBufferStart() + SymTabCommand.
symoff;
311 writeNListEntry<MachO::nlist_64>(*
Sym, IsLittleEndian, SymTable, Nstrx);
313 writeNListEntry<MachO::nlist>(*
Sym, IsLittleEndian, SymTable, Nstrx);
317void MachOWriter::writeRebaseInfo() {
322 .MachOLoadCommand.dyld_info_command_data;
323 char *Out = (
char *)Buf->getBufferStart() + DyLdInfoCommand.
rebase_off;
325 "Incorrect rebase opcodes size");
329void MachOWriter::writeBindInfo() {
334 .MachOLoadCommand.dyld_info_command_data;
335 char *Out = (
char *)Buf->getBufferStart() + DyLdInfoCommand.
bind_off;
337 "Incorrect bind opcodes size");
341void MachOWriter::writeWeakBindInfo() {
346 .MachOLoadCommand.dyld_info_command_data;
347 char *Out = (
char *)Buf->getBufferStart() + DyLdInfoCommand.
weak_bind_off;
349 "Incorrect weak bind opcodes size");
353void MachOWriter::writeLazyBindInfo() {
358 .MachOLoadCommand.dyld_info_command_data;
359 char *Out = (
char *)Buf->getBufferStart() + DyLdInfoCommand.
lazy_bind_off;
361 "Incorrect lazy bind opcodes size");
365void MachOWriter::writeExportInfo() {
370 .MachOLoadCommand.dyld_info_command_data;
371 char *Out = (
char *)Buf->getBufferStart() + DyLdInfoCommand.
export_off;
373 "Incorrect export trie size");
377void MachOWriter::writeIndirectSymbolTable() {
383 .MachOLoadCommand.dysymtab_command_data;
395void MachOWriter::writeLinkData(std::optional<size_t> LCIndex,
400 O.
LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data;
401 char *Out = (
char *)Buf->getBufferStart() + LinkEditDataCommand.
dataoff;
403 "Incorrect data size");
404 memcpy(Out,
LD.Data.data(),
LD.Data.size());
411 switch (MLC.load_command_data.cmd) {
412 case MachO::LC_SEGMENT:
413 return MLC.segment_command_data.fileoff;
414 case MachO::LC_SEGMENT_64:
415 return MLC.segment_command_64_data.fileoff;
424 switch (MLC.load_command_data.cmd) {
425 case MachO::LC_SEGMENT:
426 return MLC.segment_command_data.filesize;
427 case MachO::LC_SEGMENT_64:
428 return MLC.segment_command_64_data.filesize;
434void MachOWriter::writeCodeSignatureData() {
450 uint8_t *BufferStart =
reinterpret_cast<uint8_t *
>(Buf->getBufferStart());
451 uint8_t *HashReadStart = BufferStart;
452 uint8_t *HashReadEnd = BufferStart + CodeSignature.
StartOffset;
456 uint8_t *HashWriteStart = HashReadEnd + CodeSignature.
AllHeadersSize;
466 MachO::LC_SEGMENT_64);
468 .segment_command_data.segname) ==
"__TEXT");
496 CodeDirectory->nSpecialSlots = 0;
499 CodeDirectory->hashSize =
static_cast<uint8_t
>(CodeSignature.
HashSize);
501 CodeDirectory->platform = 0;
503 CodeDirectory->spare2 = 0;
504 CodeDirectory->scatterOffset = 0;
505 CodeDirectory->teamOffset = 0;
506 CodeDirectory->spare3 = 0;
507 CodeDirectory->codeLimit64 = 0;
508 write64be(&CodeDirectory->execSegBase, TextSegmentFileOff);
509 write64be(&CodeDirectory->execSegLimit, TextSegmentFileSize);
514 auto *
Id =
reinterpret_cast<char *
>(&CodeDirectory[1]);
520 uint8_t *CurrHashReadPosition = HashReadStart;
521 uint8_t *CurrHashWritePosition = HashWriteStart;
522 while (CurrHashReadPosition < HashReadEnd) {
524 std::min(
static_cast<size_t>(HashReadEnd
525 - CurrHashReadPosition),
526 static_cast<size_t>(CodeSignature.
BlockSize)));
529 std::array<uint8_t, 32> Hash = Hasher.
final();
531 memcpy(CurrHashWritePosition, Hash.data(), CodeSignature.
HashSize);
532 CurrHashReadPosition += CodeSignature.
BlockSize;
533 CurrHashWritePosition += CodeSignature.
HashSize;
535#if defined(__APPLE__)
551void MachOWriter::writeDataInCodeData() {
555void MachOWriter::writeLinkerOptimizationHint() {
560void MachOWriter::writeFunctionStartsData() {
564void MachOWriter::writeDylibCodeSignDRsData() {
568void MachOWriter::writeChainedFixupsData() {
572void MachOWriter::writeExportsTrieData() {
577 .MachOLoadCommand.linkedit_data_command_data;
578 char *Out = (
char *)Buf->getBufferStart() + ExportsTrieCmd.
dataoff;
580 "Incorrect export trie size");
584void MachOWriter::writeTail() {
586 typedef std::pair<uint64_t, WriteHandlerType> WriteOperation;
592 .MachOLoadCommand.symtab_command_data;
594 Queue.push_back({SymTabCommand.
symoff, &MachOWriter::writeSymbolTable});
596 Queue.push_back({SymTabCommand.
stroff, &MachOWriter::writeStringTable});
602 .MachOLoadCommand.dyld_info_command_data;
605 {DyLdInfoCommand.
rebase_off, &MachOWriter::writeRebaseInfo});
607 Queue.push_back({DyLdInfoCommand.
bind_off, &MachOWriter::writeBindInfo});
610 {DyLdInfoCommand.
weak_bind_off, &MachOWriter::writeWeakBindInfo});
613 {DyLdInfoCommand.
lazy_bind_off, &MachOWriter::writeLazyBindInfo});
616 {DyLdInfoCommand.
export_off, &MachOWriter::writeExportInfo});
622 .MachOLoadCommand.dysymtab_command_data;
626 &MachOWriter::writeIndirectSymbolTable);
629 std::initializer_list<std::pair<std::optional<size_t>, WriteHandlerType>>
630 LinkEditDataCommandWriters = {
635 &MachOWriter::writeLinkerOptimizationHint},
639 for (
const auto &W : LinkEditDataCommandWriters) {
640 std::optional<size_t> LinkEditDataCommandIndex;
641 WriteHandlerType WriteHandler;
642 std::tie(LinkEditDataCommandIndex, WriteHandler) =
W;
643 if (LinkEditDataCommandIndex) {
646 .MachOLoadCommand.linkedit_data_command_data;
647 if (LinkEditDataCommand.
dataoff)
648 Queue.emplace_back(LinkEditDataCommand.
dataoff, WriteHandler);
654 for (
auto WriteOp : Queue)
655 (this->*WriteOp.second)();
665 "failed to allocate memory buffer of " +
674 Out.write(Buf->getBufferStart(), Buf->getBufferSize());
static uint64_t getSegmentFileOffset(const LoadCommand &TextSegmentLoadCommand)
static uint64_t getSegmentFileSize(const LoadCommand &TextSegmentLoadCommand)
void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out, uint32_t Nstrx)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
size_t size() const
size - Get the array size.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
std::array< uint8_t, 32 > final()
Return the current raw 256-bits SHA256 for the digested data since the last call to init().
void update(ArrayRef< uint8_t > Data)
Digest more data.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
constexpr size_t size() const
size - Get the string size.
size_t getOffset(CachedHashStringRef S) const
Get the offest of a string in the string table.
void write(raw_ostream &OS) const
Class to represent struct types.
static Twine utohexstr(const uint64_t &Val)
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
StringTableBuilder & getStringTableBuilder()
const CodeSignatureInfo & getCodeSignature() const
@ CSMAGIC_EMBEDDED_SIGNATURE
@ kSecCodeSignatureHashSHA256
void swapStruct(fat_header &mh)
void write32be(void *P, uint32_t V)
void write64be(void *P, uint64_t V)
static const bool IsLittleEndianHost
void swapByteOrder(T &Value)
This is an optimization pass for GlobalISel generic memory operations.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
void sort(IteratorTy Start, IteratorTy End)
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
Function object to check whether the first component of a container supported by std::get (like std::...
ArrayRef< uint8_t > Opcodes
When MachO binaries include a LC_CODE_SIGNATURE load command, the __LINKEDIT data segment will includ...
static constexpr size_t BlobHeadersSize
static constexpr size_t HashSize
static constexpr uint32_t FixedHeadersSize
static constexpr uint8_t BlockSizeShift
static constexpr size_t BlockSize
std::vector< IndirectSymbolEntry > Symbols
ArrayRef< uint8_t > Opcodes
MachO::macho_load_command MachOLoadCommand
std::vector< std::unique_ptr< Section > > Sections
std::vector< uint8_t > Payload
std::optional< size_t > FunctionStartsCommandIndex
The index LC_FUNCTION_STARTS load command if present.
std::optional< size_t > ChainedFixupsCommandIndex
The index LC_DYLD_CHAINED_FIXUPS load command if present.
std::optional< size_t > ExportsTrieCommandIndex
The index LC_DYLD_EXPORTS_TRIE load command if present.
std::optional< size_t > DylibCodeSignDRsIndex
The index of LC_DYLIB_CODE_SIGN_DRS load command if present.
std::optional< size_t > SymTabCommandIndex
The index of LC_SYMTAB load command if present.
std::optional< size_t > DyLdInfoCommandIndex
The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.
std::vector< LoadCommand > LoadCommands
std::optional< size_t > DataInCodeCommandIndex
The index LC_DATA_IN_CODE load command if present.
std::optional< size_t > DySymTabCommandIndex
The index LC_DYSYMTAB load command if present.
LinkData LinkerOptimizationHint
std::optional< size_t > TextSegmentCommandIndex
The index of the LC_SEGMENT or LC_SEGMENT_64 load command corresponding to the __TEXT segment.
IndirectSymbolTable IndirectSymTable
LinkData DylibCodeSignDRs
std::optional< size_t > CodeSignatureCommandIndex
The index of LC_CODE_SIGNATURE load command if present.
std::optional< size_t > LinkerOptimizationHintCommandIndex
The index of LC_LINKER_OPTIMIZATIN_HINT load command if present.
ArrayRef< uint8_t > Opcodes
MachO::any_relocation_info Info
std::optional< const SymbolEntry * > Symbol
std::optional< const Section * > Sec
void setPlainRelocationSymbolNum(unsigned SymbolNum, bool IsLittleEndian)
std::vector< std::unique_ptr< SymbolEntry > > Symbols
ArrayRef< uint8_t > Opcodes