diff options
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/include/llvm/Object/Archive.h | 1 | ||||
| -rw-r--r-- | llvm/lib/Object/ArchiveWriter.cpp | 49 | ||||
| -rw-r--r-- | llvm/test/Object/archive-extract.test | 6 | ||||
| -rw-r--r-- | llvm/test/Object/archive-format.test | 19 | ||||
| -rw-r--r-- | llvm/test/Object/archive-pad.test | 19 | ||||
| -rw-r--r-- | llvm/tools/llvm-ar/llvm-ar.cpp | 15 |
6 files changed, 80 insertions, 29 deletions
diff --git a/llvm/include/llvm/Object/Archive.h b/llvm/include/llvm/Object/Archive.h index 08128b0c251..d423957d9b7 100644 --- a/llvm/include/llvm/Object/Archive.h +++ b/llvm/include/llvm/Object/Archive.h @@ -212,6 +212,7 @@ public: K_GNU, K_MIPS64, K_BSD, + K_DARWIN, K_DARWIN64, K_COFF }; diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp index fc827d321d9..e5d6267908d 100644 --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -122,12 +122,26 @@ static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, } } +static bool isBSDLike(object::Archive::Kind Kind) { + switch (Kind) { + case object::Archive::K_GNU: + return false; + case object::Archive::K_BSD: + case object::Archive::K_DARWIN: + return true; + case object::Archive::K_MIPS64: + case object::Archive::K_DARWIN64: + case object::Archive::K_COFF: + llvm_unreachable("not supported for writting"); + } +} + static void print32(raw_ostream &Out, object::Archive::Kind Kind, uint32_t Val) { - if (Kind == object::Archive::K_GNU) - support::endian::Writer<support::big>(Out).write(Val); - else + if (isBSDLike(Kind)) support::endian::Writer<support::little>(Out).write(Val); + else + support::endian::Writer<support::big>(Out).write(Val); } static void printRestOfMemberHeader( @@ -178,7 +192,7 @@ printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind, bool Thin, std::vector<unsigned>::iterator &StringMapIndexIter, const sys::TimePoint<std::chrono::seconds> &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { - if (Kind == object::Archive::K_BSD) + if (isBSDLike(Kind)) return printBSDMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); if (!useStringTable(Thin, Name)) return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); @@ -285,10 +299,10 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, if (!HeaderStartOffset) { HeaderStartOffset = Out.tell(); - if (Kind == object::Archive::K_GNU) - printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); - else + if (isBSDLike(Kind)) printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0); + else + printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); BodyStartOffset = Out.tell(); print32(Out, Kind, 0); // number of entries or bytes } @@ -307,7 +321,7 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, return EC; NameOS << '\0'; MemberOffsetRefs.push_back(MemberNum); - if (Kind == object::Archive::K_BSD) + if (isBSDLike(Kind)) print32(Out, Kind, NameOffset); print32(Out, Kind, 0); // member offset } @@ -318,12 +332,12 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, // ld64 prefers the cctools type archive which pads its string table to a // boundary of sizeof(int32_t). - if (Kind == object::Archive::K_BSD) + if (isBSDLike(Kind)) for (unsigned P = OffsetToAlignment(NameOS.tell(), sizeof(int32_t)); P--;) NameOS << '\0'; StringRef StringTable = NameOS.str(); - if (Kind == object::Archive::K_BSD) + if (isBSDLike(Kind)) print32(Out, Kind, StringTable.size()); // byte count of the string table Out << StringTable; @@ -342,10 +356,10 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, // Patch up the number of symbols. Out.seek(BodyStartOffset); unsigned NumSyms = MemberOffsetRefs.size(); - if (Kind == object::Archive::K_GNU) - print32(Out, Kind, NumSyms); - else + if (isBSDLike(Kind)) print32(Out, Kind, NumSyms * 8); + else + print32(Out, Kind, NumSyms); Out.seek(Pos); return BodyStartOffset + 4; @@ -357,8 +371,7 @@ llvm::writeArchive(StringRef ArcName, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr<MemoryBuffer> OldArchiveBuf) { - assert((!Thin || Kind == object::Archive::K_GNU) && - "Only the gnu format has a thin mode"); + assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); SmallString<128> TmpArchive; int TmpArchiveFD; if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a", @@ -388,7 +401,7 @@ llvm::writeArchive(StringRef ArcName, } std::vector<unsigned> StringMapIndexes; - if (Kind != object::Archive::K_BSD) + if (!isBSDLike(Kind)) writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); std::vector<unsigned>::iterator StringMapIndexIter = StringMapIndexes.begin(); @@ -404,7 +417,7 @@ llvm::writeArchive(StringRef ArcName, // least 4-byte aligned for 32-bit content. Opt for the larger encoding // uniformly. This matches the behaviour with cctools and ensures that ld64 // is happy with archives that we generate. - if (Kind == object::Archive::K_BSD) + if (Kind == object::Archive::K_DARWIN) Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8); printMemberHeader(Out, Kind, Thin, @@ -424,7 +437,7 @@ llvm::writeArchive(StringRef ArcName, if (MemberReferenceOffset) { Out.seek(MemberReferenceOffset); for (unsigned MemberNum : MemberOffsetRefs) { - if (Kind == object::Archive::K_BSD) + if (isBSDLike(Kind)) Out.seek(Out.tell() + 4); // skip over the string offset print32(Out, Kind, MemberOffset[MemberNum]); } diff --git a/llvm/test/Object/archive-extract.test b/llvm/test/Object/archive-extract.test index a3c69e50151..b8ed65a3053 100644 --- a/llvm/test/Object/archive-extract.test +++ b/llvm/test/Object/archive-extract.test @@ -43,10 +43,10 @@ CHECK-GNU: 1465 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc ; RUN: rm -f %t.a -; RUN: llvm-ar -format bsd rcU %t.a very_long_bytecode_file_name.bc -; RUN: env TZ=GMT llvm-ar tv %t.a | FileCheck %s -check-prefix CHECK-BSD +; RUN: llvm-ar -format darwin rcU %t.a very_long_bytecode_file_name.bc +; RUN: env TZ=GMT llvm-ar tv %t.a | FileCheck %s -check-prefix CHECK-DARWIN -CHECK-BSD: 1472 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc +CHECK-DARWIN: 1472 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc RUN: not llvm-ar x %p/Inputs/GNU.a foo.o 2>&1 | FileCheck --check-prefix=NOTFOUND %s NOTFOUND: foo.o was not found diff --git a/llvm/test/Object/archive-format.test b/llvm/test/Object/archive-format.test index 7505b1ffd5b..f895a36bce3 100644 --- a/llvm/test/Object/archive-format.test +++ b/llvm/test/Object/archive-format.test @@ -32,12 +32,23 @@ RUN: llvm-ar --format=bsd rc %t.a 0123456789abcde 0123456789abcdef RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=BSD %s BSD: !<arch> -BSD-NEXT: #1/20 0 0 0 644 28 ` +BSD-NEXT: #1/20 0 0 0 644 24 ` +BSD-NEXT: 0123456789abcde{{.....}}bar. +BSD-SAME: #1/16 0 0 0 644 20 ` +BSD-NEXT: 0123456789abcdefzed. + +RUN: rm -f %t.a +RUN: llvm-ar --format=darwin rc %t.a 0123456789abcde 0123456789abcdef +RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=DARWIN %s + +DARWIN: !<arch> +DARWIN-NEXT: #1/20 0 0 0 644 28 ` Each [[:space:]] matches a newline. We explicitly match 3 newlines, as the fourth newline is implicitly consumed by FileCheck and cannot be matched. -BSD-NEXT: 0123456789abcde{{.....}}bar.{{[[:space:]][[:space:]][[:space:]]}} -BSD-NEXT: #1/20 0 0 0 644 28 ` -BSD-NEXT: 0123456789abcdef{{....}}zed. +DARWIN-NEXT: 0123456789abcde{{.....}}bar.{{[[:space:]][[:space:]][[:space:]]}} +DARWIN-NEXT: #1/20 0 0 0 644 28 ` +DARWIN-NEXT: 0123456789abcdef{{....}}zed. + RUN: rm -f test.a RUN: llvm-ar --format=gnu rcT test.a 0123456789abcde 0123456789abcdef diff --git a/llvm/test/Object/archive-pad.test b/llvm/test/Object/archive-pad.test new file mode 100644 index 00000000000..e906791787a --- /dev/null +++ b/llvm/test/Object/archive-pad.test @@ -0,0 +1,19 @@ +Test that only the darwin format needs to modify archive members to +avoid a ld64 bug. + +RUN: echo foo > %t.o + +RUN: rm -f %t.a +RUN: llvm-ar -format=bsd rc %t.a %t.o +RUN: llvm-ar p %t.a > %bsd.o +RUN: cmp %bsd.o %t.o + +RUN: rm -f %t.a +RUN: llvm-ar -format=gnu rc %t.a %t.o +RUN: llvm-ar p %t.a > %gnu.o +RUN: cmp %gnu.o %t.o + +RUN: rm -f %t.a +RUN: llvm-ar -format=darwin rc %t.a %t.o +RUN: llvm-ar p %t.a > %darwin.o +RUN: not cmp %darwin.o %t.o diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp index b99a396da62..6d7c1c1c546 100644 --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -87,13 +87,14 @@ static cl::opt<bool> MRI("M", cl::desc("")); static cl::opt<std::string> Plugin("plugin", cl::desc("plugin (ignored for compatibility")); namespace { -enum Format { Default, GNU, BSD }; +enum Format { Default, GNU, BSD, DARWIN }; } static cl::opt<Format> FormatOpt("format", cl::desc("Archive format to create"), cl::values(clEnumValN(Default, "default", "default"), clEnumValN(GNU, "gnu", "gnu"), + clEnumValN(DARWIN, "darwin", "darwin"), clEnumValN(BSD, "bsd", "bsd"))); static std::string Options; @@ -623,8 +624,9 @@ computeNewArchiveMembers(ArchiveOperation Operation, } static object::Archive::Kind getDefaultForHost() { - return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_BSD - : object::Archive::K_GNU; + return Triple(sys::getProcessTriple()).isOSDarwin() + ? object::Archive::K_DARWIN + : object::Archive::K_GNU; } static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) { @@ -633,7 +635,7 @@ static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) { if (OptionalObject) return isa<object::MachOObjectFile>(**OptionalObject) - ? object::Archive::K_BSD + ? object::Archive::K_DARWIN : object::Archive::K_GNU; // squelch the error in case we had a non-object file @@ -672,6 +674,11 @@ performWriteOperation(ArchiveOperation Operation, fail("Only the gnu format has a thin mode"); Kind = object::Archive::K_BSD; break; + case DARWIN: + if (Thin) + fail("Only the gnu format has a thin mode"); + Kind = object::Archive::K_DARWIN; + break; } std::pair<StringRef, std::error_code> Result = |

