diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp --- a/llvm/lib/Object/Archive.cpp +++ b/llvm/lib/Object/Archive.cpp @@ -15,8 +15,10 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Object/Binary.h" #include "llvm/Object/Error.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -144,7 +146,8 @@ Expected ArchiveMemberHeader::getRawName() const { char EndCond; auto Kind = Parent->kind(); - if (Kind == Archive::K_BSD || Kind == Archive::K_DARWIN64) { + if (Kind == Archive::K_BSD || Kind == Archive::K_DARWIN || + Kind == Archive::K_DARWIN64) { if (ArMemHdr->Name[0] == ' ') { uint64_t Offset = reinterpret_cast(ArMemHdr) - Parent->getData().data(); @@ -690,6 +693,62 @@ FirstRegularStartOfFile = C.StartOfFile; } +bool isMacho(Expected &Buffer) { + if (!Buffer) + return false; + + 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::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; + } +} + Archive::Archive(MemoryBufferRef Source, Error &Err) : Binary(Binary::ID_Archive, Source) { ErrorAsOutParameter ErrAsOutParam(&Err); @@ -744,6 +803,14 @@ } StringRef Name = NameOrErr.get(); + auto UpdatePotentialDarwinFormat = [&]() { + if (Format == K_DARWIN || Format == K_DARWIN64 || !C->Header) + return; + auto MemoryBuffer = C->getMemoryBufferRef(); + if (MemoryBuffer && isMacho(MemoryBuffer)) + Format = K_DARWIN; + }; + // Below is the pattern that is used to figure out the archive format // GNU archive format // First member : / (may exist, if it exists, points to the symbol table ) @@ -754,6 +821,9 @@ // There is no string table, if the filename exceeds 15 characters or has a // embedded space, the filename has #1/, The size represents the size // of the filename that needs to be read after the archive header + // One special case of this is for Darwin where there are slight differences + // for MachO specifics that are potentially also valid BSD, to determine the + // difference we look at the type of the first member. // COFF archive format // First member : / // Second member : / (provides a directory of symbols) @@ -776,9 +846,12 @@ return; } SymbolTable = BufOrErr.get(); - if (Increment()) + if (Increment()) { + UpdatePotentialDarwinFormat(); return; + } setFirstRegular(*C); + UpdatePotentialDarwinFormat(); Err = Error::success(); return; @@ -802,8 +875,10 @@ return; } SymbolTable = BufOrErr.get(); - if (Increment()) + if (Increment()) { + UpdatePotentialDarwinFormat(); return; + } } else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64") { Format = K_DARWIN64; // We know that the symbol table is not an external file, but we still @@ -818,6 +893,7 @@ return; } setFirstRegular(*C); + UpdatePotentialDarwinFormat(); return; } @@ -961,7 +1037,7 @@ Offset = read32be(Offsets + SymbolIndex * 4); } else if (Parent->kind() == K_GNU64) { Offset = read64be(Offsets + SymbolIndex * 8); - } else if (Parent->kind() == K_BSD) { + } else if (Parent->kind() == K_BSD || Parent->kind() == K_DARWIN) { // The SymbolIndex is an index into the ranlib structs that start at // Offsets (the first uint32_t is the number of bytes of the ranlib // structs). The ranlib structs are a pair of uint32_t's the first @@ -1011,7 +1087,7 @@ Archive::Symbol Archive::Symbol::getNext() const { Symbol t(*this); - if (Parent->kind() == K_BSD) { + if (Parent->kind() == K_BSD || Parent->kind() == K_DARWIN) { // t.StringIndex is an offset from the start of the __.SYMDEF or // "__.SYMDEF SORTED" member into the string table for the ranlib // struct indexed by t.SymbolIndex . To change t.StringIndex to the @@ -1060,7 +1136,7 @@ } else if (kind() == K_GNU64) { uint64_t symbol_count = read64be(buf); buf += sizeof(uint64_t) + (symbol_count * (sizeof(uint64_t))); - } else if (kind() == K_BSD) { + } else if (kind() == K_BSD || kind() == K_DARWIN) { // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t // which is the number of bytes of ranlib structs that follow. The ranlib // structs are a pair of uint32_t's the first being a string table offset @@ -1116,7 +1192,7 @@ return read32be(buf); if (kind() == K_GNU64) return read64be(buf); - if (kind() == K_BSD) + if (kind() == K_BSD || kind() == K_DARWIN) return read32le(buf) / 8; if (kind() == K_DARWIN64) return read64le(buf) / 16; diff --git a/llvm/test/tools/llvm-ar/default-macho.test b/llvm/test/tools/llvm-ar/default-macho.test --- a/llvm/test/tools/llvm-ar/default-macho.test +++ b/llvm/test/tools/llvm-ar/default-macho.test @@ -7,3 +7,12 @@ Ensure that we generate a BSD style archive for MachO by default. ld64 expects that it will be in BSD format. +Make sure darwin specific alignment is preserved when updating the archive + +RUN: rm -rf %t; split-file %S/../llvm-objcopy/MachO/Inputs/unaligned_objects.yaml %t +RUN: yaml2obj %t/first-object.yaml > %t/first.o +RUN: yaml2obj %t/second-object.yaml > %t/second.o +RUN: llvm-ar --format=darwin crs %t/lib.a %t/first.o %t/second.o +RUN: cp %t/lib.a %t/originallib.a +RUN: llvm-ar crs %t/lib.a %t/second.o +RUN: cmp %t/lib.a %t/originallib.a diff --git a/llvm/test/tools/llvm-objcopy/MachO/Inputs/unaligned_objects.yaml b/llvm/test/tools/llvm-objcopy/MachO/Inputs/unaligned_objects.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/Inputs/unaligned_objects.yaml @@ -0,0 +1,279 @@ +#--- first-object.yaml +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x1000007 + cpusubtype: 0x3 + filetype: 0x1 + ncmds: 4 + sizeofcmds: 208 + flags: 0x2000 + reserved: 0x0 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: '' + vmaddr: 0 + vmsize: 314 + fileoff: 240 + filesize: 314 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0 + size: 314 + offset: 0xF0 + align: 4 + reloff: 0x0 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: 554889E54839F7730431C05DC3480FBDCE4883F13F4885FF740A480FBDC74883F03FEB05B8400000004829C14889F048D3E089C94839C74883D9004989F349D3E34C29DF41B80100000049D3E04839F773054C89C05DC34D85DB78054C89C0EB2E49D1EB48FFC941B90100000049D3E131C04989FA4D29DA490F49C1490F49FA4C09C04D89C84839F70F82A900000049FFC84885C90F849700000049FFCB4C8D49FF4989CA4983E203742631F60F1F004801FF4889FA4C29DA4889D748C1FF3F4C21DF4801D748FFC64939F275E24829F14983F903725B660F1F8400000000004801FF4C29DF4889FA48C1FA3F4C21DA4801FA4801D24C29DA4889D648C1FE3F4C21DE4801D64801F64C29DE4889F248C1FA3F4C21DA4801F24801D24C29DA4889D748C1FF3F4C21DF4801D74883C1FC75AE4C21C74809F85DC3 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 554 + nsyms: 13 + stroff: 762 + strsize: 680 + - cmd: LC_VERSION_MIN_IPHONEOS + cmdsize: 16 + version: 458752 + sdk: 0 + - cmd: LC_DATA_IN_CODE + cmdsize: 16 + dataoff: 554 + datasize: 0 +LinkEditData: + NameList: + - n_strx: 572 + n_type: 0x64 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 539 + n_type: 0x64 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 672 + n_type: 0x2E + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 528 + n_type: 0x24 + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 398 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 297 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 130 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 214 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 672 + n_type: 0x24 + n_sect: 0 + n_desc: 0 + n_value: 314 + - n_strx: 672 + n_type: 0x4E + n_sect: 1 + n_desc: 0 + n_value: 314 + - n_strx: 672 + n_type: 0x64 + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 528 + n_type: 0x1F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/int/specialized_div_rem/norm_shift.rs' + - '/rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/num/uint_macros.rs' + - '/rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/num/int_macros.rs' + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/macros.rs' + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/int/specialized_div_rem/binary_long.rs' + - ___udivdi3 + - compiler_builtins.f13b4771-cgu.1 + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/lib.rs/@/' + - '' + - '' + - '' + - '' + - '' + - '' + - '' +... + +#--- second-object.yaml +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x1000007 + cpusubtype: 0x3 + filetype: 0x1 + ncmds: 4 + sizeofcmds: 208 + flags: 0x2000 + reserved: 0x0 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: '' + vmaddr: 0 + vmsize: 94 + fileoff: 240 + filesize: 94 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0 + size: 94 + offset: 0xF0 + align: 4 + reloff: 0x0 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x0 + reserved2: 0x0 + reserved3: 0x0 + content: 554889E589F840F6C610752985F6744C0FB7F84189F04183E00F4489C1D3EFC1E81040F6DE4080E60F89C289F1D3E209FA89C7EB1789C7C1EF10C1F8104080E60F89F1D3F86641B80F0089C20FBFC74489C1D3F80FB7CAC1E01009C85DC3 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 334 + nsyms: 14 + stroff: 558 + strsize: 704 + - cmd: LC_VERSION_MIN_IPHONEOS + cmdsize: 16 + version: 458752 + sdk: 0 + - cmd: LC_DATA_IN_CODE + cmdsize: 16 + dataoff: 334 + datasize: 0 +LinkEditData: + NameList: + - n_strx: 596 + n_type: 0x64 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 562 + n_type: 0x64 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 696 + n_type: 0x2E + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 551 + n_type: 0x24 + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 77 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 449 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 181 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 265 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 348 + n_type: 0x84 + n_sect: 0 + n_desc: 0 + n_value: 0 + - n_strx: 696 + n_type: 0x24 + n_sect: 0 + n_desc: 0 + n_value: 94 + - n_strx: 696 + n_type: 0x4E + n_sect: 1 + n_desc: 0 + n_value: 94 + - n_strx: 696 + n_type: 0x64 + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 551 + n_type: 0x1F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '/rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/ops/bit.rs' + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/int/shift.rs' + - '/rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/num/uint_macros.rs' + - '/rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/num/int_macros.rs' + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/macros.rs' + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/int/mod.rs' + - ___ashrsi3 + - compiler_builtins.f13b4771-cgu.10 + - '/Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.67/src/lib.rs/@/' + - '' + - '' + - '' + - '' + - '' + - '' + - '' +... diff --git a/llvm/test/tools/llvm-objcopy/MachO/real-world-input-copy.test b/llvm/test/tools/llvm-objcopy/MachO/real-world-input-copy.test --- a/llvm/test/tools/llvm-objcopy/MachO/real-world-input-copy.test +++ b/llvm/test/tools/llvm-objcopy/MachO/real-world-input-copy.test @@ -12,4 +12,13 @@ # RUN: llvm-objcopy %t.various-symbols.o %t.various-symbols.copy.o # RUN: cmp %t.various-symbols.o %t.various-symbols.copy.o +## Make sure darwin specific alignment is preserved in archives +# RUN: rm -rf %t; split-file %p/Inputs/unaligned_objects.yaml %t +# RUN: yaml2obj %t/first-object.yaml > %t/first.o +# RUN: yaml2obj %t/second-object.yaml > %t/second.o +## The object isn't duplicated, but forces ar to do a write of the archive +# RUN: llvm-ar cr %t/lib.a %t/first.o %t/second.o +# RUN: llvm-objcopy %t/lib.a %t/lib.copy.a +# RUN: cmp %t/lib.a %t/lib.copy.a + # REQUIRES: x86-registered-target