diff --git a/llvm/test/tools/llvm-objcopy/MachO/code_signature_lc.test b/llvm/test/tools/llvm-objcopy/MachO/code_signature_lc.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/code_signature_lc.test @@ -0,0 +1,40 @@ +# RUN: yaml2obj %s -o %t + +## Verify that the input file is valid and contains the expected load command. +# RUN: llvm-objdump --private-headers %t | FileCheck %s + +# CHECK: cmd LC_CODE_SIGNATURE +# CHECK-NEXT: cmdsize 16 +# CHECK-NEXT: dataoff 124 +# CHECK-NEXT: datasize 16 + +# RUN: llvm-objcopy %t %t.copy +# RUN: cmp %t %t.copy + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x80000003 + filetype: 0x00000002 + ncmds: 2 + sizeofcmds: 88 + flags: 0x00218085 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 72 + segname: __LINKEDIT + vmaddr: 4294979584 + vmsize: 4096 + fileoff: 120 + filesize: 20 + maxprot: 7 + initprot: 1 + nsects: 0 + flags: 0 + - cmd: LC_CODE_SIGNATURE + cmdsize: 16 + dataoff: 124 + datasize: 16 +... diff --git a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp @@ -216,10 +216,22 @@ } Error MachOLayoutBuilder::layoutTail(uint64_t Offset) { + // If we are building the layout of an executable or dynamic library + // which does not have any segments other than __LINKEDIT, + // the Offset can be equal to zero by this time. It happens because of the + // convention that in such cases the file offsets specified by LC_SEGMENT start + // with zero (unlike the case of a relocatable object file). + const bool IsObject = O.Header.FileType == MachO::HeaderFileType::MH_OBJECT; + const uint64_t HeaderSize = + Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); + assert((!IsObject || Offset >= HeaderSize + O.Header.SizeOfCmds) && + "Incorrect tail offset"); + Offset = std::max(Offset, HeaderSize + O.Header.SizeOfCmds); + // The order of LINKEDIT elements is as follows: // rebase info, binding info, weak binding info, lazy binding info, export // trie, data-in-code, symbol table, indirect symbol table, symbol table - // strings. + // strings, code signature. uint64_t NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); uint64_t StartOfLinkEdit = Offset; uint64_t StartOfRebaseInfo = StartOfLinkEdit; @@ -238,8 +250,10 @@ uint64_t StartOfSymbolStrings = StartOfIndirectSymbols + sizeof(uint32_t) * O.IndirectSymTable.Symbols.size(); + uint64_t StartOfCodeSignature = + StartOfSymbolStrings + StrTableBuilder.getSize(); uint64_t LinkEditSize = - (StartOfSymbolStrings + StrTableBuilder.getSize()) - StartOfLinkEdit; + (StartOfCodeSignature + O.CodeSignature.Data.size()) - StartOfLinkEdit; // Now we have determined the layout of the contents of the __LINKEDIT // segment. Update its load command. @@ -265,6 +279,10 @@ auto &MLC = LC.MachOLoadCommand; auto cmd = MLC.load_command_data.cmd; switch (cmd) { + case MachO::LC_CODE_SIGNATURE: + MLC.linkedit_data_command_data.dataoff = StartOfCodeSignature; + MLC.linkedit_data_command_data.datasize = O.CodeSignature.Data.size(); + break; case MachO::LC_SYMTAB: MLC.symtab_command_data.symoff = StartOfSymbols; MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size(); diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.h b/llvm/tools/llvm-objcopy/MachO/MachOReader.h --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.h @@ -36,6 +36,8 @@ void readWeakBindInfo(Object &O) const; void readLazyBindInfo(Object &O) const; void readExportInfo(Object &O) const; + void readLinkData(Object &O, Optional LCIndex, LinkData &LD) const; + void readCodeSignature(Object &O) const; void readDataInCodeData(Object &O) const; void readFunctionStartsData(Object &O) const; void readIndirectSymbolTable(Object &O) const; diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -119,6 +119,9 @@ for (auto LoadCmd : MachOObj.load_commands()) { LoadCommand LC; switch (LoadCmd.C.cmd) { + case MachO::LC_CODE_SIGNATURE: + O.CodeSignatureCommandIndex = O.LoadCommands.size(); + break; case MachO::LC_SEGMENT: LC.Sections = extractSections( LoadCmd, MachOObj, NextSectionIndex); @@ -247,26 +250,26 @@ O.Exports.Trie = MachOObj.getDyldInfoExportsTrie(); } -void MachOReader::readDataInCodeData(Object &O) const { - if (!O.DataInCodeCommandIndex) +void MachOReader::readLinkData(Object &O, Optional LCIndex, + LinkData &LD) const { + if (!LCIndex) return; - const MachO::linkedit_data_command &LDC = - O.LoadCommands[*O.DataInCodeCommandIndex] - .MachOLoadCommand.linkedit_data_command_data; + const MachO::linkedit_data_command &LC = + O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data; + LD.Data = + arrayRefFromStringRef(MachOObj.getData().substr(LC.dataoff, LC.datasize)); +} - O.DataInCode.Data = arrayRefFromStringRef( - MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +void MachOReader::readCodeSignature(Object &O) const { + return readLinkData(O, O.CodeSignatureCommandIndex, O.CodeSignature); } -void MachOReader::readFunctionStartsData(Object &O) const { - if (!O.FunctionStartsCommandIndex) - return; - const MachO::linkedit_data_command &LDC = - O.LoadCommands[*O.FunctionStartsCommandIndex] - .MachOLoadCommand.linkedit_data_command_data; +void MachOReader::readDataInCodeData(Object &O) const { + return readLinkData(O, O.DataInCodeCommandIndex, O.DataInCode); +} - O.FunctionStarts.Data = arrayRefFromStringRef( - MachOObj.getData().substr(LDC.dataoff, LDC.datasize)); +void MachOReader::readFunctionStartsData(Object &O) const { + return readLinkData(O, O.FunctionStartsCommandIndex, O.FunctionStarts); } void MachOReader::readIndirectSymbolTable(Object &O) const { @@ -316,6 +319,7 @@ readWeakBindInfo(*Obj); readLazyBindInfo(*Obj); readExportInfo(*Obj); + readCodeSignature(*Obj); readDataInCodeData(*Obj); readFunctionStartsData(*Obj); readIndirectSymbolTable(*Obj); diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.h b/llvm/tools/llvm-objcopy/MachO/MachOWriter.h --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.h @@ -45,6 +45,8 @@ void writeLazyBindInfo(); void writeExportInfo(); void writeIndirectSymbolTable(); + void writeLinkData(Optional LCIndex, const LinkData &LD); + void writeCodeSignatureData(); void writeDataInCodeData(); void writeFunctionStartsData(); void writeTail(); diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -89,6 +89,15 @@ sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); } + if (O.CodeSignatureCommandIndex) { + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.CodeSignatureCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + if (LinkEditDataCommand.dataoff) + Ends.push_back(LinkEditDataCommand.dataoff + + LinkEditDataCommand.datasize); + } + if (O.DataInCodeCommandIndex) { const MachO::linkedit_data_command &LinkEditDataCommand = O.LoadCommands[*O.DataInCodeCommandIndex] @@ -381,28 +390,27 @@ } } -void MachOWriter::writeDataInCodeData() { - if (!O.DataInCodeCommandIndex) +void MachOWriter::writeLinkData(Optional LCIndex, const LinkData &LD) { + if (!LCIndex) return; const MachO::linkedit_data_command &LinkEditDataCommand = - O.LoadCommands[*O.DataInCodeCommandIndex] - .MachOLoadCommand.linkedit_data_command_data; + O.LoadCommands[*LCIndex].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()); + assert((LinkEditDataCommand.datasize == LD.Data.size()) && + "Incorrect data size"); + memcpy(Out, LD.Data.data(), LD.Data.size()); +} + +void MachOWriter::writeCodeSignatureData() { + return writeLinkData(O.CodeSignatureCommandIndex, O.CodeSignature); +} + +void MachOWriter::writeDataInCodeData() { + return writeLinkData(O.DataInCodeCommandIndex, O.DataInCode); } 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()); + return writeLinkData(O.FunctionStartsCommandIndex, O.FunctionStarts); } void MachOWriter::writeTail() { @@ -450,6 +458,16 @@ &MachOWriter::writeIndirectSymbolTable); } + if (O.CodeSignatureCommandIndex) { + const MachO::linkedit_data_command &LinkEditDataCommand = + O.LoadCommands[*O.CodeSignatureCommandIndex] + .MachOLoadCommand.linkedit_data_command_data; + + if (LinkEditDataCommand.dataoff) + Queue.emplace_back(LinkEditDataCommand.dataoff, + &MachOWriter::writeCodeSignatureData); + } + if (O.DataInCodeCommandIndex) { const MachO::linkedit_data_command &LinkEditDataCommand = O.LoadCommands[*O.DataInCodeCommandIndex] diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -302,9 +302,12 @@ IndirectSymbolTable IndirectSymTable; LinkData DataInCode; LinkData FunctionStarts; + LinkData CodeSignature; Optional SwiftVersion; + /// The index of LC_CODE_SIGNATURE load command if present. + Optional CodeSignatureCommandIndex; /// The index of LC_SYMTAB load command if present. Optional SymTabCommandIndex; /// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.