mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
Don't modify archive members unless really needed.
For whatever reason ld64 requires that member headers (not the member themselves) should be aligned. The only way to do that is to edit the previous member so that it ends at an aligned boundary. Since modifying data put in an archive is an undesirable property, llvm-ar should only do it when it is absolutely necessary. llvm-svn: 295765
This commit is contained in:
parent
c010343bc2
commit
98752fcfe6
@ -212,6 +212,7 @@ public:
|
|||||||
K_GNU,
|
K_GNU,
|
||||||
K_MIPS64,
|
K_MIPS64,
|
||||||
K_BSD,
|
K_BSD,
|
||||||
|
K_DARWIN,
|
||||||
K_DARWIN64,
|
K_DARWIN64,
|
||||||
K_COFF
|
K_COFF
|
||||||
};
|
};
|
||||||
|
@ -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,
|
static void print32(raw_ostream &Out, object::Archive::Kind Kind,
|
||||||
uint32_t Val) {
|
uint32_t Val) {
|
||||||
if (Kind == object::Archive::K_GNU)
|
if (isBSDLike(Kind))
|
||||||
support::endian::Writer<support::big>(Out).write(Val);
|
|
||||||
else
|
|
||||||
support::endian::Writer<support::little>(Out).write(Val);
|
support::endian::Writer<support::little>(Out).write(Val);
|
||||||
|
else
|
||||||
|
support::endian::Writer<support::big>(Out).write(Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printRestOfMemberHeader(
|
static void printRestOfMemberHeader(
|
||||||
@ -178,7 +192,7 @@ printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind, bool Thin,
|
|||||||
std::vector<unsigned>::iterator &StringMapIndexIter,
|
std::vector<unsigned>::iterator &StringMapIndexIter,
|
||||||
const sys::TimePoint<std::chrono::seconds> &ModTime,
|
const sys::TimePoint<std::chrono::seconds> &ModTime,
|
||||||
unsigned UID, unsigned GID, unsigned Perms, unsigned Size) {
|
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);
|
return printBSDMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
|
||||||
if (!useStringTable(Thin, Name))
|
if (!useStringTable(Thin, Name))
|
||||||
return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
|
return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
|
||||||
@ -285,10 +299,10 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
|
|||||||
|
|
||||||
if (!HeaderStartOffset) {
|
if (!HeaderStartOffset) {
|
||||||
HeaderStartOffset = Out.tell();
|
HeaderStartOffset = Out.tell();
|
||||||
if (Kind == object::Archive::K_GNU)
|
if (isBSDLike(Kind))
|
||||||
printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0);
|
|
||||||
else
|
|
||||||
printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0);
|
printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0);
|
||||||
|
else
|
||||||
|
printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0);
|
||||||
BodyStartOffset = Out.tell();
|
BodyStartOffset = Out.tell();
|
||||||
print32(Out, Kind, 0); // number of entries or bytes
|
print32(Out, Kind, 0); // number of entries or bytes
|
||||||
}
|
}
|
||||||
@ -307,7 +321,7 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
|
|||||||
return EC;
|
return EC;
|
||||||
NameOS << '\0';
|
NameOS << '\0';
|
||||||
MemberOffsetRefs.push_back(MemberNum);
|
MemberOffsetRefs.push_back(MemberNum);
|
||||||
if (Kind == object::Archive::K_BSD)
|
if (isBSDLike(Kind))
|
||||||
print32(Out, Kind, NameOffset);
|
print32(Out, Kind, NameOffset);
|
||||||
print32(Out, Kind, 0); // member offset
|
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
|
// ld64 prefers the cctools type archive which pads its string table to a
|
||||||
// boundary of sizeof(int32_t).
|
// boundary of sizeof(int32_t).
|
||||||
if (Kind == object::Archive::K_BSD)
|
if (isBSDLike(Kind))
|
||||||
for (unsigned P = OffsetToAlignment(NameOS.tell(), sizeof(int32_t)); P--;)
|
for (unsigned P = OffsetToAlignment(NameOS.tell(), sizeof(int32_t)); P--;)
|
||||||
NameOS << '\0';
|
NameOS << '\0';
|
||||||
|
|
||||||
StringRef StringTable = NameOS.str();
|
StringRef StringTable = NameOS.str();
|
||||||
if (Kind == object::Archive::K_BSD)
|
if (isBSDLike(Kind))
|
||||||
print32(Out, Kind, StringTable.size()); // byte count of the string table
|
print32(Out, Kind, StringTable.size()); // byte count of the string table
|
||||||
Out << StringTable;
|
Out << StringTable;
|
||||||
|
|
||||||
@ -342,10 +356,10 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
|
|||||||
// Patch up the number of symbols.
|
// Patch up the number of symbols.
|
||||||
Out.seek(BodyStartOffset);
|
Out.seek(BodyStartOffset);
|
||||||
unsigned NumSyms = MemberOffsetRefs.size();
|
unsigned NumSyms = MemberOffsetRefs.size();
|
||||||
if (Kind == object::Archive::K_GNU)
|
if (isBSDLike(Kind))
|
||||||
print32(Out, Kind, NumSyms);
|
|
||||||
else
|
|
||||||
print32(Out, Kind, NumSyms * 8);
|
print32(Out, Kind, NumSyms * 8);
|
||||||
|
else
|
||||||
|
print32(Out, Kind, NumSyms);
|
||||||
|
|
||||||
Out.seek(Pos);
|
Out.seek(Pos);
|
||||||
return BodyStartOffset + 4;
|
return BodyStartOffset + 4;
|
||||||
@ -357,8 +371,7 @@ llvm::writeArchive(StringRef ArcName,
|
|||||||
bool WriteSymtab, object::Archive::Kind Kind,
|
bool WriteSymtab, object::Archive::Kind Kind,
|
||||||
bool Deterministic, bool Thin,
|
bool Deterministic, bool Thin,
|
||||||
std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
|
std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
|
||||||
assert((!Thin || Kind == object::Archive::K_GNU) &&
|
assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
|
||||||
"Only the gnu format has a thin mode");
|
|
||||||
SmallString<128> TmpArchive;
|
SmallString<128> TmpArchive;
|
||||||
int TmpArchiveFD;
|
int TmpArchiveFD;
|
||||||
if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",
|
if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",
|
||||||
@ -388,7 +401,7 @@ llvm::writeArchive(StringRef ArcName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned> StringMapIndexes;
|
std::vector<unsigned> StringMapIndexes;
|
||||||
if (Kind != object::Archive::K_BSD)
|
if (!isBSDLike(Kind))
|
||||||
writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin);
|
writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin);
|
||||||
|
|
||||||
std::vector<unsigned>::iterator StringMapIndexIter = StringMapIndexes.begin();
|
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
|
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
|
||||||
// uniformly. This matches the behaviour with cctools and ensures that ld64
|
// uniformly. This matches the behaviour with cctools and ensures that ld64
|
||||||
// is happy with archives that we generate.
|
// 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);
|
Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8);
|
||||||
|
|
||||||
printMemberHeader(Out, Kind, Thin,
|
printMemberHeader(Out, Kind, Thin,
|
||||||
@ -424,7 +437,7 @@ llvm::writeArchive(StringRef ArcName,
|
|||||||
if (MemberReferenceOffset) {
|
if (MemberReferenceOffset) {
|
||||||
Out.seek(MemberReferenceOffset);
|
Out.seek(MemberReferenceOffset);
|
||||||
for (unsigned MemberNum : MemberOffsetRefs) {
|
for (unsigned MemberNum : MemberOffsetRefs) {
|
||||||
if (Kind == object::Archive::K_BSD)
|
if (isBSDLike(Kind))
|
||||||
Out.seek(Out.tell() + 4); // skip over the string offset
|
Out.seek(Out.tell() + 4); // skip over the string offset
|
||||||
print32(Out, Kind, MemberOffset[MemberNum]);
|
print32(Out, Kind, MemberOffset[MemberNum]);
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,10 @@
|
|||||||
CHECK-GNU: 1465 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc
|
CHECK-GNU: 1465 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc
|
||||||
|
|
||||||
; RUN: rm -f %t.a
|
; RUN: rm -f %t.a
|
||||||
; RUN: llvm-ar -format bsd rcU %t.a very_long_bytecode_file_name.bc
|
; 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-BSD
|
; 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
|
RUN: not llvm-ar x %p/Inputs/GNU.a foo.o 2>&1 | FileCheck --check-prefix=NOTFOUND %s
|
||||||
NOTFOUND: foo.o was not found
|
NOTFOUND: foo.o was not found
|
||||||
|
@ -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
|
RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=BSD %s
|
||||||
|
|
||||||
BSD: !<arch>
|
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
|
Each [[:space:]] matches a newline. We explicitly match 3 newlines, as the
|
||||||
fourth newline is implicitly consumed by FileCheck and cannot be matched.
|
fourth newline is implicitly consumed by FileCheck and cannot be matched.
|
||||||
BSD-NEXT: 0123456789abcde{{.....}}bar.{{[[:space:]][[:space:]][[:space:]]}}
|
DARWIN-NEXT: 0123456789abcde{{.....}}bar.{{[[:space:]][[:space:]][[:space:]]}}
|
||||||
BSD-NEXT: #1/20 0 0 0 644 28 `
|
DARWIN-NEXT: #1/20 0 0 0 644 28 `
|
||||||
BSD-NEXT: 0123456789abcdef{{....}}zed.
|
DARWIN-NEXT: 0123456789abcdef{{....}}zed.
|
||||||
|
|
||||||
|
|
||||||
RUN: rm -f test.a
|
RUN: rm -f test.a
|
||||||
RUN: llvm-ar --format=gnu rcT test.a 0123456789abcde 0123456789abcdef
|
RUN: llvm-ar --format=gnu rcT test.a 0123456789abcde 0123456789abcdef
|
||||||
|
19
test/Object/archive-pad.test
Normal file
19
test/Object/archive-pad.test
Normal file
@ -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
|
@ -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"));
|
static cl::opt<std::string> Plugin("plugin", cl::desc("plugin (ignored for compatibility"));
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum Format { Default, GNU, BSD };
|
enum Format { Default, GNU, BSD, DARWIN };
|
||||||
}
|
}
|
||||||
|
|
||||||
static cl::opt<Format>
|
static cl::opt<Format>
|
||||||
FormatOpt("format", cl::desc("Archive format to create"),
|
FormatOpt("format", cl::desc("Archive format to create"),
|
||||||
cl::values(clEnumValN(Default, "default", "default"),
|
cl::values(clEnumValN(Default, "default", "default"),
|
||||||
clEnumValN(GNU, "gnu", "gnu"),
|
clEnumValN(GNU, "gnu", "gnu"),
|
||||||
|
clEnumValN(DARWIN, "darwin", "darwin"),
|
||||||
clEnumValN(BSD, "bsd", "bsd")));
|
clEnumValN(BSD, "bsd", "bsd")));
|
||||||
|
|
||||||
static std::string Options;
|
static std::string Options;
|
||||||
@ -623,8 +624,9 @@ computeNewArchiveMembers(ArchiveOperation Operation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static object::Archive::Kind getDefaultForHost() {
|
static object::Archive::Kind getDefaultForHost() {
|
||||||
return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_BSD
|
return Triple(sys::getProcessTriple()).isOSDarwin()
|
||||||
: object::Archive::K_GNU;
|
? object::Archive::K_DARWIN
|
||||||
|
: object::Archive::K_GNU;
|
||||||
}
|
}
|
||||||
|
|
||||||
static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
|
static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
|
||||||
@ -633,7 +635,7 @@ static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
|
|||||||
|
|
||||||
if (OptionalObject)
|
if (OptionalObject)
|
||||||
return isa<object::MachOObjectFile>(**OptionalObject)
|
return isa<object::MachOObjectFile>(**OptionalObject)
|
||||||
? object::Archive::K_BSD
|
? object::Archive::K_DARWIN
|
||||||
: object::Archive::K_GNU;
|
: object::Archive::K_GNU;
|
||||||
|
|
||||||
// squelch the error in case we had a non-object file
|
// 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");
|
fail("Only the gnu format has a thin mode");
|
||||||
Kind = object::Archive::K_BSD;
|
Kind = object::Archive::K_BSD;
|
||||||
break;
|
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 =
|
std::pair<StringRef, std::error_code> Result =
|
||||||
|
Loading…
Reference in New Issue
Block a user