From 23a76be5adcaa768ba538f8a4514a7afccf61988 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 21 Feb 2017 20:40:54 +0000 Subject: 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 --- llvm/lib/Object/ArchiveWriter.cpp | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'llvm/lib/Object/ArchiveWriter.cpp') 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(Out).write(Val); - else + if (isBSDLike(Kind)) support::endian::Writer(Out).write(Val); + else + support::endian::Writer(Out).write(Val); } static void printRestOfMemberHeader( @@ -178,7 +192,7 @@ printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind, bool Thin, std::vector::iterator &StringMapIndexIter, const sys::TimePoint &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 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 StringMapIndexes; - if (Kind != object::Archive::K_BSD) + if (!isBSDLike(Kind)) writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); std::vector::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]); } -- cgit v1.2.3