summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/Object/Archive.h1
-rw-r--r--llvm/lib/Object/ArchiveWriter.cpp49
-rw-r--r--llvm/test/Object/archive-extract.test6
-rw-r--r--llvm/test/Object/archive-format.test19
-rw-r--r--llvm/test/Object/archive-pad.test19
-rw-r--r--llvm/tools/llvm-ar/llvm-ar.cpp15
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 =
OpenPOWER on IntegriCloud