ArchiveWriter.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. //===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file defines the writeArchive function.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/Object/ArchiveWriter.h"
  14. #include "llvm/ADT/ArrayRef.h"
  15. #include "llvm/ADT/StringRef.h"
  16. #include "llvm/BinaryFormat/Magic.h"
  17. #include "llvm/IR/LLVMContext.h"
  18. #include "llvm/Object/Archive.h"
  19. #include "llvm/Object/ObjectFile.h"
  20. #include "llvm/Object/SymbolicFile.h"
  21. #include "llvm/Support/EndianStream.h"
  22. #include "llvm/Support/Errc.h"
  23. #include "llvm/Support/ErrorHandling.h"
  24. #include "llvm/Support/Format.h"
  25. #include "llvm/Support/Path.h"
  26. #include "llvm/Support/ToolOutputFile.h"
  27. #include "llvm/Support/raw_ostream.h"
  28. #if !defined(_MSC_VER) && !defined(__MINGW32__)
  29. #include <unistd.h>
  30. #else
  31. #include <io.h>
  32. #endif
  33. using namespace llvm;
  34. NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
  35. : Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
  36. MemberName(BufRef.getBufferIdentifier()) {}
  37. Expected<NewArchiveMember>
  38. NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
  39. bool Deterministic) {
  40. Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
  41. if (!BufOrErr)
  42. return BufOrErr.takeError();
  43. NewArchiveMember M;
  44. assert(M.IsNew == false);
  45. M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
  46. M.MemberName = M.Buf->getBufferIdentifier();
  47. if (!Deterministic) {
  48. auto ModTimeOrErr = OldMember.getLastModified();
  49. if (!ModTimeOrErr)
  50. return ModTimeOrErr.takeError();
  51. M.ModTime = ModTimeOrErr.get();
  52. Expected<unsigned> UIDOrErr = OldMember.getUID();
  53. if (!UIDOrErr)
  54. return UIDOrErr.takeError();
  55. M.UID = UIDOrErr.get();
  56. Expected<unsigned> GIDOrErr = OldMember.getGID();
  57. if (!GIDOrErr)
  58. return GIDOrErr.takeError();
  59. M.GID = GIDOrErr.get();
  60. Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
  61. if (!AccessModeOrErr)
  62. return AccessModeOrErr.takeError();
  63. M.Perms = AccessModeOrErr.get();
  64. }
  65. return std::move(M);
  66. }
  67. Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
  68. bool Deterministic) {
  69. sys::fs::file_status Status;
  70. int FD;
  71. if (auto EC = sys::fs::openFileForRead(FileName, FD))
  72. return errorCodeToError(EC);
  73. assert(FD != -1);
  74. if (auto EC = sys::fs::status(FD, Status))
  75. return errorCodeToError(EC);
  76. // Opening a directory doesn't make sense. Let it fail.
  77. // Linux cannot open directories with open(2), although
  78. // cygwin and *bsd can.
  79. if (Status.type() == sys::fs::file_type::directory_file)
  80. return errorCodeToError(make_error_code(errc::is_a_directory));
  81. ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
  82. MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
  83. if (!MemberBufferOrErr)
  84. return errorCodeToError(MemberBufferOrErr.getError());
  85. if (close(FD) != 0)
  86. return errorCodeToError(std::error_code(errno, std::generic_category()));
  87. NewArchiveMember M;
  88. M.IsNew = true;
  89. M.Buf = std::move(*MemberBufferOrErr);
  90. M.MemberName = M.Buf->getBufferIdentifier();
  91. if (!Deterministic) {
  92. M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
  93. Status.getLastModificationTime());
  94. M.UID = Status.getUser();
  95. M.GID = Status.getGroup();
  96. M.Perms = Status.permissions();
  97. }
  98. return std::move(M);
  99. }
  100. template <typename T>
  101. static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
  102. uint64_t OldPos = OS.tell();
  103. OS << Data;
  104. unsigned SizeSoFar = OS.tell() - OldPos;
  105. assert(SizeSoFar <= Size && "Data doesn't fit in Size");
  106. OS.indent(Size - SizeSoFar);
  107. }
  108. static bool isBSDLike(object::Archive::Kind Kind) {
  109. switch (Kind) {
  110. case object::Archive::K_GNU:
  111. return false;
  112. case object::Archive::K_BSD:
  113. case object::Archive::K_DARWIN:
  114. return true;
  115. case object::Archive::K_GNU64:
  116. case object::Archive::K_DARWIN64:
  117. case object::Archive::K_COFF:
  118. break;
  119. }
  120. llvm_unreachable("not supported for writting");
  121. }
  122. static void print32(raw_ostream &Out, object::Archive::Kind Kind,
  123. uint32_t Val) {
  124. if (isBSDLike(Kind))
  125. support::endian::Writer<support::little>(Out).write(Val);
  126. else
  127. support::endian::Writer<support::big>(Out).write(Val);
  128. }
  129. static void printRestOfMemberHeader(
  130. raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
  131. unsigned UID, unsigned GID, unsigned Perms, unsigned Size) {
  132. printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
  133. // The format has only 6 chars for uid and gid. Truncate if the provided
  134. // values don't fit.
  135. printWithSpacePadding(Out, UID % 1000000, 6);
  136. printWithSpacePadding(Out, GID % 1000000, 6);
  137. printWithSpacePadding(Out, format("%o", Perms), 8);
  138. printWithSpacePadding(Out, Size, 10);
  139. Out << "`\n";
  140. }
  141. static void
  142. printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
  143. const sys::TimePoint<std::chrono::seconds> &ModTime,
  144. unsigned UID, unsigned GID, unsigned Perms,
  145. unsigned Size) {
  146. printWithSpacePadding(Out, Twine(Name) + "/", 16);
  147. printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
  148. }
  149. static void
  150. printBSDMemberHeader(raw_ostream &Out, StringRef Name,
  151. const sys::TimePoint<std::chrono::seconds> &ModTime,
  152. unsigned UID, unsigned GID, unsigned Perms,
  153. unsigned Size) {
  154. uint64_t PosAfterHeader = Out.tell() + 60 + Name.size();
  155. // Pad so that even 64 bit object files are aligned.
  156. unsigned Pad = OffsetToAlignment(PosAfterHeader, 8);
  157. unsigned NameWithPadding = Name.size() + Pad;
  158. printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
  159. printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
  160. NameWithPadding + Size);
  161. Out << Name;
  162. assert(PosAfterHeader == Out.tell());
  163. while (Pad--)
  164. Out.write(uint8_t(0));
  165. }
  166. static bool useStringTable(bool Thin, StringRef Name) {
  167. return Thin || Name.size() >= 16 || Name.contains('/');
  168. }
  169. static void
  170. printMemberHeader(raw_ostream &Out, object::Archive::Kind Kind, bool Thin,
  171. StringRef Name,
  172. std::vector<unsigned>::iterator &StringMapIndexIter,
  173. const sys::TimePoint<std::chrono::seconds> &ModTime,
  174. unsigned UID, unsigned GID, unsigned Perms, unsigned Size) {
  175. if (isBSDLike(Kind))
  176. return printBSDMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
  177. if (!useStringTable(Thin, Name))
  178. return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
  179. Out << '/';
  180. printWithSpacePadding(Out, *StringMapIndexIter++, 15);
  181. printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
  182. }
  183. // Compute the relative path from From to To.
  184. static std::string computeRelativePath(StringRef From, StringRef To) {
  185. if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
  186. return To;
  187. StringRef DirFrom = sys::path::parent_path(From);
  188. auto FromI = sys::path::begin(DirFrom);
  189. auto ToI = sys::path::begin(To);
  190. while (*FromI == *ToI) {
  191. ++FromI;
  192. ++ToI;
  193. }
  194. SmallString<128> Relative;
  195. for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
  196. sys::path::append(Relative, "..");
  197. for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
  198. sys::path::append(Relative, *ToI);
  199. #ifdef LLVM_ON_WIN32
  200. // Replace backslashes with slashes so that the path is portable between *nix
  201. // and Windows.
  202. std::replace(Relative.begin(), Relative.end(), '\\', '/');
  203. #endif
  204. return Relative.str();
  205. }
  206. static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName,
  207. ArrayRef<NewArchiveMember> Members,
  208. std::vector<unsigned> &StringMapIndexes,
  209. bool Thin) {
  210. unsigned StartOffset = 0;
  211. for (const NewArchiveMember &M : Members) {
  212. StringRef Path = M.Buf->getBufferIdentifier();
  213. StringRef Name = M.MemberName;
  214. if (!useStringTable(Thin, Name))
  215. continue;
  216. if (StartOffset == 0) {
  217. printWithSpacePadding(Out, "//", 58);
  218. Out << "`\n";
  219. StartOffset = Out.tell();
  220. }
  221. StringMapIndexes.push_back(Out.tell() - StartOffset);
  222. if (Thin) {
  223. if (M.IsNew)
  224. Out << computeRelativePath(ArcName, Path);
  225. else
  226. Out << M.Buf->getBufferIdentifier();
  227. } else
  228. Out << Name;
  229. Out << "/\n";
  230. }
  231. if (StartOffset == 0)
  232. return;
  233. if (Out.tell() % 2)
  234. Out << '\n';
  235. int Pos = Out.tell();
  236. Out.seek(StartOffset - 12);
  237. printWithSpacePadding(Out, Pos - StartOffset, 10);
  238. Out.seek(Pos);
  239. }
  240. static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) {
  241. using namespace std::chrono;
  242. if (!Deterministic)
  243. return time_point_cast<seconds>(system_clock::now());
  244. return sys::TimePoint<seconds>();
  245. }
  246. static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
  247. uint32_t Symflags = S.getFlags();
  248. if (Symflags & object::SymbolRef::SF_FormatSpecific)
  249. return false;
  250. if (!(Symflags & object::SymbolRef::SF_Global))
  251. return false;
  252. if (Symflags & object::SymbolRef::SF_Undefined &&
  253. !(Symflags & object::SymbolRef::SF_Indirect))
  254. return false;
  255. return true;
  256. }
  257. // Returns the offset of the first reference to a member offset.
  258. static Expected<unsigned>
  259. writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
  260. ArrayRef<NewArchiveMember> Members,
  261. std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) {
  262. unsigned HeaderStartOffset = 0;
  263. unsigned BodyStartOffset = 0;
  264. SmallString<128> NameBuf;
  265. raw_svector_ostream NameOS(NameBuf);
  266. LLVMContext Context;
  267. for (unsigned MemberNum = 0, N = Members.size(); MemberNum < N; ++MemberNum) {
  268. MemoryBufferRef MemberBuffer = Members[MemberNum].Buf->getMemBufferRef();
  269. Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr =
  270. object::SymbolicFile::createSymbolicFile(
  271. MemberBuffer, llvm::file_magic::unknown, &Context);
  272. if (!ObjOrErr) {
  273. // FIXME: check only for "not an object file" errors.
  274. consumeError(ObjOrErr.takeError());
  275. continue;
  276. }
  277. object::SymbolicFile &Obj = *ObjOrErr.get();
  278. if (!HeaderStartOffset) {
  279. HeaderStartOffset = Out.tell();
  280. if (isBSDLike(Kind))
  281. printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0);
  282. else
  283. printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0);
  284. BodyStartOffset = Out.tell();
  285. print32(Out, Kind, 0); // number of entries or bytes
  286. }
  287. for (const object::BasicSymbolRef &S : Obj.symbols()) {
  288. if (!isArchiveSymbol(S))
  289. continue;
  290. unsigned NameOffset = NameOS.tell();
  291. if (std::error_code EC = S.printName(NameOS))
  292. return errorCodeToError(EC);
  293. NameOS << '\0';
  294. MemberOffsetRefs.push_back(MemberNum);
  295. if (isBSDLike(Kind))
  296. print32(Out, Kind, NameOffset);
  297. print32(Out, Kind, 0); // member offset
  298. }
  299. }
  300. if (HeaderStartOffset == 0)
  301. return 0;
  302. // ld64 prefers the cctools type archive which pads its string table to a
  303. // boundary of sizeof(int32_t).
  304. if (isBSDLike(Kind))
  305. for (unsigned P = OffsetToAlignment(NameOS.tell(), sizeof(int32_t)); P--;)
  306. NameOS << '\0';
  307. StringRef StringTable = NameOS.str();
  308. if (isBSDLike(Kind))
  309. print32(Out, Kind, StringTable.size()); // byte count of the string table
  310. Out << StringTable;
  311. // If there are no symbols, emit an empty symbol table, to satisfy Solaris
  312. // tools, older versions of which expect a symbol table in a non-empty
  313. // archive, regardless of whether there are any symbols in it.
  314. if (StringTable.size() == 0)
  315. print32(Out, Kind, 0);
  316. // ld64 expects the members to be 8-byte aligned for 64-bit content and at
  317. // least 4-byte aligned for 32-bit content. Opt for the larger encoding
  318. // uniformly.
  319. // We do this for all bsd formats because it simplifies aligning members.
  320. unsigned Alignment = isBSDLike(Kind) ? 8 : 2;
  321. unsigned Pad = OffsetToAlignment(Out.tell(), Alignment);
  322. while (Pad--)
  323. Out.write(uint8_t(0));
  324. // Patch up the size of the symbol table now that we know how big it is.
  325. unsigned Pos = Out.tell();
  326. const unsigned MemberHeaderSize = 60;
  327. Out.seek(HeaderStartOffset + 48); // offset of the size field.
  328. printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10);
  329. // Patch up the number of symbols.
  330. Out.seek(BodyStartOffset);
  331. unsigned NumSyms = MemberOffsetRefs.size();
  332. if (isBSDLike(Kind))
  333. print32(Out, Kind, NumSyms * 8);
  334. else
  335. print32(Out, Kind, NumSyms);
  336. Out.seek(Pos);
  337. return BodyStartOffset + 4;
  338. }
  339. Error llvm::writeArchive(StringRef ArcName,
  340. ArrayRef<NewArchiveMember> NewMembers,
  341. bool WriteSymtab, object::Archive::Kind Kind,
  342. bool Deterministic, bool Thin,
  343. std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
  344. assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
  345. SmallString<128> TmpArchive;
  346. int TmpArchiveFD;
  347. if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",
  348. TmpArchiveFD, TmpArchive))
  349. return errorCodeToError(EC);
  350. ToolOutputFile Output(TmpArchive, TmpArchiveFD);
  351. raw_fd_ostream &Out = Output.os();
  352. if (Thin)
  353. Out << "!<thin>\n";
  354. else
  355. Out << "!<arch>\n";
  356. std::vector<unsigned> MemberOffsetRefs;
  357. unsigned MemberReferenceOffset = 0;
  358. if (WriteSymtab) {
  359. Expected<unsigned> MemberReferenceOffsetOrErr = writeSymbolTable(
  360. Out, Kind, NewMembers, MemberOffsetRefs, Deterministic);
  361. if (auto E = MemberReferenceOffsetOrErr.takeError())
  362. return E;
  363. MemberReferenceOffset = MemberReferenceOffsetOrErr.get();
  364. }
  365. std::vector<unsigned> StringMapIndexes;
  366. if (!isBSDLike(Kind))
  367. writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin);
  368. std::vector<unsigned>::iterator StringMapIndexIter = StringMapIndexes.begin();
  369. std::vector<unsigned> MemberOffset;
  370. for (const NewArchiveMember &M : NewMembers) {
  371. MemoryBufferRef File = M.Buf->getMemBufferRef();
  372. unsigned Padding = 0;
  373. unsigned Pos = Out.tell();
  374. MemberOffset.push_back(Pos);
  375. // ld64 expects the members to be 8-byte aligned for 64-bit content and at
  376. // least 4-byte aligned for 32-bit content. Opt for the larger encoding
  377. // uniformly. This matches the behaviour with cctools and ensures that ld64
  378. // is happy with archives that we generate.
  379. if (Kind == object::Archive::K_DARWIN)
  380. Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8);
  381. printMemberHeader(Out, Kind, Thin, M.MemberName, StringMapIndexIter,
  382. M.ModTime, M.UID, M.GID, M.Perms,
  383. M.Buf->getBufferSize() + Padding);
  384. if (!Thin)
  385. Out << File.getBuffer();
  386. while (Padding--)
  387. Out << '\n';
  388. if (Out.tell() % 2)
  389. Out << '\n';
  390. }
  391. if (MemberReferenceOffset) {
  392. Out.seek(MemberReferenceOffset);
  393. for (unsigned MemberNum : MemberOffsetRefs) {
  394. if (isBSDLike(Kind))
  395. Out.seek(Out.tell() + 4); // skip over the string offset
  396. print32(Out, Kind, MemberOffset[MemberNum]);
  397. }
  398. }
  399. Output.keep();
  400. Out.close();
  401. // At this point, we no longer need whatever backing memory
  402. // was used to generate the NewMembers. On Windows, this buffer
  403. // could be a mapped view of the file we want to replace (if
  404. // we're updating an existing archive, say). In that case, the
  405. // rename would still succeed, but it would leave behind a
  406. // temporary file (actually the original file renamed) because
  407. // a file cannot be deleted while there's a handle open on it,
  408. // only renamed. So by freeing this buffer, this ensures that
  409. // the last open handle on the destination file, if any, is
  410. // closed before we attempt to rename.
  411. OldArchiveBuf.reset();
  412. sys::fs::rename(TmpArchive, ArcName);
  413. return Error::success();
  414. }