diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 | 
| commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
| tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /lib/Object/ArchiveWriter.cpp | |
| parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) | |
Notes
Diffstat (limited to 'lib/Object/ArchiveWriter.cpp')
| -rw-r--r-- | lib/Object/ArchiveWriter.cpp | 73 | 
1 files changed, 52 insertions, 21 deletions
diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp index f8e3c5a0a03f..5b233aab2018 100644 --- a/lib/Object/ArchiveWriter.cpp +++ b/lib/Object/ArchiveWriter.cpp @@ -122,12 +122,27 @@ 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: +    break; +  } +  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 +193,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 +300,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 +322,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      } @@ -316,10 +331,21 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,    if (HeaderStartOffset == 0)      return 0; +  // ld64 prefers the cctools type archive which pads its string table to a +  // boundary of sizeof(int32_t). +  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; +  // If there are no symbols, emit an empty symbol table, to satisfy Solaris +  // tools, older versions of which expect a symbol table in a non-empty +  // archive, regardless of whether there are any symbols in it. +  if (StringTable.size() == 0) +    print32(Out, Kind, 0);    // ld64 requires the next member header to start at an offset that is    // 4 bytes aligned. @@ -336,10 +362,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; @@ -351,8 +377,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", @@ -368,10 +393,6 @@ llvm::writeArchive(StringRef ArcName,    std::vector<unsigned> MemberOffsetRefs; -  std::vector<std::unique_ptr<MemoryBuffer>> Buffers; -  std::vector<MemoryBufferRef> Members; -  std::vector<sys::fs::file_status> NewMemberStatus; -    unsigned MemberReferenceOffset = 0;    if (WriteSymtab) {      ErrorOr<unsigned> MemberReferenceOffsetOrErr = writeSymbolTable( @@ -382,25 +403,35 @@ 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();    std::vector<unsigned> MemberOffset;    for (const NewArchiveMember &M : NewMembers) {      MemoryBufferRef File = M.Buf->getMemBufferRef(); +    unsigned Padding = 0;      unsigned Pos = Out.tell();      MemberOffset.push_back(Pos); +    // ld64 expects the members to be 8-byte aligned for 64-bit content and at +    // 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_DARWIN) +      Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8); +      printMemberHeader(Out, Kind, Thin,                        sys::path::filename(M.Buf->getBufferIdentifier()),                        StringMapIndexIter, M.ModTime, M.UID, M.GID, M.Perms, -                      M.Buf->getBufferSize()); +                      M.Buf->getBufferSize() + Padding);      if (!Thin)        Out << File.getBuffer(); +    while (Padding--) +      Out << '\n';      if (Out.tell() % 2)        Out << '\n';    } @@ -408,7 +439,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]);      }  | 
