diff options
Diffstat (limited to 'tools/llvm-objcopy/MachO/MachOWriter.cpp')
-rw-r--r-- | tools/llvm-objcopy/MachO/MachOWriter.cpp | 305 |
1 files changed, 103 insertions, 202 deletions
diff --git a/tools/llvm-objcopy/MachO/MachOWriter.cpp b/tools/llvm-objcopy/MachO/MachOWriter.cpp index 74200c5aa62a..4ec91cc9eb7a 100644 --- a/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "MachOWriter.h" +#include "MachOLayoutBuilder.h" #include "Object.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/MachO.h" @@ -40,16 +41,10 @@ size_t MachOWriter::totalSize() const { const MachO::symtab_command &SymTabCommand = O.LoadCommands[*O.SymTabCommandIndex] .MachOLoadCommand.symtab_command_data; - if (SymTabCommand.symoff) { - assert((SymTabCommand.nsyms == O.SymTable.Symbols.size()) && - "Incorrect number of symbols"); + if (SymTabCommand.symoff) Ends.push_back(SymTabCommand.symoff + symTableSize()); - } - if (SymTabCommand.stroff) { - assert((SymTabCommand.strsize == StrTableBuilder.getSize()) && - "Incorrect string table size"); + if (SymTabCommand.stroff) Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize); - } } if (O.DyLdInfoCommandIndex) { const MachO::dyld_info_command &DyLdInfoCommand = @@ -84,6 +79,36 @@ size_t MachOWriter::totalSize() const { } } + if (O.DySymTabCommandIndex) { + const MachO::dysymtab_command &DySymTabCommand = + O.LoadCommands[*O.DySymTabCommandIndex] + .MachOLoadCommand.dysymtab_command_data; + + if (DySymTabCommand.indirectsymoff) + Ends.push_back(DySymTabCommand.indirectsymoff + + sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); + } + + if (O.DataInCodeCommandIndex) { + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.DataInCodeCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + + if (LinkEditDataCommand.dataoff) + Ends.push_back(LinkEditDataCommand.dataoff + + LinkEditDataCommand.datasize); + } + + if (O.FunctionStartsCommandIndex) { + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.FunctionStartsCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + + if (LinkEditDataCommand.dataoff) + Ends.push_back(LinkEditDataCommand.dataoff + + LinkEditDataCommand.datasize); + } + // Otherwise, use the last section / reloction. for (const auto &LC : O.LoadCommands) for (const auto &S : LC.Sections) { @@ -120,14 +145,6 @@ void MachOWriter::writeHeader() { memcpy(B.getBufferStart(), &Header, HeaderSize); } -void MachOWriter::updateSymbolIndexes() { - uint32_t Index = 0; - for (auto &Symbol : O.SymTable.Symbols) { - Symbol->Index = Index; - Index++; - } -} - void MachOWriter::writeLoadCommands() { uint8_t *Begin = B.getBufferStart() + headerSize(); for (const auto &LC : O.LoadCommands) { @@ -253,7 +270,7 @@ void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out, Out += sizeof(NListType); } -void MachOWriter::writeSymbolTable() { +void MachOWriter::writeStringTable() { if (!O.SymTabCommandIndex) return; const MachO::symtab_command &SymTabCommand = @@ -261,10 +278,10 @@ void MachOWriter::writeSymbolTable() { .MachOLoadCommand.symtab_command_data; uint8_t *StrTable = (uint8_t *)B.getBufferStart() + SymTabCommand.stroff; - StrTableBuilder.write(StrTable); + LayoutBuilder.getStringTableBuilder().write(StrTable); } -void MachOWriter::writeStringTable() { +void MachOWriter::writeSymbolTable() { if (!O.SymTabCommandIndex) return; const MachO::symtab_command &SymTabCommand = @@ -275,7 +292,7 @@ void MachOWriter::writeStringTable() { for (auto Iter = O.SymTable.Symbols.begin(), End = O.SymTable.Symbols.end(); Iter != End; Iter++) { SymbolEntry *Sym = Iter->get(); - auto Nstrx = StrTableBuilder.getOffset(Sym->Name); + uint32_t Nstrx = LayoutBuilder.getStringTableBuilder().getOffset(Sym->Name); if (Is64Bit) writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx); @@ -344,6 +361,45 @@ void MachOWriter::writeExportInfo() { memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size()); } +void MachOWriter::writeIndirectSymbolTable() { + if (!O.DySymTabCommandIndex) + return; + + const MachO::dysymtab_command &DySymTabCommand = + O.LoadCommands[*O.DySymTabCommandIndex] + .MachOLoadCommand.dysymtab_command_data; + + char *Out = (char *)B.getBufferStart() + DySymTabCommand.indirectsymoff; + assert((DySymTabCommand.nindirectsyms == O.IndirectSymTable.Symbols.size()) && + "Incorrect indirect symbol table size"); + memcpy(Out, O.IndirectSymTable.Symbols.data(), + sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); +} + +void MachOWriter::writeDataInCodeData() { + if (!O.DataInCodeCommandIndex) + return; + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.DataInCodeCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + char *Out = (char *)B.getBufferStart() + LinkEditDataCommand.dataoff; + assert((LinkEditDataCommand.datasize == O.DataInCode.Data.size()) && + "Incorrect data in code data size"); + memcpy(Out, O.DataInCode.Data.data(), O.DataInCode.Data.size()); +} + +void MachOWriter::writeFunctionStartsData() { + if (!O.FunctionStartsCommandIndex) + return; + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.FunctionStartsCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + char *Out = (char *)B.getBufferStart() + LinkEditDataCommand.dataoff; + assert((LinkEditDataCommand.datasize == O.FunctionStarts.Data.size()) && + "Incorrect function starts data size"); + memcpy(Out, O.FunctionStarts.Data.data(), O.FunctionStarts.Data.size()); +} + void MachOWriter::writeTail() { typedef void (MachOWriter::*WriteHandlerType)(void); typedef std::pair<uint64_t, WriteHandlerType> WriteOperation; @@ -379,206 +435,51 @@ void MachOWriter::writeTail() { {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo}); } - llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) { - return LHS.first < RHS.first; - }); - - for (auto WriteOp : Queue) - (this->*WriteOp.second)(); -} - -void MachOWriter::updateSizeOfCmds() { - auto Size = 0; - for (const auto &LC : O.LoadCommands) { - auto &MLC = LC.MachOLoadCommand; - auto cmd = MLC.load_command_data.cmd; - - switch (cmd) { - case MachO::LC_SEGMENT: - Size += sizeof(MachO::segment_command) + - sizeof(MachO::section) * LC.Sections.size(); - continue; - case MachO::LC_SEGMENT_64: - Size += sizeof(MachO::segment_command_64) + - sizeof(MachO::section_64) * LC.Sections.size(); - continue; - } - - switch (cmd) { -#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ - case MachO::LCName: \ - Size += sizeof(MachO::LCStruct); \ - break; -#include "llvm/BinaryFormat/MachO.def" -#undef HANDLE_LOAD_COMMAND - } - } - - O.Header.SizeOfCmds = Size; -} - -// Updates the index and the number of local/external/undefined symbols. Here we -// assume that MLC is a LC_DYSYMTAB and the nlist entries in the symbol table -// are already sorted by the those types. -void MachOWriter::updateDySymTab(MachO::macho_load_command &MLC) { - uint32_t NumLocalSymbols = 0; - auto Iter = O.SymTable.Symbols.begin(); - auto End = O.SymTable.Symbols.end(); - for (; Iter != End; Iter++) { - if ((*Iter)->n_type & (MachO::N_EXT | MachO::N_PEXT)) - break; + if (O.DySymTabCommandIndex) { + const MachO::dysymtab_command &DySymTabCommand = + O.LoadCommands[*O.DySymTabCommandIndex] + .MachOLoadCommand.dysymtab_command_data; - NumLocalSymbols++; + if (DySymTabCommand.indirectsymoff) + Queue.emplace_back(DySymTabCommand.indirectsymoff, + &MachOWriter::writeIndirectSymbolTable); } - uint32_t NumExtDefSymbols = 0; - for (; Iter != End; Iter++) { - if (((*Iter)->n_type & MachO::N_TYPE) == MachO::N_UNDF) - break; - - NumExtDefSymbols++; - } - - MLC.dysymtab_command_data.ilocalsym = 0; - MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols; - MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols; - MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols; - MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols; - MLC.dysymtab_command_data.nundefsym = - O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols); -} - -// Recomputes and updates offset and size fields in load commands and sections -// since they could be modified. -Error MachOWriter::layout() { - auto SizeOfCmds = loadCommandsSize(); - auto Offset = headerSize() + SizeOfCmds; - O.Header.NCmds = O.LoadCommands.size(); - O.Header.SizeOfCmds = SizeOfCmds; - - // Lay out sections. - for (auto &LC : O.LoadCommands) { - uint64_t FileOff = Offset; - uint64_t VMSize = 0; - uint64_t FileOffsetInSegment = 0; - for (auto &Sec : LC.Sections) { - if (!Sec.isVirtualSection()) { - auto FilePaddingSize = - OffsetToAlignment(FileOffsetInSegment, 1ull << Sec.Align); - Sec.Offset = Offset + FileOffsetInSegment + FilePaddingSize; - Sec.Size = Sec.Content.size(); - FileOffsetInSegment += FilePaddingSize + Sec.Size; - } - - VMSize = std::max(VMSize, Sec.Addr + Sec.Size); - } - - // TODO: Handle the __PAGEZERO segment. - auto &MLC = LC.MachOLoadCommand; - switch (MLC.load_command_data.cmd) { - case MachO::LC_SEGMENT: - MLC.segment_command_data.cmdsize = - sizeof(MachO::segment_command) + - sizeof(MachO::section) * LC.Sections.size(); - MLC.segment_command_data.nsects = LC.Sections.size(); - MLC.segment_command_data.fileoff = FileOff; - MLC.segment_command_data.vmsize = VMSize; - MLC.segment_command_data.filesize = FileOffsetInSegment; - break; - case MachO::LC_SEGMENT_64: - MLC.segment_command_64_data.cmdsize = - sizeof(MachO::segment_command_64) + - sizeof(MachO::section_64) * LC.Sections.size(); - MLC.segment_command_64_data.nsects = LC.Sections.size(); - MLC.segment_command_64_data.fileoff = FileOff; - MLC.segment_command_64_data.vmsize = VMSize; - MLC.segment_command_64_data.filesize = FileOffsetInSegment; - break; - } + if (O.DataInCodeCommandIndex) { + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.DataInCodeCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; - Offset += FileOffsetInSegment; + if (LinkEditDataCommand.dataoff) + Queue.emplace_back(LinkEditDataCommand.dataoff, + &MachOWriter::writeDataInCodeData); } - // Lay out relocations. - for (auto &LC : O.LoadCommands) - for (auto &Sec : LC.Sections) { - Sec.RelOff = Sec.Relocations.empty() ? 0 : Offset; - Sec.NReloc = Sec.Relocations.size(); - Offset += sizeof(MachO::any_relocation_info) * Sec.NReloc; - } + if (O.FunctionStartsCommandIndex) { + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.FunctionStartsCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; - // Lay out tail stuff. - auto NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); - for (auto &LC : O.LoadCommands) { - auto &MLC = LC.MachOLoadCommand; - auto cmd = MLC.load_command_data.cmd; - switch (cmd) { - case MachO::LC_SYMTAB: - MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size(); - MLC.symtab_command_data.strsize = StrTableBuilder.getSize(); - MLC.symtab_command_data.symoff = Offset; - Offset += NListSize * MLC.symtab_command_data.nsyms; - MLC.symtab_command_data.stroff = Offset; - Offset += MLC.symtab_command_data.strsize; - break; - case MachO::LC_DYSYMTAB: { - if (MLC.dysymtab_command_data.ntoc != 0 || - MLC.dysymtab_command_data.nmodtab != 0 || - MLC.dysymtab_command_data.nextrefsyms != 0 || - MLC.dysymtab_command_data.nlocrel != 0 || - MLC.dysymtab_command_data.nextrel != 0) - return createStringError(llvm::errc::not_supported, - "shared library is not yet supported"); - - if (MLC.dysymtab_command_data.nindirectsyms != 0) - return createStringError(llvm::errc::not_supported, - "indirect symbol table is not yet supported"); - - updateDySymTab(MLC); - break; - } - case MachO::LC_SEGMENT: - case MachO::LC_SEGMENT_64: - case MachO::LC_VERSION_MIN_MACOSX: - case MachO::LC_BUILD_VERSION: - case MachO::LC_ID_DYLIB: - case MachO::LC_LOAD_DYLIB: - case MachO::LC_UUID: - case MachO::LC_SOURCE_VERSION: - // Nothing to update. - break; - default: - // Abort if it's unsupported in order to prevent corrupting the object. - return createStringError(llvm::errc::not_supported, - "unsupported load command (cmd=0x%x)", cmd); - } + if (LinkEditDataCommand.dataoff) + Queue.emplace_back(LinkEditDataCommand.dataoff, + &MachOWriter::writeFunctionStartsData); } - return Error::success(); -} + llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) { + return LHS.first < RHS.first; + }); -void MachOWriter::constructStringTable() { - for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols) - StrTableBuilder.add(Sym->Name); - StrTableBuilder.finalize(); + for (auto WriteOp : Queue) + (this->*WriteOp.second)(); } -Error MachOWriter::finalize() { - updateSizeOfCmds(); - constructStringTable(); - - if (auto E = layout()) - return E; - - return Error::success(); -} +Error MachOWriter::finalize() { return LayoutBuilder.layout(); } Error MachOWriter::write() { if (Error E = B.allocate(totalSize())) return E; memset(B.getBufferStart(), 0, totalSize()); writeHeader(); - updateSymbolIndexes(); writeLoadCommands(); writeSections(); writeTail(); |