10b57cec5SDimitry Andric //===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines the writeArchive function. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/Object/ArchiveWriter.h" 140b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 155ffd83dbSDimitry Andric #include "llvm/ADT/StringMap.h" 160b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 170b57cec5SDimitry Andric #include "llvm/BinaryFormat/Magic.h" 180b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 190b57cec5SDimitry Andric #include "llvm/Object/Archive.h" 2006c3fb27SDimitry Andric #include "llvm/Object/COFF.h" 218bcb0991SDimitry Andric #include "llvm/Object/Error.h" 2281ad6265SDimitry Andric #include "llvm/Object/IRObjectFile.h" 2381ad6265SDimitry Andric #include "llvm/Object/MachO.h" 240b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h" 250b57cec5SDimitry Andric #include "llvm/Object/SymbolicFile.h" 2681ad6265SDimitry Andric #include "llvm/Object/XCOFFObjectFile.h" 278bcb0991SDimitry Andric #include "llvm/Support/Alignment.h" 280b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h" 290b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 300b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 310b57cec5SDimitry Andric #include "llvm/Support/Format.h" 3281ad6265SDimitry Andric #include "llvm/Support/MathExtras.h" 330b57cec5SDimitry Andric #include "llvm/Support/Path.h" 34e8d8bef9SDimitry Andric #include "llvm/Support/SmallVectorMemoryBuffer.h" 350b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 360b57cec5SDimitry Andric 3706c3fb27SDimitry Andric #include <cerrno> 380b57cec5SDimitry Andric #include <map> 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric #if !defined(_MSC_VER) && !defined(__MINGW32__) 410b57cec5SDimitry Andric #include <unistd.h> 420b57cec5SDimitry Andric #else 430b57cec5SDimitry Andric #include <io.h> 440b57cec5SDimitry Andric #endif 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric using namespace llvm; 4706c3fb27SDimitry Andric using namespace llvm::object; 4806c3fb27SDimitry Andric 4906c3fb27SDimitry Andric struct SymMap { 5006c3fb27SDimitry Andric bool UseECMap; 5106c3fb27SDimitry Andric std::map<std::string, uint16_t> Map; 5206c3fb27SDimitry Andric std::map<std::string, uint16_t> ECMap; 5306c3fb27SDimitry Andric }; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) 560b57cec5SDimitry Andric : Buf(MemoryBuffer::getMemBuffer(BufRef, false)), 570b57cec5SDimitry Andric MemberName(BufRef.getBufferIdentifier()) {} 580b57cec5SDimitry Andric 5981ad6265SDimitry Andric object::Archive::Kind NewArchiveMember::detectKindFromObject() const { 6081ad6265SDimitry Andric auto MemBufferRef = this->Buf->getMemBufferRef(); 6181ad6265SDimitry Andric Expected<std::unique_ptr<object::ObjectFile>> OptionalObject = 6281ad6265SDimitry Andric object::ObjectFile::createObjectFile(MemBufferRef); 6381ad6265SDimitry Andric 6481ad6265SDimitry Andric if (OptionalObject) 6581ad6265SDimitry Andric return isa<object::MachOObjectFile>(**OptionalObject) 6681ad6265SDimitry Andric ? object::Archive::K_DARWIN 6781ad6265SDimitry Andric : (isa<object::XCOFFObjectFile>(**OptionalObject) 6881ad6265SDimitry Andric ? object::Archive::K_AIXBIG 6981ad6265SDimitry Andric : object::Archive::K_GNU); 7081ad6265SDimitry Andric 7181ad6265SDimitry Andric // Squelch the error in case we had a non-object file. 7281ad6265SDimitry Andric consumeError(OptionalObject.takeError()); 7381ad6265SDimitry Andric 7481ad6265SDimitry Andric // If we're adding a bitcode file to the archive, detect the Archive kind 7581ad6265SDimitry Andric // based on the target triple. 7681ad6265SDimitry Andric LLVMContext Context; 7781ad6265SDimitry Andric if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) { 7881ad6265SDimitry Andric if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile( 7981ad6265SDimitry Andric MemBufferRef, file_magic::bitcode, &Context)) { 8081ad6265SDimitry Andric auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr); 8106c3fb27SDimitry Andric auto TargetTriple = Triple(IRObject.getTargetTriple()); 8206c3fb27SDimitry Andric return TargetTriple.isOSDarwin() 8381ad6265SDimitry Andric ? object::Archive::K_DARWIN 8406c3fb27SDimitry Andric : (TargetTriple.isOSAIX() ? object::Archive::K_AIXBIG 8506c3fb27SDimitry Andric : object::Archive::K_GNU); 8681ad6265SDimitry Andric } else { 8781ad6265SDimitry Andric // Squelch the error in case this was not a SymbolicFile. 8881ad6265SDimitry Andric consumeError(ObjOrErr.takeError()); 8981ad6265SDimitry Andric } 9081ad6265SDimitry Andric } 9181ad6265SDimitry Andric 9281ad6265SDimitry Andric return object::Archive::getDefaultKindForHost(); 9381ad6265SDimitry Andric } 9481ad6265SDimitry Andric 950b57cec5SDimitry Andric Expected<NewArchiveMember> 960b57cec5SDimitry Andric NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, 970b57cec5SDimitry Andric bool Deterministic) { 980b57cec5SDimitry Andric Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef(); 990b57cec5SDimitry Andric if (!BufOrErr) 1000b57cec5SDimitry Andric return BufOrErr.takeError(); 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric NewArchiveMember M; 1030b57cec5SDimitry Andric M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false); 1040b57cec5SDimitry Andric M.MemberName = M.Buf->getBufferIdentifier(); 1050b57cec5SDimitry Andric if (!Deterministic) { 1060b57cec5SDimitry Andric auto ModTimeOrErr = OldMember.getLastModified(); 1070b57cec5SDimitry Andric if (!ModTimeOrErr) 1080b57cec5SDimitry Andric return ModTimeOrErr.takeError(); 1090b57cec5SDimitry Andric M.ModTime = ModTimeOrErr.get(); 1100b57cec5SDimitry Andric Expected<unsigned> UIDOrErr = OldMember.getUID(); 1110b57cec5SDimitry Andric if (!UIDOrErr) 1120b57cec5SDimitry Andric return UIDOrErr.takeError(); 1130b57cec5SDimitry Andric M.UID = UIDOrErr.get(); 1140b57cec5SDimitry Andric Expected<unsigned> GIDOrErr = OldMember.getGID(); 1150b57cec5SDimitry Andric if (!GIDOrErr) 1160b57cec5SDimitry Andric return GIDOrErr.takeError(); 1170b57cec5SDimitry Andric M.GID = GIDOrErr.get(); 1180b57cec5SDimitry Andric Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode(); 1190b57cec5SDimitry Andric if (!AccessModeOrErr) 1200b57cec5SDimitry Andric return AccessModeOrErr.takeError(); 1210b57cec5SDimitry Andric M.Perms = AccessModeOrErr.get(); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric return std::move(M); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName, 1270b57cec5SDimitry Andric bool Deterministic) { 1280b57cec5SDimitry Andric sys::fs::file_status Status; 1290b57cec5SDimitry Andric auto FDOrErr = sys::fs::openNativeFileForRead(FileName); 1300b57cec5SDimitry Andric if (!FDOrErr) 1310b57cec5SDimitry Andric return FDOrErr.takeError(); 1320b57cec5SDimitry Andric sys::fs::file_t FD = *FDOrErr; 1330b57cec5SDimitry Andric assert(FD != sys::fs::kInvalidFile); 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric if (auto EC = sys::fs::status(FD, Status)) 1360b57cec5SDimitry Andric return errorCodeToError(EC); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric // Opening a directory doesn't make sense. Let it fail. 1390b57cec5SDimitry Andric // Linux cannot open directories with open(2), although 1400b57cec5SDimitry Andric // cygwin and *bsd can. 1410b57cec5SDimitry Andric if (Status.type() == sys::fs::file_type::directory_file) 1420b57cec5SDimitry Andric return errorCodeToError(make_error_code(errc::is_a_directory)); 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr = 1450b57cec5SDimitry Andric MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false); 1460b57cec5SDimitry Andric if (!MemberBufferOrErr) 1470b57cec5SDimitry Andric return errorCodeToError(MemberBufferOrErr.getError()); 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric if (auto EC = sys::fs::closeFile(FD)) 1500b57cec5SDimitry Andric return errorCodeToError(EC); 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric NewArchiveMember M; 1530b57cec5SDimitry Andric M.Buf = std::move(*MemberBufferOrErr); 1540b57cec5SDimitry Andric M.MemberName = M.Buf->getBufferIdentifier(); 1550b57cec5SDimitry Andric if (!Deterministic) { 1560b57cec5SDimitry Andric M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>( 1570b57cec5SDimitry Andric Status.getLastModificationTime()); 1580b57cec5SDimitry Andric M.UID = Status.getUser(); 1590b57cec5SDimitry Andric M.GID = Status.getGroup(); 1600b57cec5SDimitry Andric M.Perms = Status.permissions(); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric return std::move(M); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric template <typename T> 1660b57cec5SDimitry Andric static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { 1670b57cec5SDimitry Andric uint64_t OldPos = OS.tell(); 1680b57cec5SDimitry Andric OS << Data; 1690b57cec5SDimitry Andric unsigned SizeSoFar = OS.tell() - OldPos; 1700b57cec5SDimitry Andric assert(SizeSoFar <= Size && "Data doesn't fit in Size"); 1710b57cec5SDimitry Andric OS.indent(Size - SizeSoFar); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric static bool isDarwin(object::Archive::Kind Kind) { 1750b57cec5SDimitry Andric return Kind == object::Archive::K_DARWIN || 1760b57cec5SDimitry Andric Kind == object::Archive::K_DARWIN64; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 17981ad6265SDimitry Andric static bool isAIXBigArchive(object::Archive::Kind Kind) { 18081ad6265SDimitry Andric return Kind == object::Archive::K_AIXBIG; 18181ad6265SDimitry Andric } 18281ad6265SDimitry Andric 18306c3fb27SDimitry Andric static bool isCOFFArchive(object::Archive::Kind Kind) { 18406c3fb27SDimitry Andric return Kind == object::Archive::K_COFF; 18506c3fb27SDimitry Andric } 18606c3fb27SDimitry Andric 1870b57cec5SDimitry Andric static bool isBSDLike(object::Archive::Kind Kind) { 1880b57cec5SDimitry Andric switch (Kind) { 1890b57cec5SDimitry Andric case object::Archive::K_GNU: 1900b57cec5SDimitry Andric case object::Archive::K_GNU64: 19181ad6265SDimitry Andric case object::Archive::K_AIXBIG: 19206c3fb27SDimitry Andric case object::Archive::K_COFF: 1930b57cec5SDimitry Andric return false; 1940b57cec5SDimitry Andric case object::Archive::K_BSD: 1950b57cec5SDimitry Andric case object::Archive::K_DARWIN: 1960b57cec5SDimitry Andric case object::Archive::K_DARWIN64: 1970b57cec5SDimitry Andric return true; 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric llvm_unreachable("not supported for writting"); 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric template <class T> 2030b57cec5SDimitry Andric static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) { 2040b57cec5SDimitry Andric support::endian::write(Out, Val, 2050b57cec5SDimitry Andric isBSDLike(Kind) ? support::little : support::big); 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 20806c3fb27SDimitry Andric template <class T> static void printLE(raw_ostream &Out, T Val) { 20906c3fb27SDimitry Andric support::endian::write(Out, Val, support::little); 21006c3fb27SDimitry Andric } 21106c3fb27SDimitry Andric 2120b57cec5SDimitry Andric static void printRestOfMemberHeader( 2130b57cec5SDimitry Andric raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime, 2148bcb0991SDimitry Andric unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) { 2150b57cec5SDimitry Andric printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric // The format has only 6 chars for uid and gid. Truncate if the provided 2180b57cec5SDimitry Andric // values don't fit. 2190b57cec5SDimitry Andric printWithSpacePadding(Out, UID % 1000000, 6); 2200b57cec5SDimitry Andric printWithSpacePadding(Out, GID % 1000000, 6); 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric printWithSpacePadding(Out, format("%o", Perms), 8); 2230b57cec5SDimitry Andric printWithSpacePadding(Out, Size, 10); 2240b57cec5SDimitry Andric Out << "`\n"; 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric static void 2280b57cec5SDimitry Andric printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name, 2290b57cec5SDimitry Andric const sys::TimePoint<std::chrono::seconds> &ModTime, 2300b57cec5SDimitry Andric unsigned UID, unsigned GID, unsigned Perms, 2318bcb0991SDimitry Andric uint64_t Size) { 2320b57cec5SDimitry Andric printWithSpacePadding(Out, Twine(Name) + "/", 16); 2330b57cec5SDimitry Andric printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric static void 2370b57cec5SDimitry Andric printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name, 2380b57cec5SDimitry Andric const sys::TimePoint<std::chrono::seconds> &ModTime, 2398bcb0991SDimitry Andric unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) { 2400b57cec5SDimitry Andric uint64_t PosAfterHeader = Pos + 60 + Name.size(); 2410b57cec5SDimitry Andric // Pad so that even 64 bit object files are aligned. 2428bcb0991SDimitry Andric unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8)); 2430b57cec5SDimitry Andric unsigned NameWithPadding = Name.size() + Pad; 2440b57cec5SDimitry Andric printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16); 2450b57cec5SDimitry Andric printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, 2460b57cec5SDimitry Andric NameWithPadding + Size); 2470b57cec5SDimitry Andric Out << Name; 2480b57cec5SDimitry Andric while (Pad--) 2490b57cec5SDimitry Andric Out.write(uint8_t(0)); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 25281ad6265SDimitry Andric static void 25381ad6265SDimitry Andric printBigArchiveMemberHeader(raw_ostream &Out, StringRef Name, 25481ad6265SDimitry Andric const sys::TimePoint<std::chrono::seconds> &ModTime, 25581ad6265SDimitry Andric unsigned UID, unsigned GID, unsigned Perms, 25606c3fb27SDimitry Andric uint64_t Size, uint64_t PrevOffset, 25706c3fb27SDimitry Andric uint64_t NextOffset) { 25881ad6265SDimitry Andric unsigned NameLen = Name.size(); 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric printWithSpacePadding(Out, Size, 20); // File member size 26181ad6265SDimitry Andric printWithSpacePadding(Out, NextOffset, 20); // Next member header offset 26281ad6265SDimitry Andric printWithSpacePadding(Out, PrevOffset, 20); // Previous member header offset 26381ad6265SDimitry Andric printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); // File member date 26481ad6265SDimitry Andric // The big archive format has 12 chars for uid and gid. 26581ad6265SDimitry Andric printWithSpacePadding(Out, UID % 1000000000000, 12); // UID 26681ad6265SDimitry Andric printWithSpacePadding(Out, GID % 1000000000000, 12); // GID 26781ad6265SDimitry Andric printWithSpacePadding(Out, format("%o", Perms), 12); // Permission 26881ad6265SDimitry Andric printWithSpacePadding(Out, NameLen, 4); // Name length 26981ad6265SDimitry Andric if (NameLen) { 27081ad6265SDimitry Andric printWithSpacePadding(Out, Name, NameLen); // Name 27181ad6265SDimitry Andric if (NameLen % 2) 27281ad6265SDimitry Andric Out.write(uint8_t(0)); // Null byte padding 27381ad6265SDimitry Andric } 27481ad6265SDimitry Andric Out << "`\n"; // Terminator 27581ad6265SDimitry Andric } 27681ad6265SDimitry Andric 2770b57cec5SDimitry Andric static bool useStringTable(bool Thin, StringRef Name) { 2780b57cec5SDimitry Andric return Thin || Name.size() >= 16 || Name.contains('/'); 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric static bool is64BitKind(object::Archive::Kind Kind) { 2820b57cec5SDimitry Andric switch (Kind) { 2830b57cec5SDimitry Andric case object::Archive::K_GNU: 2840b57cec5SDimitry Andric case object::Archive::K_BSD: 2850b57cec5SDimitry Andric case object::Archive::K_DARWIN: 2860b57cec5SDimitry Andric case object::Archive::K_COFF: 2870b57cec5SDimitry Andric return false; 28881ad6265SDimitry Andric case object::Archive::K_AIXBIG: 2890b57cec5SDimitry Andric case object::Archive::K_DARWIN64: 2900b57cec5SDimitry Andric case object::Archive::K_GNU64: 2910b57cec5SDimitry Andric return true; 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric llvm_unreachable("not supported for writting"); 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric static void 2970b57cec5SDimitry Andric printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable, 2980b57cec5SDimitry Andric StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind, 2990b57cec5SDimitry Andric bool Thin, const NewArchiveMember &M, 3008bcb0991SDimitry Andric sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) { 3010b57cec5SDimitry Andric if (isBSDLike(Kind)) 3020b57cec5SDimitry Andric return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID, 3030b57cec5SDimitry Andric M.Perms, Size); 3040b57cec5SDimitry Andric if (!useStringTable(Thin, M.MemberName)) 3050b57cec5SDimitry Andric return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID, 3060b57cec5SDimitry Andric M.Perms, Size); 3070b57cec5SDimitry Andric Out << '/'; 3080b57cec5SDimitry Andric uint64_t NamePos; 3090b57cec5SDimitry Andric if (Thin) { 3100b57cec5SDimitry Andric NamePos = StringTable.tell(); 3110b57cec5SDimitry Andric StringTable << M.MemberName << "/\n"; 3120b57cec5SDimitry Andric } else { 3130b57cec5SDimitry Andric auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)}); 3140b57cec5SDimitry Andric if (Insertion.second) { 3150b57cec5SDimitry Andric Insertion.first->second = StringTable.tell(); 31606c3fb27SDimitry Andric StringTable << M.MemberName; 31706c3fb27SDimitry Andric if (isCOFFArchive(Kind)) 31806c3fb27SDimitry Andric StringTable << '\0'; 31906c3fb27SDimitry Andric else 32006c3fb27SDimitry Andric StringTable << "/\n"; 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric NamePos = Insertion.first->second; 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric printWithSpacePadding(Out, NamePos, 15); 3250b57cec5SDimitry Andric printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size); 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric namespace { 3290b57cec5SDimitry Andric struct MemberData { 3300b57cec5SDimitry Andric std::vector<unsigned> Symbols; 3310b57cec5SDimitry Andric std::string Header; 3320b57cec5SDimitry Andric StringRef Data; 3330b57cec5SDimitry Andric StringRef Padding; 3340b57cec5SDimitry Andric }; 3350b57cec5SDimitry Andric } // namespace 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric static MemberData computeStringTable(StringRef Names) { 3380b57cec5SDimitry Andric unsigned Size = Names.size(); 3398bcb0991SDimitry Andric unsigned Pad = offsetToAlignment(Size, Align(2)); 3400b57cec5SDimitry Andric std::string Header; 3410b57cec5SDimitry Andric raw_string_ostream Out(Header); 3420b57cec5SDimitry Andric printWithSpacePadding(Out, "//", 48); 3430b57cec5SDimitry Andric printWithSpacePadding(Out, Size + Pad, 10); 3440b57cec5SDimitry Andric Out << "`\n"; 3450b57cec5SDimitry Andric Out.flush(); 3460b57cec5SDimitry Andric return {{}, std::move(Header), Names, Pad ? "\n" : ""}; 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) { 3500b57cec5SDimitry Andric using namespace std::chrono; 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric if (!Deterministic) 3530b57cec5SDimitry Andric return time_point_cast<seconds>(system_clock::now()); 3540b57cec5SDimitry Andric return sys::TimePoint<seconds>(); 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric static bool isArchiveSymbol(const object::BasicSymbolRef &S) { 3585ffd83dbSDimitry Andric Expected<uint32_t> SymFlagsOrErr = S.getFlags(); 3595ffd83dbSDimitry Andric if (!SymFlagsOrErr) 3605ffd83dbSDimitry Andric // TODO: Actually report errors helpfully. 3615ffd83dbSDimitry Andric report_fatal_error(SymFlagsOrErr.takeError()); 3625ffd83dbSDimitry Andric if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific) 3630b57cec5SDimitry Andric return false; 3645ffd83dbSDimitry Andric if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global)) 3650b57cec5SDimitry Andric return false; 3665ffd83dbSDimitry Andric if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined) 3670b57cec5SDimitry Andric return false; 3680b57cec5SDimitry Andric return true; 3690b57cec5SDimitry Andric } 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric static void printNBits(raw_ostream &Out, object::Archive::Kind Kind, 3720b57cec5SDimitry Andric uint64_t Val) { 3730b57cec5SDimitry Andric if (is64BitKind(Kind)) 3740b57cec5SDimitry Andric print<uint64_t>(Out, Kind, Val); 3750b57cec5SDimitry Andric else 3760b57cec5SDimitry Andric print<uint32_t>(Out, Kind, Val); 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric 379e8d8bef9SDimitry Andric static uint64_t computeSymbolTableSize(object::Archive::Kind Kind, 380e8d8bef9SDimitry Andric uint64_t NumSyms, uint64_t OffsetSize, 38106c3fb27SDimitry Andric uint64_t StringTableSize, 382e8d8bef9SDimitry Andric uint32_t *Padding = nullptr) { 383e8d8bef9SDimitry Andric assert((OffsetSize == 4 || OffsetSize == 8) && "Unsupported OffsetSize"); 384e8d8bef9SDimitry Andric uint64_t Size = OffsetSize; // Number of entries 385e8d8bef9SDimitry Andric if (isBSDLike(Kind)) 386e8d8bef9SDimitry Andric Size += NumSyms * OffsetSize * 2; // Table 387e8d8bef9SDimitry Andric else 388e8d8bef9SDimitry Andric Size += NumSyms * OffsetSize; // Table 389e8d8bef9SDimitry Andric if (isBSDLike(Kind)) 390e8d8bef9SDimitry Andric Size += OffsetSize; // byte count 39106c3fb27SDimitry Andric Size += StringTableSize; 392e8d8bef9SDimitry Andric // ld64 expects the members to be 8-byte aligned for 64-bit content and at 393e8d8bef9SDimitry Andric // least 4-byte aligned for 32-bit content. Opt for the larger encoding 394e8d8bef9SDimitry Andric // uniformly. 395e8d8bef9SDimitry Andric // We do this for all bsd formats because it simplifies aligning members. 39681ad6265SDimitry Andric // For the big archive format, the symbol table is the last member, so there 39781ad6265SDimitry Andric // is no need to align. 39881ad6265SDimitry Andric uint32_t Pad = isAIXBigArchive(Kind) 39981ad6265SDimitry Andric ? 0 40081ad6265SDimitry Andric : offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2)); 40106c3fb27SDimitry Andric 40206c3fb27SDimitry Andric Size += Pad; 40306c3fb27SDimitry Andric if (Padding) 40406c3fb27SDimitry Andric *Padding = Pad; 40506c3fb27SDimitry Andric return Size; 40606c3fb27SDimitry Andric } 40706c3fb27SDimitry Andric 40806c3fb27SDimitry Andric static uint64_t computeSymbolMapSize(uint64_t NumObj, SymMap &SymMap, 40906c3fb27SDimitry Andric uint32_t *Padding = nullptr) { 41006c3fb27SDimitry Andric uint64_t Size = sizeof(uint32_t) * 2; // Number of symbols and objects entries 41106c3fb27SDimitry Andric Size += NumObj * sizeof(uint32_t); // Offset table 41206c3fb27SDimitry Andric 41306c3fb27SDimitry Andric for (auto S : SymMap.Map) 41406c3fb27SDimitry Andric Size += sizeof(uint16_t) + S.first.length() + 1; 41506c3fb27SDimitry Andric 41606c3fb27SDimitry Andric uint32_t Pad = offsetToAlignment(Size, Align(2)); 41706c3fb27SDimitry Andric Size += Pad; 41806c3fb27SDimitry Andric if (Padding) 41906c3fb27SDimitry Andric *Padding = Pad; 42006c3fb27SDimitry Andric return Size; 42106c3fb27SDimitry Andric } 42206c3fb27SDimitry Andric 42306c3fb27SDimitry Andric static uint64_t computeECSymbolsSize(SymMap &SymMap, 42406c3fb27SDimitry Andric uint32_t *Padding = nullptr) { 42506c3fb27SDimitry Andric uint64_t Size = sizeof(uint32_t); // Number of symbols 42606c3fb27SDimitry Andric 42706c3fb27SDimitry Andric for (auto S : SymMap.ECMap) 42806c3fb27SDimitry Andric Size += sizeof(uint16_t) + S.first.length() + 1; 42906c3fb27SDimitry Andric 43006c3fb27SDimitry Andric uint32_t Pad = offsetToAlignment(Size, Align(2)); 431e8d8bef9SDimitry Andric Size += Pad; 432e8d8bef9SDimitry Andric if (Padding) 433e8d8bef9SDimitry Andric *Padding = Pad; 434e8d8bef9SDimitry Andric return Size; 435e8d8bef9SDimitry Andric } 436e8d8bef9SDimitry Andric 437e8d8bef9SDimitry Andric static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind, 43881ad6265SDimitry Andric bool Deterministic, uint64_t Size, 43906c3fb27SDimitry Andric uint64_t PrevMemberOffset = 0, 44006c3fb27SDimitry Andric uint64_t NextMemberOffset = 0) { 441e8d8bef9SDimitry Andric if (isBSDLike(Kind)) { 442e8d8bef9SDimitry Andric const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF"; 443e8d8bef9SDimitry Andric printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0, 444e8d8bef9SDimitry Andric Size); 44581ad6265SDimitry Andric } else if (isAIXBigArchive(Kind)) { 44606c3fb27SDimitry Andric printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size, 44706c3fb27SDimitry Andric PrevMemberOffset, NextMemberOffset); 448e8d8bef9SDimitry Andric } else { 449e8d8bef9SDimitry Andric const char *Name = is64BitKind(Kind) ? "/SYM64" : ""; 450e8d8bef9SDimitry Andric printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size); 451e8d8bef9SDimitry Andric } 452e8d8bef9SDimitry Andric } 453e8d8bef9SDimitry Andric 45406c3fb27SDimitry Andric static uint64_t computeHeadersSize(object::Archive::Kind Kind, 45506c3fb27SDimitry Andric uint64_t NumMembers, 45606c3fb27SDimitry Andric uint64_t StringMemberSize, uint64_t NumSyms, 45706c3fb27SDimitry Andric uint64_t SymNamesSize, SymMap *SymMap) { 45806c3fb27SDimitry Andric uint32_t OffsetSize = is64BitKind(Kind) ? 8 : 4; 45906c3fb27SDimitry Andric uint64_t SymtabSize = 46006c3fb27SDimitry Andric computeSymbolTableSize(Kind, NumSyms, OffsetSize, SymNamesSize); 46106c3fb27SDimitry Andric auto computeSymbolTableHeaderSize = [=] { 46206c3fb27SDimitry Andric SmallString<0> TmpBuf; 46306c3fb27SDimitry Andric raw_svector_ostream Tmp(TmpBuf); 46406c3fb27SDimitry Andric writeSymbolTableHeader(Tmp, Kind, true, SymtabSize); 46506c3fb27SDimitry Andric return TmpBuf.size(); 46606c3fb27SDimitry Andric }; 46706c3fb27SDimitry Andric uint32_t HeaderSize = computeSymbolTableHeaderSize(); 46806c3fb27SDimitry Andric uint64_t Size = strlen("!<arch>\n") + HeaderSize + SymtabSize; 46906c3fb27SDimitry Andric 47006c3fb27SDimitry Andric if (SymMap) { 47106c3fb27SDimitry Andric Size += HeaderSize + computeSymbolMapSize(NumMembers, *SymMap); 47206c3fb27SDimitry Andric if (SymMap->ECMap.size()) 47306c3fb27SDimitry Andric Size += HeaderSize + computeECSymbolsSize(*SymMap); 47406c3fb27SDimitry Andric } 47506c3fb27SDimitry Andric 47606c3fb27SDimitry Andric return Size + StringMemberSize; 47706c3fb27SDimitry Andric } 47806c3fb27SDimitry Andric 47906c3fb27SDimitry Andric static Expected<std::unique_ptr<SymbolicFile>> 48006c3fb27SDimitry Andric getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { 48106c3fb27SDimitry Andric const file_magic Type = identify_magic(Buf.getBuffer()); 48206c3fb27SDimitry Andric // Don't attempt to read non-symbolic file types. 48306c3fb27SDimitry Andric if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) 48406c3fb27SDimitry Andric return nullptr; 48506c3fb27SDimitry Andric if (Type == file_magic::bitcode) { 48606c3fb27SDimitry Andric auto ObjOrErr = object::SymbolicFile::createSymbolicFile( 48706c3fb27SDimitry Andric Buf, file_magic::bitcode, &Context); 48806c3fb27SDimitry Andric if (!ObjOrErr) 48906c3fb27SDimitry Andric return ObjOrErr.takeError(); 49006c3fb27SDimitry Andric return std::move(*ObjOrErr); 49106c3fb27SDimitry Andric } else { 49206c3fb27SDimitry Andric auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf); 49306c3fb27SDimitry Andric if (!ObjOrErr) 49406c3fb27SDimitry Andric return ObjOrErr.takeError(); 49506c3fb27SDimitry Andric return std::move(*ObjOrErr); 49606c3fb27SDimitry Andric } 49706c3fb27SDimitry Andric } 49806c3fb27SDimitry Andric 49906c3fb27SDimitry Andric static Expected<bool> is64BitSymbolicFile(const StringRef &ObjStringRef) { 50006c3fb27SDimitry Andric MemoryBufferRef ObjMbf(ObjStringRef, ""); 50106c3fb27SDimitry Andric // In the scenario when LLVMContext is populated SymbolicFile will contain a 50206c3fb27SDimitry Andric // reference to it, thus SymbolicFile should be destroyed first. 50306c3fb27SDimitry Andric LLVMContext Context; 50406c3fb27SDimitry Andric Expected<std::unique_ptr<SymbolicFile>> ObjOrErr = 50506c3fb27SDimitry Andric getSymbolicFile(ObjMbf, Context); 50606c3fb27SDimitry Andric if (!ObjOrErr) 50706c3fb27SDimitry Andric return ObjOrErr.takeError(); 50806c3fb27SDimitry Andric 50906c3fb27SDimitry Andric // Treat non-symbolic file types as not 64-bits. 51006c3fb27SDimitry Andric if (!*ObjOrErr) 51106c3fb27SDimitry Andric return false; 51206c3fb27SDimitry Andric 51306c3fb27SDimitry Andric return (*ObjOrErr)->is64Bit(); 51406c3fb27SDimitry Andric } 51506c3fb27SDimitry Andric 5160b57cec5SDimitry Andric static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, 5170b57cec5SDimitry Andric bool Deterministic, ArrayRef<MemberData> Members, 51806c3fb27SDimitry Andric StringRef StringTable, uint64_t MembersOffset, 51906c3fb27SDimitry Andric unsigned NumSyms, uint64_t PrevMemberOffset = 0, 52006c3fb27SDimitry Andric uint64_t NextMemberOffset = 0, 52106c3fb27SDimitry Andric bool Is64Bit = false) { 5220b57cec5SDimitry Andric // We don't write a symbol table on an archive with no members -- except on 5230b57cec5SDimitry Andric // Darwin, where the linker will abort unless the archive has a symbol table. 52406c3fb27SDimitry Andric if (StringTable.empty() && !isDarwin(Kind) && !isCOFFArchive(Kind)) 5250b57cec5SDimitry Andric return; 5260b57cec5SDimitry Andric 527e8d8bef9SDimitry Andric uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4; 528e8d8bef9SDimitry Andric uint32_t Pad; 52906c3fb27SDimitry Andric uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, 53006c3fb27SDimitry Andric StringTable.size(), &Pad); 53106c3fb27SDimitry Andric writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset, 53206c3fb27SDimitry Andric NextMemberOffset); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric if (isBSDLike(Kind)) 5350b57cec5SDimitry Andric printNBits(Out, Kind, NumSyms * 2 * OffsetSize); 5360b57cec5SDimitry Andric else 5370b57cec5SDimitry Andric printNBits(Out, Kind, NumSyms); 5380b57cec5SDimitry Andric 53906c3fb27SDimitry Andric uint64_t Pos = MembersOffset; 5400b57cec5SDimitry Andric for (const MemberData &M : Members) { 54106c3fb27SDimitry Andric if (isAIXBigArchive(Kind)) { 54206c3fb27SDimitry Andric Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data); 54306c3fb27SDimitry Andric // If there is an error, the error will have been emitted when 54406c3fb27SDimitry Andric // 'computeMemberData' called the 'getSymbol' function, so don't need to 54506c3fb27SDimitry Andric // handle it here. 54606c3fb27SDimitry Andric if (!Is64BitOrErr) 54706c3fb27SDimitry Andric cantFail(Is64BitOrErr.takeError()); 54806c3fb27SDimitry Andric if (*Is64BitOrErr != Is64Bit) { 54906c3fb27SDimitry Andric Pos += M.Header.size() + M.Data.size() + M.Padding.size(); 55006c3fb27SDimitry Andric continue; 55106c3fb27SDimitry Andric } 55206c3fb27SDimitry Andric } 55306c3fb27SDimitry Andric 5540b57cec5SDimitry Andric for (unsigned StringOffset : M.Symbols) { 5550b57cec5SDimitry Andric if (isBSDLike(Kind)) 5560b57cec5SDimitry Andric printNBits(Out, Kind, StringOffset); 5570b57cec5SDimitry Andric printNBits(Out, Kind, Pos); // member offset 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric Pos += M.Header.size() + M.Data.size() + M.Padding.size(); 5600b57cec5SDimitry Andric } 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric if (isBSDLike(Kind)) 5630b57cec5SDimitry Andric // byte count of the string table 5640b57cec5SDimitry Andric printNBits(Out, Kind, StringTable.size()); 5650b57cec5SDimitry Andric Out << StringTable; 5660b57cec5SDimitry Andric 5670b57cec5SDimitry Andric while (Pad--) 5680b57cec5SDimitry Andric Out.write(uint8_t(0)); 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 57106c3fb27SDimitry Andric static void writeSymbolMap(raw_ostream &Out, object::Archive::Kind Kind, 57206c3fb27SDimitry Andric bool Deterministic, ArrayRef<MemberData> Members, 57306c3fb27SDimitry Andric SymMap &SymMap, uint64_t MembersOffset) { 57406c3fb27SDimitry Andric uint32_t Pad; 57506c3fb27SDimitry Andric uint64_t Size = computeSymbolMapSize(Members.size(), SymMap, &Pad); 57606c3fb27SDimitry Andric writeSymbolTableHeader(Out, Kind, Deterministic, Size, 0); 5770b57cec5SDimitry Andric 57806c3fb27SDimitry Andric uint32_t Pos = MembersOffset; 57906c3fb27SDimitry Andric 58006c3fb27SDimitry Andric printLE<uint32_t>(Out, Members.size()); 58106c3fb27SDimitry Andric for (const MemberData &M : Members) { 58206c3fb27SDimitry Andric printLE(Out, Pos); // member offset 58306c3fb27SDimitry Andric Pos += M.Header.size() + M.Data.size() + M.Padding.size(); 58406c3fb27SDimitry Andric } 58506c3fb27SDimitry Andric 58606c3fb27SDimitry Andric printLE<uint32_t>(Out, SymMap.Map.size()); 58706c3fb27SDimitry Andric 58806c3fb27SDimitry Andric for (auto S : SymMap.Map) 58906c3fb27SDimitry Andric printLE(Out, S.second); 59006c3fb27SDimitry Andric for (auto S : SymMap.Map) 59106c3fb27SDimitry Andric Out << S.first << '\0'; 59206c3fb27SDimitry Andric 59306c3fb27SDimitry Andric while (Pad--) 59406c3fb27SDimitry Andric Out.write(uint8_t(0)); 59506c3fb27SDimitry Andric } 59606c3fb27SDimitry Andric 59706c3fb27SDimitry Andric static void writeECSymbols(raw_ostream &Out, object::Archive::Kind Kind, 59806c3fb27SDimitry Andric bool Deterministic, ArrayRef<MemberData> Members, 59906c3fb27SDimitry Andric SymMap &SymMap) { 60006c3fb27SDimitry Andric uint32_t Pad; 60106c3fb27SDimitry Andric uint64_t Size = computeECSymbolsSize(SymMap, &Pad); 60206c3fb27SDimitry Andric printGNUSmallMemberHeader(Out, "/<ECSYMBOLS>", now(Deterministic), 0, 0, 0, 60306c3fb27SDimitry Andric Size); 60406c3fb27SDimitry Andric 60506c3fb27SDimitry Andric printLE<uint32_t>(Out, SymMap.ECMap.size()); 60606c3fb27SDimitry Andric 60706c3fb27SDimitry Andric for (auto S : SymMap.ECMap) 60806c3fb27SDimitry Andric printLE(Out, S.second); 60906c3fb27SDimitry Andric for (auto S : SymMap.ECMap) 61006c3fb27SDimitry Andric Out << S.first << '\0'; 61106c3fb27SDimitry Andric while (Pad--) 61206c3fb27SDimitry Andric Out.write(uint8_t(0)); 61306c3fb27SDimitry Andric } 61406c3fb27SDimitry Andric 61506c3fb27SDimitry Andric static bool isECObject(object::SymbolicFile &Obj) { 61606c3fb27SDimitry Andric if (Obj.isCOFF()) 61706c3fb27SDimitry Andric return cast<llvm::object::COFFObjectFile>(&Obj)->getMachine() != 61806c3fb27SDimitry Andric COFF::IMAGE_FILE_MACHINE_ARM64; 61906c3fb27SDimitry Andric 62006c3fb27SDimitry Andric if (Obj.isIR()) { 62106c3fb27SDimitry Andric Expected<std::string> TripleStr = 62206c3fb27SDimitry Andric getBitcodeTargetTriple(Obj.getMemoryBufferRef()); 62306c3fb27SDimitry Andric if (!TripleStr) 62406c3fb27SDimitry Andric return false; 62506c3fb27SDimitry Andric Triple T(*TripleStr); 62606c3fb27SDimitry Andric return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64; 62706c3fb27SDimitry Andric } 62806c3fb27SDimitry Andric 62906c3fb27SDimitry Andric return false; 63006c3fb27SDimitry Andric } 63106c3fb27SDimitry Andric 63206c3fb27SDimitry Andric static Expected<std::vector<unsigned>> 63306c3fb27SDimitry Andric getSymbols(MemoryBufferRef Buf, uint16_t Index, raw_ostream &SymNames, 63406c3fb27SDimitry Andric SymMap *SymMap, bool &HasObject) { 6350b57cec5SDimitry Andric // In the scenario when LLVMContext is populated SymbolicFile will contain a 6360b57cec5SDimitry Andric // reference to it, thus SymbolicFile should be destroyed first. 6370b57cec5SDimitry Andric LLVMContext Context; 638e8d8bef9SDimitry Andric 63906c3fb27SDimitry Andric std::vector<unsigned> Ret; 64006c3fb27SDimitry Andric Expected<std::unique_ptr<SymbolicFile>> ObjOrErr = 64106c3fb27SDimitry Andric getSymbolicFile(Buf, Context); 64206c3fb27SDimitry Andric if (!ObjOrErr) 64306c3fb27SDimitry Andric return ObjOrErr.takeError(); 64406c3fb27SDimitry Andric 64506c3fb27SDimitry Andric // If the member is non-symbolic file, treat it as having no symbols. 64606c3fb27SDimitry Andric if (!*ObjOrErr) 647e8d8bef9SDimitry Andric return Ret; 6480b57cec5SDimitry Andric 64906c3fb27SDimitry Andric std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); 65006c3fb27SDimitry Andric 65106c3fb27SDimitry Andric std::map<std::string, uint16_t> *Map = nullptr; 65206c3fb27SDimitry Andric if (SymMap) 65306c3fb27SDimitry Andric Map = SymMap->UseECMap && isECObject(*Obj) ? &SymMap->ECMap : &SymMap->Map; 6540b57cec5SDimitry Andric HasObject = true; 6550b57cec5SDimitry Andric for (const object::BasicSymbolRef &S : Obj->symbols()) { 6560b57cec5SDimitry Andric if (!isArchiveSymbol(S)) 6570b57cec5SDimitry Andric continue; 65806c3fb27SDimitry Andric if (Map) { 65906c3fb27SDimitry Andric std::string Name; 66006c3fb27SDimitry Andric raw_string_ostream NameStream(Name); 66106c3fb27SDimitry Andric if (Error E = S.printName(NameStream)) 66206c3fb27SDimitry Andric return std::move(E); 66306c3fb27SDimitry Andric if (Map->find(Name) != Map->end()) 66406c3fb27SDimitry Andric continue; // ignore duplicated symbol 66506c3fb27SDimitry Andric (*Map)[Name] = Index; 66606c3fb27SDimitry Andric if (Map == &SymMap->Map) { 66706c3fb27SDimitry Andric Ret.push_back(SymNames.tell()); 66806c3fb27SDimitry Andric SymNames << Name << '\0'; 66906c3fb27SDimitry Andric } 67006c3fb27SDimitry Andric } else { 6710b57cec5SDimitry Andric Ret.push_back(SymNames.tell()); 6720b57cec5SDimitry Andric if (Error E = S.printName(SymNames)) 6730b57cec5SDimitry Andric return std::move(E); 6740b57cec5SDimitry Andric SymNames << '\0'; 6750b57cec5SDimitry Andric } 67606c3fb27SDimitry Andric } 6770b57cec5SDimitry Andric return Ret; 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric static Expected<std::vector<MemberData>> 6810b57cec5SDimitry Andric computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, 6820b57cec5SDimitry Andric object::Archive::Kind Kind, bool Thin, bool Deterministic, 68306c3fb27SDimitry Andric bool NeedSymbols, SymMap *SymMap, 68406c3fb27SDimitry Andric ArrayRef<NewArchiveMember> NewMembers) { 6850b57cec5SDimitry Andric static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; 6860b57cec5SDimitry Andric 68781ad6265SDimitry Andric uint64_t Pos = 68881ad6265SDimitry Andric isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0; 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric std::vector<MemberData> Ret; 6910b57cec5SDimitry Andric bool HasObject = false; 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric // Deduplicate long member names in the string table and reuse earlier name 6940b57cec5SDimitry Andric // offsets. This especially saves space for COFF Import libraries where all 6950b57cec5SDimitry Andric // members have the same name. 6960b57cec5SDimitry Andric StringMap<uint64_t> MemberNames; 6970b57cec5SDimitry Andric 6980b57cec5SDimitry Andric // UniqueTimestamps is a special case to improve debugging on Darwin: 6990b57cec5SDimitry Andric // 7000b57cec5SDimitry Andric // The Darwin linker does not link debug info into the final 7010b57cec5SDimitry Andric // binary. Instead, it emits entries of type N_OSO in in the output 7020b57cec5SDimitry Andric // binary's symbol table, containing references to the linked-in 7030b57cec5SDimitry Andric // object files. Using that reference, the debugger can read the 7040b57cec5SDimitry Andric // debug data directly from the object files. Alternatively, an 7050b57cec5SDimitry Andric // invocation of 'dsymutil' will link the debug data from the object 7060b57cec5SDimitry Andric // files into a dSYM bundle, which can be loaded by the debugger, 7070b57cec5SDimitry Andric // instead of the object files. 7080b57cec5SDimitry Andric // 7090b57cec5SDimitry Andric // For an object file, the N_OSO entries contain the absolute path 7100b57cec5SDimitry Andric // path to the file, and the file's timestamp. For an object 7110b57cec5SDimitry Andric // included in an archive, the path is formatted like 7120b57cec5SDimitry Andric // "/absolute/path/to/archive.a(member.o)", and the timestamp is the 7130b57cec5SDimitry Andric // archive member's timestamp, rather than the archive's timestamp. 7140b57cec5SDimitry Andric // 7150b57cec5SDimitry Andric // However, this doesn't always uniquely identify an object within 7160b57cec5SDimitry Andric // an archive -- an archive file can have multiple entries with the 7170b57cec5SDimitry Andric // same filename. (This will happen commonly if the original object 7180b57cec5SDimitry Andric // files started in different directories.) The only way they get 7190b57cec5SDimitry Andric // distinguished, then, is via the timestamp. But this process is 7200b57cec5SDimitry Andric // unable to find the correct object file in the archive when there 7210b57cec5SDimitry Andric // are two files of the same name and timestamp. 7220b57cec5SDimitry Andric // 7230b57cec5SDimitry Andric // Additionally, timestamp==0 is treated specially, and causes the 7240b57cec5SDimitry Andric // timestamp to be ignored as a match criteria. 7250b57cec5SDimitry Andric // 7260b57cec5SDimitry Andric // That will "usually" work out okay when creating an archive not in 7270b57cec5SDimitry Andric // deterministic timestamp mode, because the objects will probably 7280b57cec5SDimitry Andric // have been created at different timestamps. 7290b57cec5SDimitry Andric // 7300b57cec5SDimitry Andric // To ameliorate this problem, in deterministic archive mode (which 7310b57cec5SDimitry Andric // is the default), on Darwin we will emit a unique non-zero 7320b57cec5SDimitry Andric // timestamp for each entry with a duplicated name. This is still 7330b57cec5SDimitry Andric // deterministic: the only thing affecting that timestamp is the 7340b57cec5SDimitry Andric // order of the files in the resultant archive. 7350b57cec5SDimitry Andric // 7360b57cec5SDimitry Andric // See also the functions that handle the lookup: 7370b57cec5SDimitry Andric // in lldb: ObjectContainerBSDArchive::Archive::FindObject() 7380b57cec5SDimitry Andric // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers(). 7390b57cec5SDimitry Andric bool UniqueTimestamps = Deterministic && isDarwin(Kind); 7400b57cec5SDimitry Andric std::map<StringRef, unsigned> FilenameCount; 7410b57cec5SDimitry Andric if (UniqueTimestamps) { 7420b57cec5SDimitry Andric for (const NewArchiveMember &M : NewMembers) 7430b57cec5SDimitry Andric FilenameCount[M.MemberName]++; 7440b57cec5SDimitry Andric for (auto &Entry : FilenameCount) 7450b57cec5SDimitry Andric Entry.second = Entry.second > 1 ? 1 : 0; 7460b57cec5SDimitry Andric } 7470b57cec5SDimitry Andric 74881ad6265SDimitry Andric // The big archive format needs to know the offset of the previous member 74981ad6265SDimitry Andric // header. 75006c3fb27SDimitry Andric uint64_t PrevOffset = 0; 75106c3fb27SDimitry Andric uint16_t Index = 0; 7520b57cec5SDimitry Andric for (const NewArchiveMember &M : NewMembers) { 7530b57cec5SDimitry Andric std::string Header; 7540b57cec5SDimitry Andric raw_string_ostream Out(Header); 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric MemoryBufferRef Buf = M.Buf->getMemBufferRef(); 7570b57cec5SDimitry Andric StringRef Data = Thin ? "" : Buf.getBuffer(); 7580b57cec5SDimitry Andric 75906c3fb27SDimitry Andric Index++; 76006c3fb27SDimitry Andric 7610b57cec5SDimitry Andric // ld64 expects the members to be 8-byte aligned for 64-bit content and at 7620b57cec5SDimitry Andric // least 4-byte aligned for 32-bit content. Opt for the larger encoding 7630b57cec5SDimitry Andric // uniformly. This matches the behaviour with cctools and ensures that ld64 7640b57cec5SDimitry Andric // is happy with archives that we generate. 7650b57cec5SDimitry Andric unsigned MemberPadding = 7668bcb0991SDimitry Andric isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0; 7678bcb0991SDimitry Andric unsigned TailPadding = 7688bcb0991SDimitry Andric offsetToAlignment(Data.size() + MemberPadding, Align(2)); 7690b57cec5SDimitry Andric StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding); 7700b57cec5SDimitry Andric 7710b57cec5SDimitry Andric sys::TimePoint<std::chrono::seconds> ModTime; 7720b57cec5SDimitry Andric if (UniqueTimestamps) 7730b57cec5SDimitry Andric // Increment timestamp for each file of a given name. 7740b57cec5SDimitry Andric ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++); 7750b57cec5SDimitry Andric else 7760b57cec5SDimitry Andric ModTime = M.ModTime; 7778bcb0991SDimitry Andric 7788bcb0991SDimitry Andric uint64_t Size = Buf.getBufferSize() + MemberPadding; 7798bcb0991SDimitry Andric if (Size > object::Archive::MaxMemberSize) { 7808bcb0991SDimitry Andric std::string StringMsg = 7818bcb0991SDimitry Andric "File " + M.MemberName.str() + " exceeds size limit"; 7828bcb0991SDimitry Andric return make_error<object::GenericBinaryError>( 7838bcb0991SDimitry Andric std::move(StringMsg), object::object_error::parse_failed); 7848bcb0991SDimitry Andric } 7858bcb0991SDimitry Andric 78681ad6265SDimitry Andric if (isAIXBigArchive(Kind)) { 78706c3fb27SDimitry Andric uint64_t NextOffset = Pos + sizeof(object::BigArMemHdrType) + 78881ad6265SDimitry Andric alignTo(M.MemberName.size(), 2) + alignTo(Size, 2); 78981ad6265SDimitry Andric printBigArchiveMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID, 79081ad6265SDimitry Andric M.Perms, Size, PrevOffset, NextOffset); 79181ad6265SDimitry Andric PrevOffset = Pos; 79281ad6265SDimitry Andric } else { 7930b57cec5SDimitry Andric printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M, 7948bcb0991SDimitry Andric ModTime, Size); 79581ad6265SDimitry Andric } 7960b57cec5SDimitry Andric Out.flush(); 7970b57cec5SDimitry Andric 798e8d8bef9SDimitry Andric std::vector<unsigned> Symbols; 799e8d8bef9SDimitry Andric if (NeedSymbols) { 800e8d8bef9SDimitry Andric Expected<std::vector<unsigned>> SymbolsOrErr = 80106c3fb27SDimitry Andric getSymbols(Buf, Index, SymNames, SymMap, HasObject); 802bdd1243dSDimitry Andric if (!SymbolsOrErr) 803bdd1243dSDimitry Andric return createFileError(M.MemberName, SymbolsOrErr.takeError()); 804e8d8bef9SDimitry Andric Symbols = std::move(*SymbolsOrErr); 805e8d8bef9SDimitry Andric } 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric Pos += Header.size() + Data.size() + Padding.size(); 808e8d8bef9SDimitry Andric Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding}); 8090b57cec5SDimitry Andric } 8100b57cec5SDimitry Andric // If there are no symbols, emit an empty symbol table, to satisfy Solaris 8110b57cec5SDimitry Andric // tools, older versions of which expect a symbol table in a non-empty 8120b57cec5SDimitry Andric // archive, regardless of whether there are any symbols in it. 81306c3fb27SDimitry Andric if (HasObject && SymNames.tell() == 0 && !isCOFFArchive(Kind)) 8140b57cec5SDimitry Andric SymNames << '\0' << '\0' << '\0'; 8150b57cec5SDimitry Andric return Ret; 8160b57cec5SDimitry Andric } 8170b57cec5SDimitry Andric 8180b57cec5SDimitry Andric namespace llvm { 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) { 8210b57cec5SDimitry Andric SmallString<128> Ret = P; 8220b57cec5SDimitry Andric std::error_code Err = sys::fs::make_absolute(Ret); 8230b57cec5SDimitry Andric if (Err) 8240b57cec5SDimitry Andric return Err; 8250b57cec5SDimitry Andric sys::path::remove_dots(Ret, /*removedotdot*/ true); 8260b57cec5SDimitry Andric return Ret; 8270b57cec5SDimitry Andric } 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric // Compute the relative path from From to To. 8300b57cec5SDimitry Andric Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) { 8310b57cec5SDimitry Andric ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To); 8320b57cec5SDimitry Andric ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From); 8330b57cec5SDimitry Andric if (!PathToOrErr || !DirFromOrErr) 8340b57cec5SDimitry Andric return errorCodeToError(std::error_code(errno, std::generic_category())); 8350b57cec5SDimitry Andric 8360b57cec5SDimitry Andric const SmallString<128> &PathTo = *PathToOrErr; 8370b57cec5SDimitry Andric const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr); 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric // Can't construct a relative path between different roots 8400b57cec5SDimitry Andric if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom)) 8410b57cec5SDimitry Andric return sys::path::convert_to_slash(PathTo); 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric // Skip common prefixes 8440b57cec5SDimitry Andric auto FromTo = 8450b57cec5SDimitry Andric std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom), 8460b57cec5SDimitry Andric sys::path::begin(PathTo)); 8470b57cec5SDimitry Andric auto FromI = FromTo.first; 8480b57cec5SDimitry Andric auto ToI = FromTo.second; 8490b57cec5SDimitry Andric 8500b57cec5SDimitry Andric // Construct relative path 8510b57cec5SDimitry Andric SmallString<128> Relative; 8520b57cec5SDimitry Andric for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI) 8530b57cec5SDimitry Andric sys::path::append(Relative, sys::path::Style::posix, ".."); 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI) 8560b57cec5SDimitry Andric sys::path::append(Relative, sys::path::Style::posix, *ToI); 8570b57cec5SDimitry Andric 8585ffd83dbSDimitry Andric return std::string(Relative.str()); 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric 861e8d8bef9SDimitry Andric static Error writeArchiveToStream(raw_ostream &Out, 862e8d8bef9SDimitry Andric ArrayRef<NewArchiveMember> NewMembers, 8630b57cec5SDimitry Andric bool WriteSymtab, object::Archive::Kind Kind, 86406c3fb27SDimitry Andric bool Deterministic, bool Thin, bool IsEC) { 8650b57cec5SDimitry Andric assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric SmallString<0> SymNamesBuf; 8680b57cec5SDimitry Andric raw_svector_ostream SymNames(SymNamesBuf); 8690b57cec5SDimitry Andric SmallString<0> StringTableBuf; 8700b57cec5SDimitry Andric raw_svector_ostream StringTable(StringTableBuf); 87106c3fb27SDimitry Andric SymMap SymMap; 8720b57cec5SDimitry Andric 87306c3fb27SDimitry Andric // COFF symbol map uses 16-bit indexes, so we can't use it if there are too 87406c3fb27SDimitry Andric // many members. 87506c3fb27SDimitry Andric if (isCOFFArchive(Kind) && NewMembers.size() > 0xfffe) 87606c3fb27SDimitry Andric Kind = object::Archive::K_GNU; 87706c3fb27SDimitry Andric 87806c3fb27SDimitry Andric SymMap.UseECMap = IsEC; 87906c3fb27SDimitry Andric Expected<std::vector<MemberData>> DataOrErr = computeMemberData( 88006c3fb27SDimitry Andric StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab, 88106c3fb27SDimitry Andric isCOFFArchive(Kind) ? &SymMap : nullptr, NewMembers); 8820b57cec5SDimitry Andric if (Error E = DataOrErr.takeError()) 8830b57cec5SDimitry Andric return E; 8840b57cec5SDimitry Andric std::vector<MemberData> &Data = *DataOrErr; 8850b57cec5SDimitry Andric 88606c3fb27SDimitry Andric uint64_t StringTableSize = 0; 88706c3fb27SDimitry Andric MemberData StringTableMember; 88806c3fb27SDimitry Andric if (!StringTableBuf.empty() && !isAIXBigArchive(Kind)) { 88906c3fb27SDimitry Andric StringTableMember = computeStringTable(StringTableBuf); 89006c3fb27SDimitry Andric StringTableSize = StringTableMember.Header.size() + 89106c3fb27SDimitry Andric StringTableMember.Data.size() + 89206c3fb27SDimitry Andric StringTableMember.Padding.size(); 89306c3fb27SDimitry Andric } 8940b57cec5SDimitry Andric 8950b57cec5SDimitry Andric // We would like to detect if we need to switch to a 64-bit symbol table. 89606c3fb27SDimitry Andric uint64_t LastMemberEndOffset = 0; 89706c3fb27SDimitry Andric uint64_t LastMemberHeaderOffset = 0; 898e8d8bef9SDimitry Andric uint64_t NumSyms = 0; 89906c3fb27SDimitry Andric uint64_t NumSyms32 = 0; // Store symbol number of 32-bit member files. 90006c3fb27SDimitry Andric 9010b57cec5SDimitry Andric for (const auto &M : Data) { 9020b57cec5SDimitry Andric // Record the start of the member's offset 90381ad6265SDimitry Andric LastMemberHeaderOffset = LastMemberEndOffset; 9040b57cec5SDimitry Andric // Account for the size of each part associated with the member. 90581ad6265SDimitry Andric LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size(); 906e8d8bef9SDimitry Andric NumSyms += M.Symbols.size(); 90706c3fb27SDimitry Andric 90806c3fb27SDimitry Andric // AIX big archive files may contain two global symbol tables. The 90906c3fb27SDimitry Andric // first global symbol table locates 32-bit file members that define global 91006c3fb27SDimitry Andric // symbols; the second global symbol table does the same for 64-bit file 91106c3fb27SDimitry Andric // members. As a big archive can have both 32-bit and 64-bit file members, 91206c3fb27SDimitry Andric // we need to know the number of symbols in each symbol table individually. 91306c3fb27SDimitry Andric if (isAIXBigArchive(Kind) && WriteSymtab) { 91406c3fb27SDimitry Andric Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data); 91506c3fb27SDimitry Andric if (Error E = Is64BitOrErr.takeError()) 91606c3fb27SDimitry Andric return E; 91706c3fb27SDimitry Andric 91806c3fb27SDimitry Andric if (!*Is64BitOrErr) 91906c3fb27SDimitry Andric NumSyms32 += M.Symbols.size(); 9200b57cec5SDimitry Andric } 92106c3fb27SDimitry Andric } 92206c3fb27SDimitry Andric 92306c3fb27SDimitry Andric std::optional<uint64_t> HeadersSize; 9240b57cec5SDimitry Andric 92581ad6265SDimitry Andric // The symbol table is put at the end of the big archive file. The symbol 92681ad6265SDimitry Andric // table is at the start of the archive file for other archive formats. 92706c3fb27SDimitry Andric if (WriteSymtab && !is64BitKind(Kind)) { 928e8d8bef9SDimitry Andric // We assume 32-bit offsets to see if 32-bit symbols are possible or not. 92906c3fb27SDimitry Andric HeadersSize = computeHeadersSize(Kind, Data.size(), StringTableSize, 93006c3fb27SDimitry Andric NumSyms, SymNamesBuf.size(), 93106c3fb27SDimitry Andric isCOFFArchive(Kind) ? &SymMap : nullptr); 932e8d8bef9SDimitry Andric 9330b57cec5SDimitry Andric // The SYM64 format is used when an archive's member offsets are larger than 9340b57cec5SDimitry Andric // 32-bits can hold. The need for this shift in format is detected by 9350b57cec5SDimitry Andric // writeArchive. To test this we need to generate a file with a member that 9360b57cec5SDimitry Andric // has an offset larger than 32-bits but this demands a very slow test. To 9370b57cec5SDimitry Andric // speed the test up we use this environment variable to pretend like the 9380b57cec5SDimitry Andric // cutoff happens before 32-bits and instead happens at some much smaller 9390b57cec5SDimitry Andric // value. 940e8d8bef9SDimitry Andric uint64_t Sym64Threshold = 1ULL << 32; 9410b57cec5SDimitry Andric const char *Sym64Env = std::getenv("SYM64_THRESHOLD"); 9420b57cec5SDimitry Andric if (Sym64Env) 9430b57cec5SDimitry Andric StringRef(Sym64Env).getAsInteger(10, Sym64Threshold); 9440b57cec5SDimitry Andric 94581ad6265SDimitry Andric // If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need 94681ad6265SDimitry Andric // to switch to 64-bit. Note that the file can be larger than 4GB as long as 94781ad6265SDimitry Andric // the last member starts before the 4GB offset. 94806c3fb27SDimitry Andric if (*HeadersSize + LastMemberHeaderOffset >= Sym64Threshold) { 9490b57cec5SDimitry Andric if (Kind == object::Archive::K_DARWIN) 9500b57cec5SDimitry Andric Kind = object::Archive::K_DARWIN64; 9510b57cec5SDimitry Andric else 9520b57cec5SDimitry Andric Kind = object::Archive::K_GNU64; 95306c3fb27SDimitry Andric HeadersSize.reset(); 9540b57cec5SDimitry Andric } 9550b57cec5SDimitry Andric } 9560b57cec5SDimitry Andric 9570b57cec5SDimitry Andric if (Thin) 9580b57cec5SDimitry Andric Out << "!<thin>\n"; 95981ad6265SDimitry Andric else if (isAIXBigArchive(Kind)) 96081ad6265SDimitry Andric Out << "<bigaf>\n"; 9610b57cec5SDimitry Andric else 9620b57cec5SDimitry Andric Out << "!<arch>\n"; 9630b57cec5SDimitry Andric 96481ad6265SDimitry Andric if (!isAIXBigArchive(Kind)) { 96506c3fb27SDimitry Andric if (WriteSymtab) { 96606c3fb27SDimitry Andric if (!HeadersSize) 96706c3fb27SDimitry Andric HeadersSize = computeHeadersSize( 96806c3fb27SDimitry Andric Kind, Data.size(), StringTableSize, NumSyms, SymNamesBuf.size(), 96906c3fb27SDimitry Andric isCOFFArchive(Kind) ? &SymMap : nullptr); 97006c3fb27SDimitry Andric writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf, 97106c3fb27SDimitry Andric *HeadersSize, NumSyms); 97206c3fb27SDimitry Andric 97306c3fb27SDimitry Andric if (isCOFFArchive(Kind)) 97406c3fb27SDimitry Andric writeSymbolMap(Out, Kind, Deterministic, Data, SymMap, *HeadersSize); 97506c3fb27SDimitry Andric } 97606c3fb27SDimitry Andric 97706c3fb27SDimitry Andric if (StringTableSize) 97806c3fb27SDimitry Andric Out << StringTableMember.Header << StringTableMember.Data 97906c3fb27SDimitry Andric << StringTableMember.Padding; 98006c3fb27SDimitry Andric 98106c3fb27SDimitry Andric if (WriteSymtab && SymMap.ECMap.size()) 98206c3fb27SDimitry Andric writeECSymbols(Out, Kind, Deterministic, Data, SymMap); 98306c3fb27SDimitry Andric 9840b57cec5SDimitry Andric for (const MemberData &M : Data) 9850b57cec5SDimitry Andric Out << M.Header << M.Data << M.Padding; 98681ad6265SDimitry Andric } else { 98706c3fb27SDimitry Andric HeadersSize = sizeof(object::BigArchive::FixLenHdr); 98806c3fb27SDimitry Andric LastMemberEndOffset += *HeadersSize; 98906c3fb27SDimitry Andric LastMemberHeaderOffset += *HeadersSize; 99006c3fb27SDimitry Andric 99181ad6265SDimitry Andric // For the big archive (AIX) format, compute a table of member names and 99281ad6265SDimitry Andric // offsets, used in the member table. 99381ad6265SDimitry Andric uint64_t MemberTableNameStrTblSize = 0; 99481ad6265SDimitry Andric std::vector<size_t> MemberOffsets; 99581ad6265SDimitry Andric std::vector<StringRef> MemberNames; 99681ad6265SDimitry Andric // Loop across object to find offset and names. 99781ad6265SDimitry Andric uint64_t MemberEndOffset = sizeof(object::BigArchive::FixLenHdr); 99881ad6265SDimitry Andric for (size_t I = 0, Size = NewMembers.size(); I != Size; ++I) { 99981ad6265SDimitry Andric const NewArchiveMember &Member = NewMembers[I]; 100081ad6265SDimitry Andric MemberTableNameStrTblSize += Member.MemberName.size() + 1; 100181ad6265SDimitry Andric MemberOffsets.push_back(MemberEndOffset); 100281ad6265SDimitry Andric MemberNames.push_back(Member.MemberName); 100381ad6265SDimitry Andric // File member name ended with "`\n". The length is included in 100481ad6265SDimitry Andric // BigArMemHdrType. 100581ad6265SDimitry Andric MemberEndOffset += sizeof(object::BigArMemHdrType) + 100681ad6265SDimitry Andric alignTo(Data[I].Data.size(), 2) + 100781ad6265SDimitry Andric alignTo(Member.MemberName.size(), 2); 100881ad6265SDimitry Andric } 10090b57cec5SDimitry Andric 101081ad6265SDimitry Andric // AIX member table size. 101106c3fb27SDimitry Andric uint64_t MemberTableSize = 20 + // Number of members field 101281ad6265SDimitry Andric 20 * MemberOffsets.size() + 101381ad6265SDimitry Andric MemberTableNameStrTblSize; 101481ad6265SDimitry Andric 101506c3fb27SDimitry Andric SmallString<0> SymNamesBuf32; 101606c3fb27SDimitry Andric SmallString<0> SymNamesBuf64; 101706c3fb27SDimitry Andric raw_svector_ostream SymNames32(SymNamesBuf32); 101806c3fb27SDimitry Andric raw_svector_ostream SymNames64(SymNamesBuf64); 101906c3fb27SDimitry Andric 102006c3fb27SDimitry Andric if (WriteSymtab && NumSyms) 102106c3fb27SDimitry Andric // Generate the symbol names for the members. 102206c3fb27SDimitry Andric for (const NewArchiveMember &M : NewMembers) { 102306c3fb27SDimitry Andric MemoryBufferRef Buf = M.Buf->getMemBufferRef(); 102406c3fb27SDimitry Andric Expected<bool> Is64BitOrErr = is64BitSymbolicFile(Buf.getBuffer()); 102506c3fb27SDimitry Andric if (!Is64BitOrErr) 102606c3fb27SDimitry Andric return Is64BitOrErr.takeError(); 102706c3fb27SDimitry Andric 102806c3fb27SDimitry Andric bool HasObject; 102906c3fb27SDimitry Andric Expected<std::vector<unsigned>> SymbolsOrErr = 103006c3fb27SDimitry Andric getSymbols(Buf, 0, *Is64BitOrErr ? SymNames64 : SymNames32, nullptr, 103106c3fb27SDimitry Andric HasObject); 103206c3fb27SDimitry Andric if (!SymbolsOrErr) 103306c3fb27SDimitry Andric return SymbolsOrErr.takeError(); 103406c3fb27SDimitry Andric } 103506c3fb27SDimitry Andric 103606c3fb27SDimitry Andric uint64_t MemberTableEndOffset = 103706c3fb27SDimitry Andric LastMemberEndOffset + 103806c3fb27SDimitry Andric alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2); 103906c3fb27SDimitry Andric 104006c3fb27SDimitry Andric // In AIX OS, The 'GlobSymOffset' field in the fixed-length header contains 104106c3fb27SDimitry Andric // the offset to the 32-bit global symbol table, and the 'GlobSym64Offset' 104206c3fb27SDimitry Andric // contains the offset to the 64-bit global symbol table. 104306c3fb27SDimitry Andric uint64_t GlobalSymbolOffset = 104406c3fb27SDimitry Andric (WriteSymtab && NumSyms32 > 0) ? MemberTableEndOffset : 0; 104506c3fb27SDimitry Andric 104606c3fb27SDimitry Andric uint64_t GlobalSymbolOffset64 = 0; 104706c3fb27SDimitry Andric uint64_t NumSyms64 = NumSyms - NumSyms32; 104806c3fb27SDimitry Andric if (WriteSymtab && NumSyms64 > 0) { 104906c3fb27SDimitry Andric if (GlobalSymbolOffset == 0) 105006c3fb27SDimitry Andric GlobalSymbolOffset64 = MemberTableEndOffset; 105106c3fb27SDimitry Andric else 105206c3fb27SDimitry Andric // If there is a global symbol table for 32-bit members, 105306c3fb27SDimitry Andric // the 64-bit global symbol table is after the 32-bit one. 105406c3fb27SDimitry Andric GlobalSymbolOffset64 = 105506c3fb27SDimitry Andric GlobalSymbolOffset + sizeof(object::BigArMemHdrType) + 105606c3fb27SDimitry Andric (NumSyms32 + 1) * 8 + alignTo(SymNamesBuf32.size(), 2); 105706c3fb27SDimitry Andric } 105881ad6265SDimitry Andric 105981ad6265SDimitry Andric // Fixed Sized Header. 106081ad6265SDimitry Andric printWithSpacePadding(Out, NewMembers.size() ? LastMemberEndOffset : 0, 106181ad6265SDimitry Andric 20); // Offset to member table 106281ad6265SDimitry Andric // If there are no file members in the archive, there will be no global 106381ad6265SDimitry Andric // symbol table. 106406c3fb27SDimitry Andric printWithSpacePadding(Out, GlobalSymbolOffset, 20); 106506c3fb27SDimitry Andric printWithSpacePadding(Out, GlobalSymbolOffset64, 20); 106681ad6265SDimitry Andric printWithSpacePadding( 106781ad6265SDimitry Andric Out, NewMembers.size() ? sizeof(object::BigArchive::FixLenHdr) : 0, 106881ad6265SDimitry Andric 20); // Offset to first archive member 106981ad6265SDimitry Andric printWithSpacePadding(Out, NewMembers.size() ? LastMemberHeaderOffset : 0, 107081ad6265SDimitry Andric 20); // Offset to last archive member 107181ad6265SDimitry Andric printWithSpacePadding( 107281ad6265SDimitry Andric Out, 0, 107381ad6265SDimitry Andric 20); // Offset to first member of free list - Not supported yet 107481ad6265SDimitry Andric 107581ad6265SDimitry Andric for (const MemberData &M : Data) { 107681ad6265SDimitry Andric Out << M.Header << M.Data; 107781ad6265SDimitry Andric if (M.Data.size() % 2) 107881ad6265SDimitry Andric Out << '\0'; 107981ad6265SDimitry Andric } 108081ad6265SDimitry Andric 108181ad6265SDimitry Andric if (NewMembers.size()) { 108281ad6265SDimitry Andric // Member table. 108381ad6265SDimitry Andric printBigArchiveMemberHeader(Out, "", sys::toTimePoint(0), 0, 0, 0, 108481ad6265SDimitry Andric MemberTableSize, LastMemberHeaderOffset, 108506c3fb27SDimitry Andric GlobalSymbolOffset ? GlobalSymbolOffset 108606c3fb27SDimitry Andric : GlobalSymbolOffset64); 108781ad6265SDimitry Andric printWithSpacePadding(Out, MemberOffsets.size(), 20); // Number of members 108881ad6265SDimitry Andric for (uint64_t MemberOffset : MemberOffsets) 108981ad6265SDimitry Andric printWithSpacePadding(Out, MemberOffset, 109081ad6265SDimitry Andric 20); // Offset to member file header. 109181ad6265SDimitry Andric for (StringRef MemberName : MemberNames) 109281ad6265SDimitry Andric Out << MemberName << '\0'; // Member file name, null byte padding. 109381ad6265SDimitry Andric 109481ad6265SDimitry Andric if (MemberTableNameStrTblSize % 2) 109581ad6265SDimitry Andric Out << '\0'; // Name table must be tail padded to an even number of 109681ad6265SDimitry Andric // bytes. 109781ad6265SDimitry Andric 109806c3fb27SDimitry Andric if (WriteSymtab) { 109906c3fb27SDimitry Andric // Write global symbol table for 32-bit file members. 110006c3fb27SDimitry Andric if (GlobalSymbolOffset) { 110106c3fb27SDimitry Andric writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf32, 110206c3fb27SDimitry Andric *HeadersSize, NumSyms32, LastMemberEndOffset, 110306c3fb27SDimitry Andric GlobalSymbolOffset64); 110406c3fb27SDimitry Andric // Add padding between the symbol tables, if needed. 110506c3fb27SDimitry Andric if (GlobalSymbolOffset64 && (SymNamesBuf32.size() % 2)) 110606c3fb27SDimitry Andric Out << '\0'; 110706c3fb27SDimitry Andric } 110806c3fb27SDimitry Andric 110906c3fb27SDimitry Andric // Write global symbol table for 64-bit file members. 111006c3fb27SDimitry Andric if (GlobalSymbolOffset64) 111106c3fb27SDimitry Andric writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf64, 111206c3fb27SDimitry Andric *HeadersSize, NumSyms64, 111306c3fb27SDimitry Andric GlobalSymbolOffset ? GlobalSymbolOffset 111406c3fb27SDimitry Andric : LastMemberEndOffset, 111506c3fb27SDimitry Andric 0, true); 111606c3fb27SDimitry Andric } 111781ad6265SDimitry Andric } 111881ad6265SDimitry Andric } 11190b57cec5SDimitry Andric Out.flush(); 1120e8d8bef9SDimitry Andric return Error::success(); 1121e8d8bef9SDimitry Andric } 1122e8d8bef9SDimitry Andric 1123e8d8bef9SDimitry Andric Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, 1124e8d8bef9SDimitry Andric bool WriteSymtab, object::Archive::Kind Kind, 1125e8d8bef9SDimitry Andric bool Deterministic, bool Thin, 112606c3fb27SDimitry Andric std::unique_ptr<MemoryBuffer> OldArchiveBuf, bool IsEC) { 1127e8d8bef9SDimitry Andric Expected<sys::fs::TempFile> Temp = 1128e8d8bef9SDimitry Andric sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a"); 1129e8d8bef9SDimitry Andric if (!Temp) 1130e8d8bef9SDimitry Andric return Temp.takeError(); 1131e8d8bef9SDimitry Andric raw_fd_ostream Out(Temp->FD, false); 1132e8d8bef9SDimitry Andric 1133e8d8bef9SDimitry Andric if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind, 113406c3fb27SDimitry Andric Deterministic, Thin, IsEC)) { 1135e8d8bef9SDimitry Andric if (Error DiscardError = Temp->discard()) 1136e8d8bef9SDimitry Andric return joinErrors(std::move(E), std::move(DiscardError)); 1137e8d8bef9SDimitry Andric return E; 1138e8d8bef9SDimitry Andric } 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric // At this point, we no longer need whatever backing memory 11410b57cec5SDimitry Andric // was used to generate the NewMembers. On Windows, this buffer 11420b57cec5SDimitry Andric // could be a mapped view of the file we want to replace (if 11430b57cec5SDimitry Andric // we're updating an existing archive, say). In that case, the 11440b57cec5SDimitry Andric // rename would still succeed, but it would leave behind a 11450b57cec5SDimitry Andric // temporary file (actually the original file renamed) because 11460b57cec5SDimitry Andric // a file cannot be deleted while there's a handle open on it, 11470b57cec5SDimitry Andric // only renamed. So by freeing this buffer, this ensures that 11480b57cec5SDimitry Andric // the last open handle on the destination file, if any, is 11490b57cec5SDimitry Andric // closed before we attempt to rename. 11500b57cec5SDimitry Andric OldArchiveBuf.reset(); 11510b57cec5SDimitry Andric 11520b57cec5SDimitry Andric return Temp->keep(ArcName); 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric 1155e8d8bef9SDimitry Andric Expected<std::unique_ptr<MemoryBuffer>> 1156e8d8bef9SDimitry Andric writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab, 1157e8d8bef9SDimitry Andric object::Archive::Kind Kind, bool Deterministic, 1158e8d8bef9SDimitry Andric bool Thin) { 1159e8d8bef9SDimitry Andric SmallVector<char, 0> ArchiveBufferVector; 1160e8d8bef9SDimitry Andric raw_svector_ostream ArchiveStream(ArchiveBufferVector); 1161e8d8bef9SDimitry Andric 1162e8d8bef9SDimitry Andric if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab, 116306c3fb27SDimitry Andric Kind, Deterministic, Thin, false)) 1164e8d8bef9SDimitry Andric return std::move(E); 1165e8d8bef9SDimitry Andric 1166e8d8bef9SDimitry Andric return std::make_unique<SmallVectorMemoryBuffer>( 11670eae32dcSDimitry Andric std::move(ArchiveBufferVector), /*RequiresNullTerminator=*/false); 1168e8d8bef9SDimitry Andric } 1169e8d8bef9SDimitry Andric 11700b57cec5SDimitry Andric } // namespace llvm 1171