Home | History | Annotate | Line # | Download | only in Object
      1 //===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file defines the writeArchive function.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "llvm/Object/ArchiveWriter.h"
     14 #include "llvm/ADT/ArrayRef.h"
     15 #include "llvm/ADT/StringMap.h"
     16 #include "llvm/ADT/StringRef.h"
     17 #include "llvm/BinaryFormat/Magic.h"
     18 #include "llvm/IR/LLVMContext.h"
     19 #include "llvm/Object/Archive.h"
     20 #include "llvm/Object/Error.h"
     21 #include "llvm/Object/ObjectFile.h"
     22 #include "llvm/Object/SymbolicFile.h"
     23 #include "llvm/Support/Alignment.h"
     24 #include "llvm/Support/EndianStream.h"
     25 #include "llvm/Support/Errc.h"
     26 #include "llvm/Support/ErrorHandling.h"
     27 #include "llvm/Support/Format.h"
     28 #include "llvm/Support/Path.h"
     29 #include "llvm/Support/SmallVectorMemoryBuffer.h"
     30 #include "llvm/Support/ToolOutputFile.h"
     31 #include "llvm/Support/raw_ostream.h"
     32 
     33 #include <map>
     34 
     35 #if !defined(_MSC_VER) && !defined(__MINGW32__)
     36 #include <unistd.h>
     37 #else
     38 #include <io.h>
     39 #endif
     40 
     41 using namespace llvm;
     42 
     43 NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
     44     : Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
     45       MemberName(BufRef.getBufferIdentifier()) {}
     46 
     47 Expected<NewArchiveMember>
     48 NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
     49                                bool Deterministic) {
     50   Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
     51   if (!BufOrErr)
     52     return BufOrErr.takeError();
     53 
     54   NewArchiveMember M;
     55   M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
     56   M.MemberName = M.Buf->getBufferIdentifier();
     57   if (!Deterministic) {
     58     auto ModTimeOrErr = OldMember.getLastModified();
     59     if (!ModTimeOrErr)
     60       return ModTimeOrErr.takeError();
     61     M.ModTime = ModTimeOrErr.get();
     62     Expected<unsigned> UIDOrErr = OldMember.getUID();
     63     if (!UIDOrErr)
     64       return UIDOrErr.takeError();
     65     M.UID = UIDOrErr.get();
     66     Expected<unsigned> GIDOrErr = OldMember.getGID();
     67     if (!GIDOrErr)
     68       return GIDOrErr.takeError();
     69     M.GID = GIDOrErr.get();
     70     Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
     71     if (!AccessModeOrErr)
     72       return AccessModeOrErr.takeError();
     73     M.Perms = AccessModeOrErr.get();
     74   }
     75   return std::move(M);
     76 }
     77 
     78 Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
     79                                                      bool Deterministic) {
     80   sys::fs::file_status Status;
     81   auto FDOrErr = sys::fs::openNativeFileForRead(FileName);
     82   if (!FDOrErr)
     83     return FDOrErr.takeError();
     84   sys::fs::file_t FD = *FDOrErr;
     85   assert(FD != sys::fs::kInvalidFile);
     86 
     87   if (auto EC = sys::fs::status(FD, Status))
     88     return errorCodeToError(EC);
     89 
     90   // Opening a directory doesn't make sense. Let it fail.
     91   // Linux cannot open directories with open(2), although
     92   // cygwin and *bsd can.
     93   if (Status.type() == sys::fs::file_type::directory_file)
     94     return errorCodeToError(make_error_code(errc::is_a_directory));
     95 
     96   ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
     97       MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
     98   if (!MemberBufferOrErr)
     99     return errorCodeToError(MemberBufferOrErr.getError());
    100 
    101   if (auto EC = sys::fs::closeFile(FD))
    102     return errorCodeToError(EC);
    103 
    104   NewArchiveMember M;
    105   M.Buf = std::move(*MemberBufferOrErr);
    106   M.MemberName = M.Buf->getBufferIdentifier();
    107   if (!Deterministic) {
    108     M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
    109         Status.getLastModificationTime());
    110     M.UID = Status.getUser();
    111     M.GID = Status.getGroup();
    112     M.Perms = Status.permissions();
    113   }
    114   return std::move(M);
    115 }
    116 
    117 template <typename T>
    118 static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
    119   uint64_t OldPos = OS.tell();
    120   OS << Data;
    121   unsigned SizeSoFar = OS.tell() - OldPos;
    122   assert(SizeSoFar <= Size && "Data doesn't fit in Size");
    123   OS.indent(Size - SizeSoFar);
    124 }
    125 
    126 static bool isDarwin(object::Archive::Kind Kind) {
    127   return Kind == object::Archive::K_DARWIN ||
    128          Kind == object::Archive::K_DARWIN64;
    129 }
    130 
    131 static bool isBSDLike(object::Archive::Kind Kind) {
    132   switch (Kind) {
    133   case object::Archive::K_GNU:
    134   case object::Archive::K_GNU64:
    135     return false;
    136   case object::Archive::K_BSD:
    137   case object::Archive::K_DARWIN:
    138   case object::Archive::K_DARWIN64:
    139     return true;
    140   case object::Archive::K_COFF:
    141     break;
    142   }
    143   llvm_unreachable("not supported for writting");
    144 }
    145 
    146 template <class T>
    147 static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
    148   support::endian::write(Out, Val,
    149                          isBSDLike(Kind) ? support::little : support::big);
    150 }
    151 
    152 static void printRestOfMemberHeader(
    153     raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
    154     unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
    155   printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
    156 
    157   // The format has only 6 chars for uid and gid. Truncate if the provided
    158   // values don't fit.
    159   printWithSpacePadding(Out, UID % 1000000, 6);
    160   printWithSpacePadding(Out, GID % 1000000, 6);
    161 
    162   printWithSpacePadding(Out, format("%o", Perms), 8);
    163   printWithSpacePadding(Out, Size, 10);
    164   Out << "`\n";
    165 }
    166 
    167 static void
    168 printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
    169                           const sys::TimePoint<std::chrono::seconds> &ModTime,
    170                           unsigned UID, unsigned GID, unsigned Perms,
    171                           uint64_t Size) {
    172   printWithSpacePadding(Out, Twine(Name) + "/", 16);
    173   printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
    174 }
    175 
    176 static void
    177 printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
    178                      const sys::TimePoint<std::chrono::seconds> &ModTime,
    179                      unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
    180   uint64_t PosAfterHeader = Pos + 60 + Name.size();
    181   // Pad so that even 64 bit object files are aligned.
    182   unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8));
    183   unsigned NameWithPadding = Name.size() + Pad;
    184   printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
    185   printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
    186                           NameWithPadding + Size);
    187   Out << Name;
    188   while (Pad--)
    189     Out.write(uint8_t(0));
    190 }
    191 
    192 static bool useStringTable(bool Thin, StringRef Name) {
    193   return Thin || Name.size() >= 16 || Name.contains('/');
    194 }
    195 
    196 static bool is64BitKind(object::Archive::Kind Kind) {
    197   switch (Kind) {
    198   case object::Archive::K_GNU:
    199   case object::Archive::K_BSD:
    200   case object::Archive::K_DARWIN:
    201   case object::Archive::K_COFF:
    202     return false;
    203   case object::Archive::K_DARWIN64:
    204   case object::Archive::K_GNU64:
    205     return true;
    206   }
    207   llvm_unreachable("not supported for writting");
    208 }
    209 
    210 static void
    211 printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
    212                   StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
    213                   bool Thin, const NewArchiveMember &M,
    214                   sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
    215   if (isBSDLike(Kind))
    216     return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
    217                                 M.Perms, Size);
    218   if (!useStringTable(Thin, M.MemberName))
    219     return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
    220                                      M.Perms, Size);
    221   Out << '/';
    222   uint64_t NamePos;
    223   if (Thin) {
    224     NamePos = StringTable.tell();
    225     StringTable << M.MemberName << "/\n";
    226   } else {
    227     auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
    228     if (Insertion.second) {
    229       Insertion.first->second = StringTable.tell();
    230       StringTable << M.MemberName << "/\n";
    231     }
    232     NamePos = Insertion.first->second;
    233   }
    234   printWithSpacePadding(Out, NamePos, 15);
    235   printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size);
    236 }
    237 
    238 namespace {
    239 struct MemberData {
    240   std::vector<unsigned> Symbols;
    241   std::string Header;
    242   StringRef Data;
    243   StringRef Padding;
    244 };
    245 } // namespace
    246 
    247 static MemberData computeStringTable(StringRef Names) {
    248   unsigned Size = Names.size();
    249   unsigned Pad = offsetToAlignment(Size, Align(2));
    250   std::string Header;
    251   raw_string_ostream Out(Header);
    252   printWithSpacePadding(Out, "//", 48);
    253   printWithSpacePadding(Out, Size + Pad, 10);
    254   Out << "`\n";
    255   Out.flush();
    256   return {{}, std::move(Header), Names, Pad ? "\n" : ""};
    257 }
    258 
    259 static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) {
    260   using namespace std::chrono;
    261 
    262   if (!Deterministic)
    263     return time_point_cast<seconds>(system_clock::now());
    264   return sys::TimePoint<seconds>();
    265 }
    266 
    267 static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
    268   Expected<uint32_t> SymFlagsOrErr = S.getFlags();
    269   if (!SymFlagsOrErr)
    270     // TODO: Actually report errors helpfully.
    271     report_fatal_error(SymFlagsOrErr.takeError());
    272   if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
    273     return false;
    274   if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
    275     return false;
    276   if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
    277     return false;
    278   return true;
    279 }
    280 
    281 static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
    282                        uint64_t Val) {
    283   if (is64BitKind(Kind))
    284     print<uint64_t>(Out, Kind, Val);
    285   else
    286     print<uint32_t>(Out, Kind, Val);
    287 }
    288 
    289 static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
    290                                        uint64_t NumSyms, uint64_t OffsetSize,
    291                                        StringRef StringTable,
    292                                        uint32_t *Padding = nullptr) {
    293   assert((OffsetSize == 4 || OffsetSize == 8) && "Unsupported OffsetSize");
    294   uint64_t Size = OffsetSize; // Number of entries
    295   if (isBSDLike(Kind))
    296     Size += NumSyms * OffsetSize * 2; // Table
    297   else
    298     Size += NumSyms * OffsetSize; // Table
    299   if (isBSDLike(Kind))
    300     Size += OffsetSize; // byte count
    301   Size += StringTable.size();
    302   // ld64 expects the members to be 8-byte aligned for 64-bit content and at
    303   // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
    304   // uniformly.
    305   // We do this for all bsd formats because it simplifies aligning members.
    306   uint32_t Pad = offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
    307   Size += Pad;
    308   if (Padding)
    309     *Padding = Pad;
    310   return Size;
    311 }
    312 
    313 static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
    314                                    bool Deterministic, uint64_t Size) {
    315   if (isBSDLike(Kind)) {
    316     const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
    317     printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
    318                          Size);
    319   } else {
    320     const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
    321     printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
    322   }
    323 }
    324 
    325 static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
    326                              bool Deterministic, ArrayRef<MemberData> Members,
    327                              StringRef StringTable) {
    328   // We don't write a symbol table on an archive with no members -- except on
    329   // Darwin, where the linker will abort unless the archive has a symbol table.
    330   if (StringTable.empty() && !isDarwin(Kind))
    331     return;
    332 
    333   unsigned NumSyms = 0;
    334   for (const MemberData &M : Members)
    335     NumSyms += M.Symbols.size();
    336 
    337   uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
    338   uint32_t Pad;
    339   uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, StringTable, &Pad);
    340   writeSymbolTableHeader(Out, Kind, Deterministic, Size);
    341 
    342   uint64_t Pos = Out.tell() + Size;
    343 
    344   if (isBSDLike(Kind))
    345     printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
    346   else
    347     printNBits(Out, Kind, NumSyms);
    348 
    349   for (const MemberData &M : Members) {
    350     for (unsigned StringOffset : M.Symbols) {
    351       if (isBSDLike(Kind))
    352         printNBits(Out, Kind, StringOffset);
    353       printNBits(Out, Kind, Pos); // member offset
    354     }
    355     Pos += M.Header.size() + M.Data.size() + M.Padding.size();
    356   }
    357 
    358   if (isBSDLike(Kind))
    359     // byte count of the string table
    360     printNBits(Out, Kind, StringTable.size());
    361   Out << StringTable;
    362 
    363   while (Pad--)
    364     Out.write(uint8_t(0));
    365 }
    366 
    367 static Expected<std::vector<unsigned>>
    368 getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
    369   std::vector<unsigned> Ret;
    370 
    371   // In the scenario when LLVMContext is populated SymbolicFile will contain a
    372   // reference to it, thus SymbolicFile should be destroyed first.
    373   LLVMContext Context;
    374   std::unique_ptr<object::SymbolicFile> Obj;
    375 
    376   const file_magic Type = identify_magic(Buf.getBuffer());
    377   // Treat unsupported file types as having no symbols.
    378   if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
    379     return Ret;
    380   if (Type == file_magic::bitcode) {
    381     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
    382         Buf, file_magic::bitcode, &Context);
    383     if (!ObjOrErr)
    384       return ObjOrErr.takeError();
    385     Obj = std::move(*ObjOrErr);
    386   } else {
    387     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
    388     if (!ObjOrErr)
    389       return ObjOrErr.takeError();
    390     Obj = std::move(*ObjOrErr);
    391   }
    392 
    393   HasObject = true;
    394   for (const object::BasicSymbolRef &S : Obj->symbols()) {
    395     if (!isArchiveSymbol(S))
    396       continue;
    397     Ret.push_back(SymNames.tell());
    398     if (Error E = S.printName(SymNames))
    399       return std::move(E);
    400     SymNames << '\0';
    401   }
    402   return Ret;
    403 }
    404 
    405 static Expected<std::vector<MemberData>>
    406 computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
    407                   object::Archive::Kind Kind, bool Thin, bool Deterministic,
    408                   bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
    409   static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
    410 
    411   // This ignores the symbol table, but we only need the value mod 8 and the
    412   // symbol table is aligned to be a multiple of 8 bytes
    413   uint64_t Pos = 0;
    414 
    415   std::vector<MemberData> Ret;
    416   bool HasObject = false;
    417 
    418   // Deduplicate long member names in the string table and reuse earlier name
    419   // offsets. This especially saves space for COFF Import libraries where all
    420   // members have the same name.
    421   StringMap<uint64_t> MemberNames;
    422 
    423   // UniqueTimestamps is a special case to improve debugging on Darwin:
    424   //
    425   // The Darwin linker does not link debug info into the final
    426   // binary. Instead, it emits entries of type N_OSO in in the output
    427   // binary's symbol table, containing references to the linked-in
    428   // object files. Using that reference, the debugger can read the
    429   // debug data directly from the object files. Alternatively, an
    430   // invocation of 'dsymutil' will link the debug data from the object
    431   // files into a dSYM bundle, which can be loaded by the debugger,
    432   // instead of the object files.
    433   //
    434   // For an object file, the N_OSO entries contain the absolute path
    435   // path to the file, and the file's timestamp. For an object
    436   // included in an archive, the path is formatted like
    437   // "/absolute/path/to/archive.a(member.o)", and the timestamp is the
    438   // archive member's timestamp, rather than the archive's timestamp.
    439   //
    440   // However, this doesn't always uniquely identify an object within
    441   // an archive -- an archive file can have multiple entries with the
    442   // same filename. (This will happen commonly if the original object
    443   // files started in different directories.) The only way they get
    444   // distinguished, then, is via the timestamp. But this process is
    445   // unable to find the correct object file in the archive when there
    446   // are two files of the same name and timestamp.
    447   //
    448   // Additionally, timestamp==0 is treated specially, and causes the
    449   // timestamp to be ignored as a match criteria.
    450   //
    451   // That will "usually" work out okay when creating an archive not in
    452   // deterministic timestamp mode, because the objects will probably
    453   // have been created at different timestamps.
    454   //
    455   // To ameliorate this problem, in deterministic archive mode (which
    456   // is the default), on Darwin we will emit a unique non-zero
    457   // timestamp for each entry with a duplicated name. This is still
    458   // deterministic: the only thing affecting that timestamp is the
    459   // order of the files in the resultant archive.
    460   //
    461   // See also the functions that handle the lookup:
    462   // in lldb: ObjectContainerBSDArchive::Archive::FindObject()
    463   // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
    464   bool UniqueTimestamps = Deterministic && isDarwin(Kind);
    465   std::map<StringRef, unsigned> FilenameCount;
    466   if (UniqueTimestamps) {
    467     for (const NewArchiveMember &M : NewMembers)
    468       FilenameCount[M.MemberName]++;
    469     for (auto &Entry : FilenameCount)
    470       Entry.second = Entry.second > 1 ? 1 : 0;
    471   }
    472 
    473   for (const NewArchiveMember &M : NewMembers) {
    474     std::string Header;
    475     raw_string_ostream Out(Header);
    476 
    477     MemoryBufferRef Buf = M.Buf->getMemBufferRef();
    478     StringRef Data = Thin ? "" : Buf.getBuffer();
    479 
    480     // ld64 expects the members to be 8-byte aligned for 64-bit content and at
    481     // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
    482     // uniformly.  This matches the behaviour with cctools and ensures that ld64
    483     // is happy with archives that we generate.
    484     unsigned MemberPadding =
    485         isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0;
    486     unsigned TailPadding =
    487         offsetToAlignment(Data.size() + MemberPadding, Align(2));
    488     StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
    489 
    490     sys::TimePoint<std::chrono::seconds> ModTime;
    491     if (UniqueTimestamps)
    492       // Increment timestamp for each file of a given name.
    493       ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
    494     else
    495       ModTime = M.ModTime;
    496 
    497     uint64_t Size = Buf.getBufferSize() + MemberPadding;
    498     if (Size > object::Archive::MaxMemberSize) {
    499       std::string StringMsg =
    500           "File " + M.MemberName.str() + " exceeds size limit";
    501       return make_error<object::GenericBinaryError>(
    502           std::move(StringMsg), object::object_error::parse_failed);
    503     }
    504 
    505     printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
    506                       ModTime, Size);
    507     Out.flush();
    508 
    509     std::vector<unsigned> Symbols;
    510     if (NeedSymbols) {
    511       Expected<std::vector<unsigned>> SymbolsOrErr =
    512           getSymbols(Buf, SymNames, HasObject);
    513       if (auto E = SymbolsOrErr.takeError())
    514         return std::move(E);
    515       Symbols = std::move(*SymbolsOrErr);
    516     }
    517 
    518     Pos += Header.size() + Data.size() + Padding.size();
    519     Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding});
    520   }
    521   // If there are no symbols, emit an empty symbol table, to satisfy Solaris
    522   // tools, older versions of which expect a symbol table in a non-empty
    523   // archive, regardless of whether there are any symbols in it.
    524   if (HasObject && SymNames.tell() == 0)
    525     SymNames << '\0' << '\0' << '\0';
    526   return Ret;
    527 }
    528 
    529 namespace llvm {
    530 
    531 static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) {
    532   SmallString<128> Ret = P;
    533   std::error_code Err = sys::fs::make_absolute(Ret);
    534   if (Err)
    535     return Err;
    536   sys::path::remove_dots(Ret, /*removedotdot*/ true);
    537   return Ret;
    538 }
    539 
    540 // Compute the relative path from From to To.
    541 Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
    542   ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To);
    543   ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From);
    544   if (!PathToOrErr || !DirFromOrErr)
    545     return errorCodeToError(std::error_code(errno, std::generic_category()));
    546 
    547   const SmallString<128> &PathTo = *PathToOrErr;
    548   const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
    549 
    550   // Can't construct a relative path between different roots
    551   if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
    552     return sys::path::convert_to_slash(PathTo);
    553 
    554   // Skip common prefixes
    555   auto FromTo =
    556       std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
    557                     sys::path::begin(PathTo));
    558   auto FromI = FromTo.first;
    559   auto ToI = FromTo.second;
    560 
    561   // Construct relative path
    562   SmallString<128> Relative;
    563   for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
    564     sys::path::append(Relative, sys::path::Style::posix, "..");
    565 
    566   for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
    567     sys::path::append(Relative, sys::path::Style::posix, *ToI);
    568 
    569   return std::string(Relative.str());
    570 }
    571 
    572 static Error writeArchiveToStream(raw_ostream &Out,
    573                                   ArrayRef<NewArchiveMember> NewMembers,
    574                                   bool WriteSymtab, object::Archive::Kind Kind,
    575                                   bool Deterministic, bool Thin) {
    576   assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
    577 
    578   SmallString<0> SymNamesBuf;
    579   raw_svector_ostream SymNames(SymNamesBuf);
    580   SmallString<0> StringTableBuf;
    581   raw_svector_ostream StringTable(StringTableBuf);
    582 
    583   Expected<std::vector<MemberData>> DataOrErr =
    584       computeMemberData(StringTable, SymNames, Kind, Thin, Deterministic,
    585                         WriteSymtab, NewMembers);
    586   if (Error E = DataOrErr.takeError())
    587     return E;
    588   std::vector<MemberData> &Data = *DataOrErr;
    589 
    590   if (!StringTableBuf.empty())
    591     Data.insert(Data.begin(), computeStringTable(StringTableBuf));
    592 
    593   // We would like to detect if we need to switch to a 64-bit symbol table.
    594   if (WriteSymtab) {
    595     uint64_t MaxOffset = 8; // For the file signature.
    596     uint64_t LastOffset = MaxOffset;
    597     uint64_t NumSyms = 0;
    598     for (const auto &M : Data) {
    599       // Record the start of the member's offset
    600       LastOffset = MaxOffset;
    601       // Account for the size of each part associated with the member.
    602       MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
    603       NumSyms += M.Symbols.size();
    604     }
    605 
    606     // We assume 32-bit offsets to see if 32-bit symbols are possible or not.
    607     uint64_t SymtabSize = computeSymbolTableSize(Kind, NumSyms, 4, SymNamesBuf);
    608     auto computeSymbolTableHeaderSize =
    609         [=] {
    610           SmallString<0> TmpBuf;
    611           raw_svector_ostream Tmp(TmpBuf);
    612           writeSymbolTableHeader(Tmp, Kind, Deterministic, SymtabSize);
    613           return TmpBuf.size();
    614         };
    615     LastOffset += computeSymbolTableHeaderSize() + SymtabSize;
    616 
    617     // The SYM64 format is used when an archive's member offsets are larger than
    618     // 32-bits can hold. The need for this shift in format is detected by
    619     // writeArchive. To test this we need to generate a file with a member that
    620     // has an offset larger than 32-bits but this demands a very slow test. To
    621     // speed the test up we use this environment variable to pretend like the
    622     // cutoff happens before 32-bits and instead happens at some much smaller
    623     // value.
    624     uint64_t Sym64Threshold = 1ULL << 32;
    625     const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
    626     if (Sym64Env)
    627       StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
    628 
    629     // If LastOffset isn't going to fit in a 32-bit varible we need to switch
    630     // to 64-bit. Note that the file can be larger than 4GB as long as the last
    631     // member starts before the 4GB offset.
    632     if (LastOffset >= Sym64Threshold) {
    633       if (Kind == object::Archive::K_DARWIN)
    634         Kind = object::Archive::K_DARWIN64;
    635       else
    636         Kind = object::Archive::K_GNU64;
    637     }
    638   }
    639 
    640   if (Thin)
    641     Out << "!<thin>\n";
    642   else
    643     Out << "!<arch>\n";
    644 
    645   if (WriteSymtab)
    646     writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
    647 
    648   for (const MemberData &M : Data)
    649     Out << M.Header << M.Data << M.Padding;
    650 
    651   Out.flush();
    652   return Error::success();
    653 }
    654 
    655 Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
    656                    bool WriteSymtab, object::Archive::Kind Kind,
    657                    bool Deterministic, bool Thin,
    658                    std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
    659   Expected<sys::fs::TempFile> Temp =
    660       sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
    661   if (!Temp)
    662     return Temp.takeError();
    663   raw_fd_ostream Out(Temp->FD, false);
    664 
    665   if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind,
    666                                      Deterministic, Thin)) {
    667     if (Error DiscardError = Temp->discard())
    668       return joinErrors(std::move(E), std::move(DiscardError));
    669     return E;
    670   }
    671 
    672   // At this point, we no longer need whatever backing memory
    673   // was used to generate the NewMembers. On Windows, this buffer
    674   // could be a mapped view of the file we want to replace (if
    675   // we're updating an existing archive, say). In that case, the
    676   // rename would still succeed, but it would leave behind a
    677   // temporary file (actually the original file renamed) because
    678   // a file cannot be deleted while there's a handle open on it,
    679   // only renamed. So by freeing this buffer, this ensures that
    680   // the last open handle on the destination file, if any, is
    681   // closed before we attempt to rename.
    682   OldArchiveBuf.reset();
    683 
    684   return Temp->keep(ArcName);
    685 }
    686 
    687 Expected<std::unique_ptr<MemoryBuffer>>
    688 writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab,
    689                      object::Archive::Kind Kind, bool Deterministic,
    690                      bool Thin) {
    691   SmallVector<char, 0> ArchiveBufferVector;
    692   raw_svector_ostream ArchiveStream(ArchiveBufferVector);
    693 
    694   if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab,
    695                                      Kind, Deterministic, Thin))
    696     return std::move(E);
    697 
    698   return std::make_unique<SmallVectorMemoryBuffer>(
    699       std::move(ArchiveBufferVector));
    700 }
    701 
    702 } // namespace llvm
    703