comparison lib/Object/ArchiveWriter.cpp @ 148:63bd29f05246

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