Mercurial > hg > CbC > CbC_llvm
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 |