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/COFF.h"
21 #include "llvm/Object/Error.h"
22 #include "llvm/Object/IRObjectFile.h"
23 #include "llvm/Object/MachO.h"
24 #include "llvm/Object/ObjectFile.h"
25 #include "llvm/Object/SymbolicFile.h"
26 #include "llvm/Object/XCOFFObjectFile.h"
27 #include "llvm/Support/Alignment.h"
28 #include "llvm/Support/EndianStream.h"
29 #include "llvm/Support/Errc.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/Format.h"
32 #include "llvm/Support/MathExtras.h"
33 #include "llvm/Support/Path.h"
34 #include "llvm/Support/SmallVectorMemoryBuffer.h"
35 #include "llvm/Support/raw_ostream.h"
36 
37 #include <cerrno>
38 #include <map>
39 
40 #if !defined(_MSC_VER) && !defined(__MINGW32__)
41 #include <unistd.h>
42 #else
43 #include <io.h>
44 #endif
45 
46 using namespace llvm;
47 using namespace llvm::object;
48 
49 struct SymMap {
50   bool UseECMap;
51   std::map<std::string, uint16_t> Map;
52   std::map<std::string, uint16_t> ECMap;
53 };
54 
55 NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
56     : Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
57       MemberName(BufRef.getBufferIdentifier()) {}
58 
59 object::Archive::Kind NewArchiveMember::detectKindFromObject() const {
60   auto MemBufferRef = this->Buf->getMemBufferRef();
61   Expected<std::unique_ptr<object::ObjectFile>> OptionalObject =
62       object::ObjectFile::createObjectFile(MemBufferRef);
63 
64   if (OptionalObject)
65     return isa<object::MachOObjectFile>(**OptionalObject)
66                ? object::Archive::K_DARWIN
67                : (isa<object::XCOFFObjectFile>(**OptionalObject)
68                       ? object::Archive::K_AIXBIG
69                       : object::Archive::K_GNU);
70 
71   // Squelch the error in case we had a non-object file.
72   consumeError(OptionalObject.takeError());
73 
74   // If we're adding a bitcode file to the archive, detect the Archive kind
75   // based on the target triple.
76   LLVMContext Context;
77   if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) {
78     if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
79             MemBufferRef, file_magic::bitcode, &Context)) {
80       auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr);
81       auto TargetTriple = Triple(IRObject.getTargetTriple());
82       return TargetTriple.isOSDarwin()
83                  ? object::Archive::K_DARWIN
84                  : (TargetTriple.isOSAIX() ? object::Archive::K_AIXBIG
85                                            : object::Archive::K_GNU);
86     } else {
87       // Squelch the error in case this was not a SymbolicFile.
88       consumeError(ObjOrErr.takeError());
89     }
90   }
91 
92   return object::Archive::getDefaultKindForHost();
93 }
94 
95 Expected<NewArchiveMember>
96 NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
97                                bool Deterministic) {
98   Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
99   if (!BufOrErr)
100     return BufOrErr.takeError();
101 
102   NewArchiveMember M;
103   M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
104   M.MemberName = M.Buf->getBufferIdentifier();
105   if (!Deterministic) {
106     auto ModTimeOrErr = OldMember.getLastModified();
107     if (!ModTimeOrErr)
108       return ModTimeOrErr.takeError();
109     M.ModTime = ModTimeOrErr.get();
110     Expected<unsigned> UIDOrErr = OldMember.getUID();
111     if (!UIDOrErr)
112       return UIDOrErr.takeError();
113     M.UID = UIDOrErr.get();
114     Expected<unsigned> GIDOrErr = OldMember.getGID();
115     if (!GIDOrErr)
116       return GIDOrErr.takeError();
117     M.GID = GIDOrErr.get();
118     Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
119     if (!AccessModeOrErr)
120       return AccessModeOrErr.takeError();
121     M.Perms = AccessModeOrErr.get();
122   }
123   return std::move(M);
124 }
125 
126 Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
127                                                      bool Deterministic) {
128   sys::fs::file_status Status;
129   auto FDOrErr = sys::fs::openNativeFileForRead(FileName);
130   if (!FDOrErr)
131     return FDOrErr.takeError();
132   sys::fs::file_t FD = *FDOrErr;
133   assert(FD != sys::fs::kInvalidFile);
134 
135   if (auto EC = sys::fs::status(FD, Status))
136     return errorCodeToError(EC);
137 
138   // Opening a directory doesn't make sense. Let it fail.
139   // Linux cannot open directories with open(2), although
140   // cygwin and *bsd can.
141   if (Status.type() == sys::fs::file_type::directory_file)
142     return errorCodeToError(make_error_code(errc::is_a_directory));
143 
144   ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
145       MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
146   if (!MemberBufferOrErr)
147     return errorCodeToError(MemberBufferOrErr.getError());
148 
149   if (auto EC = sys::fs::closeFile(FD))
150     return errorCodeToError(EC);
151 
152   NewArchiveMember M;
153   M.Buf = std::move(*MemberBufferOrErr);
154   M.MemberName = M.Buf->getBufferIdentifier();
155   if (!Deterministic) {
156     M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
157         Status.getLastModificationTime());
158     M.UID = Status.getUser();
159     M.GID = Status.getGroup();
160     M.Perms = Status.permissions();
161   }
162   return std::move(M);
163 }
164 
165 template <typename T>
166 static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
167   uint64_t OldPos = OS.tell();
168   OS << Data;
169   unsigned SizeSoFar = OS.tell() - OldPos;
170   assert(SizeSoFar <= Size && "Data doesn't fit in Size");
171   OS.indent(Size - SizeSoFar);
172 }
173 
174 static bool isDarwin(object::Archive::Kind Kind) {
175   return Kind == object::Archive::K_DARWIN ||
176          Kind == object::Archive::K_DARWIN64;
177 }
178 
179 static bool isAIXBigArchive(object::Archive::Kind Kind) {
180   return Kind == object::Archive::K_AIXBIG;
181 }
182 
183 static bool isCOFFArchive(object::Archive::Kind Kind) {
184   return Kind == object::Archive::K_COFF;
185 }
186 
187 static bool isBSDLike(object::Archive::Kind Kind) {
188   switch (Kind) {
189   case object::Archive::K_GNU:
190   case object::Archive::K_GNU64:
191   case object::Archive::K_AIXBIG:
192   case object::Archive::K_COFF:
193     return false;
194   case object::Archive::K_BSD:
195   case object::Archive::K_DARWIN:
196   case object::Archive::K_DARWIN64:
197     return true;
198   }
199   llvm_unreachable("not supported for writting");
200 }
201 
202 template <class T>
203 static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
204   support::endian::write(Out, Val,
205                          isBSDLike(Kind) ? support::little : support::big);
206 }
207 
208 template <class T> static void printLE(raw_ostream &Out, T Val) {
209   support::endian::write(Out, Val, support::little);
210 }
211 
212 static void printRestOfMemberHeader(
213     raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
214     unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
215   printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
216 
217   // The format has only 6 chars for uid and gid. Truncate if the provided
218   // values don't fit.
219   printWithSpacePadding(Out, UID % 1000000, 6);
220   printWithSpacePadding(Out, GID % 1000000, 6);
221 
222   printWithSpacePadding(Out, format("%o", Perms), 8);
223   printWithSpacePadding(Out, Size, 10);
224   Out << "`\n";
225 }
226 
227 static void
228 printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
229                           const sys::TimePoint<std::chrono::seconds> &ModTime,
230                           unsigned UID, unsigned GID, unsigned Perms,
231                           uint64_t Size) {
232   printWithSpacePadding(Out, Twine(Name) + "/", 16);
233   printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
234 }
235 
236 static void
237 printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
238                      const sys::TimePoint<std::chrono::seconds> &ModTime,
239                      unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
240   uint64_t PosAfterHeader = Pos + 60 + Name.size();
241   // Pad so that even 64 bit object files are aligned.
242   unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8));
243   unsigned NameWithPadding = Name.size() + Pad;
244   printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
245   printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
246                           NameWithPadding + Size);
247   Out << Name;
248   while (Pad--)
249     Out.write(uint8_t(0));
250 }
251 
252 static void
253 printBigArchiveMemberHeader(raw_ostream &Out, StringRef Name,
254                             const sys::TimePoint<std::chrono::seconds> &ModTime,
255                             unsigned UID, unsigned GID, unsigned Perms,
256                             uint64_t Size, uint64_t PrevOffset,
257                             uint64_t NextOffset) {
258   unsigned NameLen = Name.size();
259 
260   printWithSpacePadding(Out, Size, 20);           // File member size
261   printWithSpacePadding(Out, NextOffset, 20);     // Next member header offset
262   printWithSpacePadding(Out, PrevOffset, 20); // Previous member header offset
263   printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); // File member date
264   // The big archive format has 12 chars for uid and gid.
265   printWithSpacePadding(Out, UID % 1000000000000, 12);   // UID
266   printWithSpacePadding(Out, GID % 1000000000000, 12);   // GID
267   printWithSpacePadding(Out, format("%o", Perms), 12);   // Permission
268   printWithSpacePadding(Out, NameLen, 4);                // Name length
269   if (NameLen) {
270     printWithSpacePadding(Out, Name, NameLen); // Name
271     if (NameLen % 2)
272       Out.write(uint8_t(0)); // Null byte padding
273   }
274   Out << "`\n"; // Terminator
275 }
276 
277 static bool useStringTable(bool Thin, StringRef Name) {
278   return Thin || Name.size() >= 16 || Name.contains('/');
279 }
280 
281 static bool is64BitKind(object::Archive::Kind Kind) {
282   switch (Kind) {
283   case object::Archive::K_GNU:
284   case object::Archive::K_BSD:
285   case object::Archive::K_DARWIN:
286   case object::Archive::K_COFF:
287     return false;
288   case object::Archive::K_AIXBIG:
289   case object::Archive::K_DARWIN64:
290   case object::Archive::K_GNU64:
291     return true;
292   }
293   llvm_unreachable("not supported for writting");
294 }
295 
296 static void
297 printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
298                   StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
299                   bool Thin, const NewArchiveMember &M,
300                   sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
301   if (isBSDLike(Kind))
302     return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
303                                 M.Perms, Size);
304   if (!useStringTable(Thin, M.MemberName))
305     return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
306                                      M.Perms, Size);
307   Out << '/';
308   uint64_t NamePos;
309   if (Thin) {
310     NamePos = StringTable.tell();
311     StringTable << M.MemberName << "/\n";
312   } else {
313     auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
314     if (Insertion.second) {
315       Insertion.first->second = StringTable.tell();
316       StringTable << M.MemberName;
317       if (isCOFFArchive(Kind))
318         StringTable << '\0';
319       else
320         StringTable << "/\n";
321     }
322     NamePos = Insertion.first->second;
323   }
324   printWithSpacePadding(Out, NamePos, 15);
325   printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size);
326 }
327 
328 namespace {
329 struct MemberData {
330   std::vector<unsigned> Symbols;
331   std::string Header;
332   StringRef Data;
333   StringRef Padding;
334 };
335 } // namespace
336 
337 static MemberData computeStringTable(StringRef Names) {
338   unsigned Size = Names.size();
339   unsigned Pad = offsetToAlignment(Size, Align(2));
340   std::string Header;
341   raw_string_ostream Out(Header);
342   printWithSpacePadding(Out, "//", 48);
343   printWithSpacePadding(Out, Size + Pad, 10);
344   Out << "`\n";
345   Out.flush();
346   return {{}, std::move(Header), Names, Pad ? "\n" : ""};
347 }
348 
349 static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) {
350   using namespace std::chrono;
351 
352   if (!Deterministic)
353     return time_point_cast<seconds>(system_clock::now());
354   return sys::TimePoint<seconds>();
355 }
356 
357 static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
358   Expected<uint32_t> SymFlagsOrErr = S.getFlags();
359   if (!SymFlagsOrErr)
360     // TODO: Actually report errors helpfully.
361     report_fatal_error(SymFlagsOrErr.takeError());
362   if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
363     return false;
364   if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
365     return false;
366   if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
367     return false;
368   return true;
369 }
370 
371 static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
372                        uint64_t Val) {
373   if (is64BitKind(Kind))
374     print<uint64_t>(Out, Kind, Val);
375   else
376     print<uint32_t>(Out, Kind, Val);
377 }
378 
379 static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
380                                        uint64_t NumSyms, uint64_t OffsetSize,
381                                        uint64_t StringTableSize,
382                                        uint32_t *Padding = nullptr) {
383   assert((OffsetSize == 4 || OffsetSize == 8) && "Unsupported OffsetSize");
384   uint64_t Size = OffsetSize; // Number of entries
385   if (isBSDLike(Kind))
386     Size += NumSyms * OffsetSize * 2; // Table
387   else
388     Size += NumSyms * OffsetSize; // Table
389   if (isBSDLike(Kind))
390     Size += OffsetSize; // byte count
391   Size += StringTableSize;
392   // ld64 expects the members to be 8-byte aligned for 64-bit content and at
393   // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
394   // uniformly.
395   // We do this for all bsd formats because it simplifies aligning members.
396   // For the big archive format, the symbol table is the last member, so there
397   // is no need to align.
398   uint32_t Pad = isAIXBigArchive(Kind)
399                      ? 0
400                      : offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
401 
402   Size += Pad;
403   if (Padding)
404     *Padding = Pad;
405   return Size;
406 }
407 
408 static uint64_t computeSymbolMapSize(uint64_t NumObj, SymMap &SymMap,
409                                      uint32_t *Padding = nullptr) {
410   uint64_t Size = sizeof(uint32_t) * 2; // Number of symbols and objects entries
411   Size += NumObj * sizeof(uint32_t);    // Offset table
412 
413   for (auto S : SymMap.Map)
414     Size += sizeof(uint16_t) + S.first.length() + 1;
415 
416   uint32_t Pad = offsetToAlignment(Size, Align(2));
417   Size += Pad;
418   if (Padding)
419     *Padding = Pad;
420   return Size;
421 }
422 
423 static uint64_t computeECSymbolsSize(SymMap &SymMap,
424                                      uint32_t *Padding = nullptr) {
425   uint64_t Size = sizeof(uint32_t); // Number of symbols
426 
427   for (auto S : SymMap.ECMap)
428     Size += sizeof(uint16_t) + S.first.length() + 1;
429 
430   uint32_t Pad = offsetToAlignment(Size, Align(2));
431   Size += Pad;
432   if (Padding)
433     *Padding = Pad;
434   return Size;
435 }
436 
437 static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
438                                    bool Deterministic, uint64_t Size,
439                                    uint64_t PrevMemberOffset = 0,
440                                    uint64_t NextMemberOffset = 0) {
441   if (isBSDLike(Kind)) {
442     const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
443     printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
444                          Size);
445   } else if (isAIXBigArchive(Kind)) {
446     printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size,
447                                 PrevMemberOffset, NextMemberOffset);
448   } else {
449     const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
450     printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
451   }
452 }
453 
454 static uint64_t computeHeadersSize(object::Archive::Kind Kind,
455                                    uint64_t NumMembers,
456                                    uint64_t StringMemberSize, uint64_t NumSyms,
457                                    uint64_t SymNamesSize, SymMap *SymMap) {
458   uint32_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
459   uint64_t SymtabSize =
460       computeSymbolTableSize(Kind, NumSyms, OffsetSize, SymNamesSize);
461   auto computeSymbolTableHeaderSize = [=] {
462     SmallString<0> TmpBuf;
463     raw_svector_ostream Tmp(TmpBuf);
464     writeSymbolTableHeader(Tmp, Kind, true, SymtabSize);
465     return TmpBuf.size();
466   };
467   uint32_t HeaderSize = computeSymbolTableHeaderSize();
468   uint64_t Size = strlen("!<arch>\n") + HeaderSize + SymtabSize;
469 
470   if (SymMap) {
471     Size += HeaderSize + computeSymbolMapSize(NumMembers, *SymMap);
472     if (SymMap->ECMap.size())
473       Size += HeaderSize + computeECSymbolsSize(*SymMap);
474   }
475 
476   return Size + StringMemberSize;
477 }
478 
479 static Expected<std::unique_ptr<SymbolicFile>>
480 getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) {
481   const file_magic Type = identify_magic(Buf.getBuffer());
482   // Don't attempt to read non-symbolic file types.
483   if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
484     return nullptr;
485   if (Type == file_magic::bitcode) {
486     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
487         Buf, file_magic::bitcode, &Context);
488     if (!ObjOrErr)
489       return ObjOrErr.takeError();
490     return std::move(*ObjOrErr);
491   } else {
492     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
493     if (!ObjOrErr)
494       return ObjOrErr.takeError();
495     return std::move(*ObjOrErr);
496   }
497 }
498 
499 static Expected<bool> is64BitSymbolicFile(const StringRef &ObjStringRef) {
500   MemoryBufferRef ObjMbf(ObjStringRef, "");
501   // In the scenario when LLVMContext is populated SymbolicFile will contain a
502   // reference to it, thus SymbolicFile should be destroyed first.
503   LLVMContext Context;
504   Expected<std::unique_ptr<SymbolicFile>> ObjOrErr =
505       getSymbolicFile(ObjMbf, Context);
506   if (!ObjOrErr)
507     return ObjOrErr.takeError();
508 
509   // Treat non-symbolic file types as not 64-bits.
510   if (!*ObjOrErr)
511     return false;
512 
513   return (*ObjOrErr)->is64Bit();
514 }
515 
516 static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
517                              bool Deterministic, ArrayRef<MemberData> Members,
518                              StringRef StringTable, uint64_t MembersOffset,
519                              unsigned NumSyms, uint64_t PrevMemberOffset = 0,
520                              uint64_t NextMemberOffset = 0,
521                              bool Is64Bit = false) {
522   // We don't write a symbol table on an archive with no members -- except on
523   // Darwin, where the linker will abort unless the archive has a symbol table.
524   if (StringTable.empty() && !isDarwin(Kind) && !isCOFFArchive(Kind))
525     return;
526 
527   uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
528   uint32_t Pad;
529   uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize,
530                                          StringTable.size(), &Pad);
531   writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset,
532                          NextMemberOffset);
533 
534   if (isBSDLike(Kind))
535     printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
536   else
537     printNBits(Out, Kind, NumSyms);
538 
539   uint64_t Pos = MembersOffset;
540   for (const MemberData &M : Members) {
541     if (isAIXBigArchive(Kind)) {
542       Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data);
543       // If there is an error, the error will have been emitted when
544       // 'computeMemberData' called the 'getSymbol' function, so don't need to
545       // handle it here.
546       if (!Is64BitOrErr)
547         cantFail(Is64BitOrErr.takeError());
548       if (*Is64BitOrErr != Is64Bit) {
549         Pos += M.Header.size() + M.Data.size() + M.Padding.size();
550         continue;
551       }
552     }
553 
554     for (unsigned StringOffset : M.Symbols) {
555       if (isBSDLike(Kind))
556         printNBits(Out, Kind, StringOffset);
557       printNBits(Out, Kind, Pos); // member offset
558     }
559     Pos += M.Header.size() + M.Data.size() + M.Padding.size();
560   }
561 
562   if (isBSDLike(Kind))
563     // byte count of the string table
564     printNBits(Out, Kind, StringTable.size());
565   Out << StringTable;
566 
567   while (Pad--)
568     Out.write(uint8_t(0));
569 }
570 
571 static void writeSymbolMap(raw_ostream &Out, object::Archive::Kind Kind,
572                            bool Deterministic, ArrayRef<MemberData> Members,
573                            SymMap &SymMap, uint64_t MembersOffset) {
574   uint32_t Pad;
575   uint64_t Size = computeSymbolMapSize(Members.size(), SymMap, &Pad);
576   writeSymbolTableHeader(Out, Kind, Deterministic, Size, 0);
577 
578   uint32_t Pos = MembersOffset;
579 
580   printLE<uint32_t>(Out, Members.size());
581   for (const MemberData &M : Members) {
582     printLE(Out, Pos); // member offset
583     Pos += M.Header.size() + M.Data.size() + M.Padding.size();
584   }
585 
586   printLE<uint32_t>(Out, SymMap.Map.size());
587 
588   for (auto S : SymMap.Map)
589     printLE(Out, S.second);
590   for (auto S : SymMap.Map)
591     Out << S.first << '\0';
592 
593   while (Pad--)
594     Out.write(uint8_t(0));
595 }
596 
597 static void writeECSymbols(raw_ostream &Out, object::Archive::Kind Kind,
598                            bool Deterministic, ArrayRef<MemberData> Members,
599                            SymMap &SymMap) {
600   uint32_t Pad;
601   uint64_t Size = computeECSymbolsSize(SymMap, &Pad);
602   printGNUSmallMemberHeader(Out, "/<ECSYMBOLS>", now(Deterministic), 0, 0, 0,
603                             Size);
604 
605   printLE<uint32_t>(Out, SymMap.ECMap.size());
606 
607   for (auto S : SymMap.ECMap)
608     printLE(Out, S.second);
609   for (auto S : SymMap.ECMap)
610     Out << S.first << '\0';
611   while (Pad--)
612     Out.write(uint8_t(0));
613 }
614 
615 static bool isECObject(object::SymbolicFile &Obj) {
616   if (Obj.isCOFF())
617     return cast<llvm::object::COFFObjectFile>(&Obj)->getMachine() !=
618            COFF::IMAGE_FILE_MACHINE_ARM64;
619 
620   if (Obj.isIR()) {
621     Expected<std::string> TripleStr =
622         getBitcodeTargetTriple(Obj.getMemoryBufferRef());
623     if (!TripleStr)
624       return false;
625     Triple T(*TripleStr);
626     return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64;
627   }
628 
629   return false;
630 }
631 
632 static Expected<std::vector<unsigned>>
633 getSymbols(MemoryBufferRef Buf, uint16_t Index, raw_ostream &SymNames,
634            SymMap *SymMap, bool &HasObject) {
635   // In the scenario when LLVMContext is populated SymbolicFile will contain a
636   // reference to it, thus SymbolicFile should be destroyed first.
637   LLVMContext Context;
638 
639   std::vector<unsigned> Ret;
640   Expected<std::unique_ptr<SymbolicFile>> ObjOrErr =
641       getSymbolicFile(Buf, Context);
642   if (!ObjOrErr)
643     return ObjOrErr.takeError();
644 
645   // If the member is non-symbolic file, treat it as having no symbols.
646   if (!*ObjOrErr)
647     return Ret;
648 
649   std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr);
650 
651   std::map<std::string, uint16_t> *Map = nullptr;
652   if (SymMap)
653     Map = SymMap->UseECMap && isECObject(*Obj) ? &SymMap->ECMap : &SymMap->Map;
654   HasObject = true;
655   for (const object::BasicSymbolRef &S : Obj->symbols()) {
656     if (!isArchiveSymbol(S))
657       continue;
658     if (Map) {
659       std::string Name;
660       raw_string_ostream NameStream(Name);
661       if (Error E = S.printName(NameStream))
662         return std::move(E);
663       if (Map->find(Name) != Map->end())
664         continue; // ignore duplicated symbol
665       (*Map)[Name] = Index;
666       if (Map == &SymMap->Map) {
667         Ret.push_back(SymNames.tell());
668         SymNames << Name << '\0';
669       }
670     } else {
671       Ret.push_back(SymNames.tell());
672       if (Error E = S.printName(SymNames))
673         return std::move(E);
674       SymNames << '\0';
675     }
676   }
677   return Ret;
678 }
679 
680 static Expected<std::vector<MemberData>>
681 computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
682                   object::Archive::Kind Kind, bool Thin, bool Deterministic,
683                   bool NeedSymbols, SymMap *SymMap,
684                   ArrayRef<NewArchiveMember> NewMembers) {
685   static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
686 
687   uint64_t Pos =
688       isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0;
689 
690   std::vector<MemberData> Ret;
691   bool HasObject = false;
692 
693   // Deduplicate long member names in the string table and reuse earlier name
694   // offsets. This especially saves space for COFF Import libraries where all
695   // members have the same name.
696   StringMap<uint64_t> MemberNames;
697 
698   // UniqueTimestamps is a special case to improve debugging on Darwin:
699   //
700   // The Darwin linker does not link debug info into the final
701   // binary. Instead, it emits entries of type N_OSO in in the output
702   // binary's symbol table, containing references to the linked-in
703   // object files. Using that reference, the debugger can read the
704   // debug data directly from the object files. Alternatively, an
705   // invocation of 'dsymutil' will link the debug data from the object
706   // files into a dSYM bundle, which can be loaded by the debugger,
707   // instead of the object files.
708   //
709   // For an object file, the N_OSO entries contain the absolute path
710   // path to the file, and the file's timestamp. For an object
711   // included in an archive, the path is formatted like
712   // "/absolute/path/to/archive.a(member.o)", and the timestamp is the
713   // archive member's timestamp, rather than the archive's timestamp.
714   //
715   // However, this doesn't always uniquely identify an object within
716   // an archive -- an archive file can have multiple entries with the
717   // same filename. (This will happen commonly if the original object
718   // files started in different directories.) The only way they get
719   // distinguished, then, is via the timestamp. But this process is
720   // unable to find the correct object file in the archive when there
721   // are two files of the same name and timestamp.
722   //
723   // Additionally, timestamp==0 is treated specially, and causes the
724   // timestamp to be ignored as a match criteria.
725   //
726   // That will "usually" work out okay when creating an archive not in
727   // deterministic timestamp mode, because the objects will probably
728   // have been created at different timestamps.
729   //
730   // To ameliorate this problem, in deterministic archive mode (which
731   // is the default), on Darwin we will emit a unique non-zero
732   // timestamp for each entry with a duplicated name. This is still
733   // deterministic: the only thing affecting that timestamp is the
734   // order of the files in the resultant archive.
735   //
736   // See also the functions that handle the lookup:
737   // in lldb: ObjectContainerBSDArchive::Archive::FindObject()
738   // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
739   bool UniqueTimestamps = Deterministic && isDarwin(Kind);
740   std::map<StringRef, unsigned> FilenameCount;
741   if (UniqueTimestamps) {
742     for (const NewArchiveMember &M : NewMembers)
743       FilenameCount[M.MemberName]++;
744     for (auto &Entry : FilenameCount)
745       Entry.second = Entry.second > 1 ? 1 : 0;
746   }
747 
748   // The big archive format needs to know the offset of the previous member
749   // header.
750   uint64_t PrevOffset = 0;
751   uint16_t Index = 0;
752   for (const NewArchiveMember &M : NewMembers) {
753     std::string Header;
754     raw_string_ostream Out(Header);
755 
756     MemoryBufferRef Buf = M.Buf->getMemBufferRef();
757     StringRef Data = Thin ? "" : Buf.getBuffer();
758 
759     Index++;
760 
761     // ld64 expects the members to be 8-byte aligned for 64-bit content and at
762     // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
763     // uniformly.  This matches the behaviour with cctools and ensures that ld64
764     // is happy with archives that we generate.
765     unsigned MemberPadding =
766         isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0;
767     unsigned TailPadding =
768         offsetToAlignment(Data.size() + MemberPadding, Align(2));
769     StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
770 
771     sys::TimePoint<std::chrono::seconds> ModTime;
772     if (UniqueTimestamps)
773       // Increment timestamp for each file of a given name.
774       ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
775     else
776       ModTime = M.ModTime;
777 
778     uint64_t Size = Buf.getBufferSize() + MemberPadding;
779     if (Size > object::Archive::MaxMemberSize) {
780       std::string StringMsg =
781           "File " + M.MemberName.str() + " exceeds size limit";
782       return make_error<object::GenericBinaryError>(
783           std::move(StringMsg), object::object_error::parse_failed);
784     }
785 
786     if (isAIXBigArchive(Kind)) {
787       uint64_t NextOffset = Pos + sizeof(object::BigArMemHdrType) +
788                             alignTo(M.MemberName.size(), 2) + alignTo(Size, 2);
789       printBigArchiveMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
790                                   M.Perms, Size, PrevOffset, NextOffset);
791       PrevOffset = Pos;
792     } else {
793       printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
794                         ModTime, Size);
795     }
796     Out.flush();
797 
798     std::vector<unsigned> Symbols;
799     if (NeedSymbols) {
800       Expected<std::vector<unsigned>> SymbolsOrErr =
801           getSymbols(Buf, Index, SymNames, SymMap, HasObject);
802       if (!SymbolsOrErr)
803         return createFileError(M.MemberName, SymbolsOrErr.takeError());
804       Symbols = std::move(*SymbolsOrErr);
805     }
806 
807     Pos += Header.size() + Data.size() + Padding.size();
808     Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding});
809   }
810   // If there are no symbols, emit an empty symbol table, to satisfy Solaris
811   // tools, older versions of which expect a symbol table in a non-empty
812   // archive, regardless of whether there are any symbols in it.
813   if (HasObject && SymNames.tell() == 0 && !isCOFFArchive(Kind))
814     SymNames << '\0' << '\0' << '\0';
815   return Ret;
816 }
817 
818 namespace llvm {
819 
820 static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) {
821   SmallString<128> Ret = P;
822   std::error_code Err = sys::fs::make_absolute(Ret);
823   if (Err)
824     return Err;
825   sys::path::remove_dots(Ret, /*removedotdot*/ true);
826   return Ret;
827 }
828 
829 // Compute the relative path from From to To.
830 Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
831   ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To);
832   ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From);
833   if (!PathToOrErr || !DirFromOrErr)
834     return errorCodeToError(std::error_code(errno, std::generic_category()));
835 
836   const SmallString<128> &PathTo = *PathToOrErr;
837   const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
838 
839   // Can't construct a relative path between different roots
840   if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
841     return sys::path::convert_to_slash(PathTo);
842 
843   // Skip common prefixes
844   auto FromTo =
845       std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
846                     sys::path::begin(PathTo));
847   auto FromI = FromTo.first;
848   auto ToI = FromTo.second;
849 
850   // Construct relative path
851   SmallString<128> Relative;
852   for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
853     sys::path::append(Relative, sys::path::Style::posix, "..");
854 
855   for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
856     sys::path::append(Relative, sys::path::Style::posix, *ToI);
857 
858   return std::string(Relative.str());
859 }
860 
861 static Error writeArchiveToStream(raw_ostream &Out,
862                                   ArrayRef<NewArchiveMember> NewMembers,
863                                   bool WriteSymtab, object::Archive::Kind Kind,
864                                   bool Deterministic, bool Thin, bool IsEC) {
865   assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
866 
867   SmallString<0> SymNamesBuf;
868   raw_svector_ostream SymNames(SymNamesBuf);
869   SmallString<0> StringTableBuf;
870   raw_svector_ostream StringTable(StringTableBuf);
871   SymMap SymMap;
872 
873   // COFF symbol map uses 16-bit indexes, so we can't use it if there are too
874   // many members.
875   if (isCOFFArchive(Kind) && NewMembers.size() > 0xfffe)
876     Kind = object::Archive::K_GNU;
877 
878   SymMap.UseECMap = IsEC;
879   Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
880       StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab,
881       isCOFFArchive(Kind) ? &SymMap : nullptr, NewMembers);
882   if (Error E = DataOrErr.takeError())
883     return E;
884   std::vector<MemberData> &Data = *DataOrErr;
885 
886   uint64_t StringTableSize = 0;
887   MemberData StringTableMember;
888   if (!StringTableBuf.empty() && !isAIXBigArchive(Kind)) {
889     StringTableMember = computeStringTable(StringTableBuf);
890     StringTableSize = StringTableMember.Header.size() +
891                       StringTableMember.Data.size() +
892                       StringTableMember.Padding.size();
893   }
894 
895   // We would like to detect if we need to switch to a 64-bit symbol table.
896   uint64_t LastMemberEndOffset = 0;
897   uint64_t LastMemberHeaderOffset = 0;
898   uint64_t NumSyms = 0;
899   uint64_t NumSyms32 = 0; // Store symbol number of 32-bit member files.
900 
901   for (const auto &M : Data) {
902     // Record the start of the member's offset
903     LastMemberHeaderOffset = LastMemberEndOffset;
904     // Account for the size of each part associated with the member.
905     LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size();
906     NumSyms += M.Symbols.size();
907 
908     // AIX big archive files may contain two global symbol tables. The
909     // first global symbol table locates 32-bit file members that define global
910     // symbols; the second global symbol table does the same for 64-bit file
911     // members. As a big archive can have both 32-bit and 64-bit file members,
912     // we need to know the number of symbols in each symbol table individually.
913     if (isAIXBigArchive(Kind) && WriteSymtab) {
914       Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data);
915       if (Error E = Is64BitOrErr.takeError())
916         return E;
917 
918       if (!*Is64BitOrErr)
919         NumSyms32 += M.Symbols.size();
920     }
921   }
922 
923   std::optional<uint64_t> HeadersSize;
924 
925   // The symbol table is put at the end of the big archive file. The symbol
926   // table is at the start of the archive file for other archive formats.
927   if (WriteSymtab && !is64BitKind(Kind)) {
928     // We assume 32-bit offsets to see if 32-bit symbols are possible or not.
929     HeadersSize = computeHeadersSize(Kind, Data.size(), StringTableSize,
930                                      NumSyms, SymNamesBuf.size(),
931                                      isCOFFArchive(Kind) ? &SymMap : nullptr);
932 
933     // The SYM64 format is used when an archive's member offsets are larger than
934     // 32-bits can hold. The need for this shift in format is detected by
935     // writeArchive. To test this we need to generate a file with a member that
936     // has an offset larger than 32-bits but this demands a very slow test. To
937     // speed the test up we use this environment variable to pretend like the
938     // cutoff happens before 32-bits and instead happens at some much smaller
939     // value.
940     uint64_t Sym64Threshold = 1ULL << 32;
941     const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
942     if (Sym64Env)
943       StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
944 
945     // If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need
946     // to switch to 64-bit. Note that the file can be larger than 4GB as long as
947     // the last member starts before the 4GB offset.
948     if (*HeadersSize + LastMemberHeaderOffset >= Sym64Threshold) {
949       if (Kind == object::Archive::K_DARWIN)
950         Kind = object::Archive::K_DARWIN64;
951       else
952         Kind = object::Archive::K_GNU64;
953       HeadersSize.reset();
954     }
955   }
956 
957   if (Thin)
958     Out << "!<thin>\n";
959   else if (isAIXBigArchive(Kind))
960     Out << "<bigaf>\n";
961   else
962     Out << "!<arch>\n";
963 
964   if (!isAIXBigArchive(Kind)) {
965     if (WriteSymtab) {
966       if (!HeadersSize)
967         HeadersSize = computeHeadersSize(
968             Kind, Data.size(), StringTableSize, NumSyms, SymNamesBuf.size(),
969             isCOFFArchive(Kind) ? &SymMap : nullptr);
970       writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf,
971                        *HeadersSize, NumSyms);
972 
973       if (isCOFFArchive(Kind))
974         writeSymbolMap(Out, Kind, Deterministic, Data, SymMap, *HeadersSize);
975     }
976 
977     if (StringTableSize)
978       Out << StringTableMember.Header << StringTableMember.Data
979           << StringTableMember.Padding;
980 
981     if (WriteSymtab && SymMap.ECMap.size())
982       writeECSymbols(Out, Kind, Deterministic, Data, SymMap);
983 
984     for (const MemberData &M : Data)
985       Out << M.Header << M.Data << M.Padding;
986   } else {
987     HeadersSize = sizeof(object::BigArchive::FixLenHdr);
988     LastMemberEndOffset += *HeadersSize;
989     LastMemberHeaderOffset += *HeadersSize;
990 
991     // For the big archive (AIX) format, compute a table of member names and
992     // offsets, used in the member table.
993     uint64_t MemberTableNameStrTblSize = 0;
994     std::vector<size_t> MemberOffsets;
995     std::vector<StringRef> MemberNames;
996     // Loop across object to find offset and names.
997     uint64_t MemberEndOffset = sizeof(object::BigArchive::FixLenHdr);
998     for (size_t I = 0, Size = NewMembers.size(); I != Size; ++I) {
999       const NewArchiveMember &Member = NewMembers[I];
1000       MemberTableNameStrTblSize += Member.MemberName.size() + 1;
1001       MemberOffsets.push_back(MemberEndOffset);
1002       MemberNames.push_back(Member.MemberName);
1003       // File member name ended with "`\n". The length is included in
1004       // BigArMemHdrType.
1005       MemberEndOffset += sizeof(object::BigArMemHdrType) +
1006                              alignTo(Data[I].Data.size(), 2) +
1007                              alignTo(Member.MemberName.size(), 2);
1008     }
1009 
1010     // AIX member table size.
1011     uint64_t MemberTableSize = 20 + // Number of members field
1012                                20 * MemberOffsets.size() +
1013                                MemberTableNameStrTblSize;
1014 
1015     SmallString<0> SymNamesBuf32;
1016     SmallString<0> SymNamesBuf64;
1017     raw_svector_ostream SymNames32(SymNamesBuf32);
1018     raw_svector_ostream SymNames64(SymNamesBuf64);
1019 
1020     if (WriteSymtab && NumSyms)
1021       // Generate the symbol names for the members.
1022       for (const NewArchiveMember &M : NewMembers) {
1023         MemoryBufferRef Buf = M.Buf->getMemBufferRef();
1024         Expected<bool> Is64BitOrErr = is64BitSymbolicFile(Buf.getBuffer());
1025         if (!Is64BitOrErr)
1026           return Is64BitOrErr.takeError();
1027 
1028         bool HasObject;
1029         Expected<std::vector<unsigned>> SymbolsOrErr =
1030             getSymbols(Buf, 0, *Is64BitOrErr ? SymNames64 : SymNames32, nullptr,
1031                        HasObject);
1032         if (!SymbolsOrErr)
1033           return SymbolsOrErr.takeError();
1034       }
1035 
1036     uint64_t MemberTableEndOffset =
1037         LastMemberEndOffset +
1038         alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2);
1039 
1040     // In AIX OS, The 'GlobSymOffset' field in the fixed-length header contains
1041     // the offset to the 32-bit global symbol table, and the 'GlobSym64Offset'
1042     // contains the offset to the 64-bit global symbol table.
1043     uint64_t GlobalSymbolOffset =
1044         (WriteSymtab && NumSyms32 > 0) ? MemberTableEndOffset : 0;
1045 
1046     uint64_t GlobalSymbolOffset64 = 0;
1047     uint64_t NumSyms64 = NumSyms - NumSyms32;
1048     if (WriteSymtab && NumSyms64 > 0) {
1049       if (GlobalSymbolOffset == 0)
1050         GlobalSymbolOffset64 = MemberTableEndOffset;
1051       else
1052         // If there is a global symbol table for 32-bit members,
1053         // the 64-bit global symbol table is after the 32-bit one.
1054         GlobalSymbolOffset64 =
1055             GlobalSymbolOffset + sizeof(object::BigArMemHdrType) +
1056             (NumSyms32 + 1) * 8 + alignTo(SymNamesBuf32.size(), 2);
1057     }
1058 
1059     // Fixed Sized Header.
1060     printWithSpacePadding(Out, NewMembers.size() ? LastMemberEndOffset : 0,
1061                           20); // Offset to member table
1062     // If there are no file members in the archive, there will be no global
1063     // symbol table.
1064     printWithSpacePadding(Out, GlobalSymbolOffset, 20);
1065     printWithSpacePadding(Out, GlobalSymbolOffset64, 20);
1066     printWithSpacePadding(
1067         Out, NewMembers.size() ? sizeof(object::BigArchive::FixLenHdr) : 0,
1068         20); // Offset to first archive member
1069     printWithSpacePadding(Out, NewMembers.size() ? LastMemberHeaderOffset : 0,
1070                           20); // Offset to last archive member
1071     printWithSpacePadding(
1072         Out, 0,
1073         20); // Offset to first member of free list - Not supported yet
1074 
1075     for (const MemberData &M : Data) {
1076       Out << M.Header << M.Data;
1077       if (M.Data.size() % 2)
1078         Out << '\0';
1079     }
1080 
1081     if (NewMembers.size()) {
1082       // Member table.
1083       printBigArchiveMemberHeader(Out, "", sys::toTimePoint(0), 0, 0, 0,
1084                                   MemberTableSize, LastMemberHeaderOffset,
1085                                   GlobalSymbolOffset ? GlobalSymbolOffset
1086                                                      : GlobalSymbolOffset64);
1087       printWithSpacePadding(Out, MemberOffsets.size(), 20); // Number of members
1088       for (uint64_t MemberOffset : MemberOffsets)
1089         printWithSpacePadding(Out, MemberOffset,
1090                               20); // Offset to member file header.
1091       for (StringRef MemberName : MemberNames)
1092         Out << MemberName << '\0'; // Member file name, null byte padding.
1093 
1094       if (MemberTableNameStrTblSize % 2)
1095         Out << '\0'; // Name table must be tail padded to an even number of
1096                      // bytes.
1097 
1098       if (WriteSymtab) {
1099         // Write global symbol table for 32-bit file members.
1100         if (GlobalSymbolOffset) {
1101           writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf32,
1102                            *HeadersSize, NumSyms32, LastMemberEndOffset,
1103                            GlobalSymbolOffset64);
1104           // Add padding between the symbol tables, if needed.
1105           if (GlobalSymbolOffset64 && (SymNamesBuf32.size() % 2))
1106             Out << '\0';
1107         }
1108 
1109         // Write global symbol table for 64-bit file members.
1110         if (GlobalSymbolOffset64)
1111           writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf64,
1112                            *HeadersSize, NumSyms64,
1113                            GlobalSymbolOffset ? GlobalSymbolOffset
1114                                               : LastMemberEndOffset,
1115                            0, true);
1116       }
1117     }
1118   }
1119   Out.flush();
1120   return Error::success();
1121 }
1122 
1123 Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
1124                    bool WriteSymtab, object::Archive::Kind Kind,
1125                    bool Deterministic, bool Thin,
1126                    std::unique_ptr<MemoryBuffer> OldArchiveBuf, bool IsEC) {
1127   Expected<sys::fs::TempFile> Temp =
1128       sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
1129   if (!Temp)
1130     return Temp.takeError();
1131   raw_fd_ostream Out(Temp->FD, false);
1132 
1133   if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind,
1134                                      Deterministic, Thin, IsEC)) {
1135     if (Error DiscardError = Temp->discard())
1136       return joinErrors(std::move(E), std::move(DiscardError));
1137     return E;
1138   }
1139 
1140   // At this point, we no longer need whatever backing memory
1141   // was used to generate the NewMembers. On Windows, this buffer
1142   // could be a mapped view of the file we want to replace (if
1143   // we're updating an existing archive, say). In that case, the
1144   // rename would still succeed, but it would leave behind a
1145   // temporary file (actually the original file renamed) because
1146   // a file cannot be deleted while there's a handle open on it,
1147   // only renamed. So by freeing this buffer, this ensures that
1148   // the last open handle on the destination file, if any, is
1149   // closed before we attempt to rename.
1150   OldArchiveBuf.reset();
1151 
1152   return Temp->keep(ArcName);
1153 }
1154 
1155 Expected<std::unique_ptr<MemoryBuffer>>
1156 writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab,
1157                      object::Archive::Kind Kind, bool Deterministic,
1158                      bool Thin) {
1159   SmallVector<char, 0> ArchiveBufferVector;
1160   raw_svector_ostream ArchiveStream(ArchiveBufferVector);
1161 
1162   if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab,
1163                                      Kind, Deterministic, Thin, false))
1164     return std::move(E);
1165 
1166   return std::make_unique<SmallVectorMemoryBuffer>(
1167       std::move(ArchiveBufferVector), /*RequiresNullTerminator=*/false);
1168 }
1169 
1170 } // namespace llvm
1171