diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -880,6 +880,8 @@ return OwningObject; } +bool isMacho(const MemoryBuffer &Buffer); + } // end namespace object } // end namespace llvm diff --git a/llvm/lib/ObjCopy/Archive.cpp b/llvm/lib/ObjCopy/Archive.cpp --- a/llvm/lib/ObjCopy/Archive.cpp +++ b/llvm/lib/ObjCopy/Archive.cpp @@ -11,6 +11,7 @@ #include "llvm/ObjCopy/MultiFormatConfig.h" #include "llvm/ObjCopy/ObjCopy.h" #include "llvm/Object/Error.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" @@ -61,6 +62,10 @@ ArrayRef NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin) { + if (Kind == object::Archive::K_BSD && !NewMembers.empty() && + isMacho(*NewMembers.front().Buf)) + Kind = object::Archive::K_DARWIN; + if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin)) return createFileError(ArcName, std::move(E)); diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp --- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp @@ -484,9 +484,13 @@ createNewArchiveMembers(Config, **ArOrErr); if (!NewArchiveMembersOrErr) return NewArchiveMembersOrErr.takeError(); + auto Kind = (*ArOrErr)->kind(); + if (Kind == object::Archive::K_BSD && !NewArchiveMembersOrErr->empty() && + isMacho(*NewArchiveMembersOrErr->front().Buf)) + Kind = object::Archive::K_DARWIN; Expected> OutputBufferOrErr = writeArchiveToBuffer(*NewArchiveMembersOrErr, - (*ArOrErr)->hasSymbolTable(), (*ArOrErr)->kind(), + (*ArOrErr)->hasSymbolTable(), Kind, Config.getCommonConfig().DeterministicArchives, (*ArOrErr)->isThin()); if (!OutputBufferOrErr) diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -21,7 +21,9 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/Swift.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Object/Error.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" @@ -5028,3 +5030,63 @@ return false; } } + +namespace llvm { +namespace object { + +bool isMacho(const MemoryBuffer &Buffer) { + auto Magic = identify_magic(Buffer.getBuffer()); + switch (Magic) { + case file_magic::bitcode: { + LLVMContext Context; + if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + Buffer, file_magic::bitcode, &Context, false)) { + auto &IRObject = cast(**ObjOrErr); + return Triple(IRObject.getTargetTriple()).isOSDarwin(); + } else { + // Squelch the error in case this was not a SymbolicFile. + consumeError(ObjOrErr.takeError()); + } + + return false; + } + case file_magic::macho_bundle: + case file_magic::macho_core: + case file_magic::macho_dsym_companion: + case file_magic::macho_dynamic_linker: + case file_magic::macho_dynamically_linked_shared_lib: + case file_magic::macho_dynamically_linked_shared_lib_stub: + case file_magic::macho_executable: + case file_magic::macho_fixed_virtual_memory_shared_lib: + case file_magic::macho_kext_bundle: + case file_magic::macho_object: + case file_magic::macho_preload_executable: + case file_magic::macho_universal_binary: + return true; + case file_magic::archive: + case file_magic::coff_cl_gl_object: + case file_magic::coff_import_library: + case file_magic::coff_object: + case file_magic::cuda_fatbinary: + case file_magic::dxcontainer_object: + case file_magic::elf: + case file_magic::elf_core: + case file_magic::elf_executable: + case file_magic::elf_relocatable: + case file_magic::elf_shared_object: + case file_magic::goff_object: + case file_magic::minidump: + case file_magic::pdb: + case file_magic::pecoff_executable: + case file_magic::tapi_file: + case file_magic::unknown: + case file_magic::wasm_object: + case file_magic::windows_resource: + case file_magic::xcoff_object_32: + case file_magic::xcoff_object_64: + return false; + } +} + +} // namespace object +} // namespace llvm diff --git a/llvm/test/tools/llvm-ar/macho-edit.test b/llvm/test/tools/llvm-ar/macho-edit.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/macho-edit.test @@ -0,0 +1,14 @@ +# REQUIRES: x86-registered-target + +## Make sure darwin specific timestamps are preserved when updating the archive + +# RUN: rm -rf %t; mkdir -p %t/a %t/b +# RUN: yaml2obj %p/Inputs/macho.yaml > %t/a/dup.o +# RUN: yaml2obj %p/Inputs/macho.yaml > %t/b/dup.o +# RUN: yaml2obj %p/Inputs/macho.yaml > %t/last.o + +# RUN: llvm-ar --format=darwin crD %t/lib.a %t/a/dup.o %t/b/dup.o %t/last.o +# RUN: cp %t/lib.a %t/originallib.a +## Inserting existing object is ignored but forces llvm-ar to rewrite the archive +# RUN: llvm-ar crD %t/lib.a %t/last.o +# RUN: cmp %t/lib.a %t/originallib.a diff --git a/llvm/test/tools/llvm-objcopy/MachO/archive-format.test b/llvm/test/tools/llvm-objcopy/MachO/archive-format.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/archive-format.test @@ -0,0 +1,10 @@ +## Make sure darwin specific timestamp logic is preserved in archives + +# RUN: rm -rf %t; mkdir -p %t/a %t/b +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %p/Inputs/macho.64.s -o %t/a/dup.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %p/Inputs/macho.64.s -o %t/b/dup.o +# RUN: llvm-ar --format=darwin crD %t/lib.a %t/a/dup.o %t/b/dup.o +# RUN: llvm-objcopy %t/lib.a %t/lib.copy.a +# RUN: cmp %t/lib.a %t/lib.copy.a + +# REQUIRES: x86-registered-target diff --git a/llvm/test/tools/llvm-objcopy/MachO/universal-object.test b/llvm/test/tools/llvm-objcopy/MachO/universal-object.test --- a/llvm/test/tools/llvm-objcopy/MachO/universal-object.test +++ b/llvm/test/tools/llvm-objcopy/MachO/universal-object.test @@ -12,9 +12,9 @@ # RUN: cmp %t.i386 %t.i386.copy # RUN: cmp %t.x86_64 %t.x86_64.copy -## Case 2: copy a universal object file containing an archive. +## Case 2: copy a universal object file containing an archive with darwin specific timestamps. # RUN: rm -f %t.archive.i386 -# RUN: llvm-ar --format=gnu cr %t.archive.i386 %t.i386 +# RUN: llvm-ar --format=darwin cr %t.archive.i386 %t.i386 %t.i386 # RUN: llvm-lipo %t.archive.i386 %t.x86_64 -create -output %t.universal.containing.archive # RUN: llvm-objcopy %t.universal.containing.archive %t.universal.containing.archive.copy # RUN: llvm-lipo %t.universal.containing.archive.copy -archs | FileCheck --check-prefix=VERIFY_ARCHS %s diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -970,6 +970,15 @@ llvm_unreachable(""); } + if (Kind == object::Archive::K_BSD) { + if (NewMembersP && !NewMembersP->empty() && + llvm::object::isMacho(*NewMembersP->front().Buf)) + Kind = object::Archive::K_DARWIN; + else if (!NewMembers.empty() && + llvm::object::isMacho(*NewMembers.front().Buf)) + Kind = object::Archive::K_DARWIN; + } + Error E = writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab, Kind, Deterministic, Thin, std::move(OldArchiveBuf));