llvm.org GIT mirror llvm / 13f0c80
Don't modify archive members unless really needed. For whatever reason ld64 requires that member headers (not the member themselves) should be aligned. The only way to do that is to edit the previous member so that it ends at an aligned boundary. Since modifying data put in an archive is an undesirable property, llvm-ar should only do it when it is absolutely necessary. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295765 91177308-0d34-0410-b5e6-96231b3b80d8 Rafael Espindola 3 years ago
6 changed file(s) with 80 addition(s) and 29 deletion(s). Raw diff Collapse all Expand all
211211 K_GNU,
212212 K_MIPS64,
213213 K_BSD,
214 K_DARWIN,
214215 K_DARWIN64,
215216 K_COFF
216217 };
121121 }
122122 }
123123
124 static bool isBSDLike(object::Archive::Kind Kind) {
125 switch (Kind) {
126 case object::Archive::K_GNU:
127 return false;
128 case object::Archive::K_BSD:
129 case object::Archive::K_DARWIN:
130 return true;
131 case object::Archive::K_MIPS64:
132 case object::Archive::K_DARWIN64:
133 case object::Archive::K_COFF:
134 llvm_unreachable("not supported for writting");
135 }
136 }
137
124138 static void print32(raw_ostream &Out, object::Archive::Kind Kind,
125139 uint32_t Val) {
126 if (Kind == object::Archive::K_GNU)
140 if (isBSDLike(Kind))
141 support::endian::Writer(Out).write(Val);
142 else
127143 support::endian::Writer(Out).write(Val);
128 else
129 support::endian::Writer(Out).write(Val);
130144 }
131145
132146 static void printRestOfMemberHeader(
177191 std::vector::iterator &StringMapIndexIter,
178192 const sys::TimePoint &ModTime,
179193 unsigned UID, unsigned GID, unsigned Perms, unsigned Size) {
180 if (Kind == object::Archive::K_BSD)
194 if (isBSDLike(Kind))
181195 return printBSDMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
182196 if (!useStringTable(Thin, Name))
183197 return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size);
284298
285299 if (!HeaderStartOffset) {
286300 HeaderStartOffset = Out.tell();
287 if (Kind == object::Archive::K_GNU)
301 if (isBSDLike(Kind))
302 printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0);
303 else
288304 printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0);
289 else
290 printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0);
291305 BodyStartOffset = Out.tell();
292306 print32(Out, Kind, 0); // number of entries or bytes
293307 }
306320 return EC;
307321 NameOS << '\0';
308322 MemberOffsetRefs.push_back(MemberNum);
309 if (Kind == object::Archive::K_BSD)
323 if (isBSDLike(Kind))
310324 print32(Out, Kind, NameOffset);
311325 print32(Out, Kind, 0); // member offset
312326 }
317331
318332 // ld64 prefers the cctools type archive which pads its string table to a
319333 // boundary of sizeof(int32_t).
320 if (Kind == object::Archive::K_BSD)
334 if (isBSDLike(Kind))
321335 for (unsigned P = OffsetToAlignment(NameOS.tell(), sizeof(int32_t)); P--;)
322336 NameOS << '\0';
323337
324338 StringRef StringTable = NameOS.str();
325 if (Kind == object::Archive::K_BSD)
339 if (isBSDLike(Kind))
326340 print32(Out, Kind, StringTable.size()); // byte count of the string table
327341 Out << StringTable;
328342
341355 // Patch up the number of symbols.
342356 Out.seek(BodyStartOffset);
343357 unsigned NumSyms = MemberOffsetRefs.size();
344 if (Kind == object::Archive::K_GNU)
358 if (isBSDLike(Kind))
359 print32(Out, Kind, NumSyms * 8);
360 else
345361 print32(Out, Kind, NumSyms);
346 else
347 print32(Out, Kind, NumSyms * 8);
348362
349363 Out.seek(Pos);
350364 return BodyStartOffset + 4;
356370 bool WriteSymtab, object::Archive::Kind Kind,
357371 bool Deterministic, bool Thin,
358372 std::unique_ptr OldArchiveBuf) {
359 assert((!Thin || Kind == object::Archive::K_GNU) &&
360 "Only the gnu format has a thin mode");
373 assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
361374 SmallString<128> TmpArchive;
362375 int TmpArchiveFD;
363376 if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",
387400 }
388401
389402 std::vector StringMapIndexes;
390 if (Kind != object::Archive::K_BSD)
403 if (!isBSDLike(Kind))
391404 writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin);
392405
393406 std::vector::iterator StringMapIndexIter = StringMapIndexes.begin();
403416 // least 4-byte aligned for 32-bit content. Opt for the larger encoding
404417 // uniformly. This matches the behaviour with cctools and ensures that ld64
405418 // is happy with archives that we generate.
406 if (Kind == object::Archive::K_BSD)
419 if (Kind == object::Archive::K_DARWIN)
407420 Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8);
408421
409422 printMemberHeader(Out, Kind, Thin,
423436 if (MemberReferenceOffset) {
424437 Out.seek(MemberReferenceOffset);
425438 for (unsigned MemberNum : MemberOffsetRefs) {
426 if (Kind == object::Archive::K_BSD)
439 if (isBSDLike(Kind))
427440 Out.seek(Out.tell() + 4); // skip over the string offset
428441 print32(Out, Kind, MemberOffset[MemberNum]);
429442 }
4242 CHECK-GNU: 1465 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc
4343
4444 ; RUN: rm -f %t.a
45 ; RUN: llvm-ar -format bsd rcU %t.a very_long_bytecode_file_name.bc
46 ; RUN: env TZ=GMT llvm-ar tv %t.a | FileCheck %s -check-prefix CHECK-BSD
45 ; RUN: llvm-ar -format darwin rcU %t.a very_long_bytecode_file_name.bc
46 ; RUN: env TZ=GMT llvm-ar tv %t.a | FileCheck %s -check-prefix CHECK-DARWIN
4747
48 CHECK-BSD: 1472 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc
48 CHECK-DARWIN: 1472 2004-11-19 03:01:31.000000000 very_long_bytecode_file_name.bc
4949
5050 RUN: not llvm-ar x %p/Inputs/GNU.a foo.o 2>&1 | FileCheck --check-prefix=NOTFOUND %s
5151 NOTFOUND: foo.o was not found
3131 RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=BSD %s
3232
3333 BSD: !
34 BSD-NEXT: #1/20 0 0 0 644 28 `
34 BSD-NEXT: #1/20 0 0 0 644 24 `
35 BSD-NEXT: 0123456789abcde{{.....}}bar.
36 BSD-SAME: #1/16 0 0 0 644 20 `
37 BSD-NEXT: 0123456789abcdefzed.
38
39 RUN: rm -f %t.a
40 RUN: llvm-ar --format=darwin rc %t.a 0123456789abcde 0123456789abcdef
41 RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=DARWIN %s
42
43 DARWIN: !
44 DARWIN-NEXT: #1/20 0 0 0 644 28 `
3545 Each [[:space:]] matches a newline. We explicitly match 3 newlines, as the
3646 fourth newline is implicitly consumed by FileCheck and cannot be matched.
37 BSD-NEXT: 0123456789abcde{{.....}}bar.{{[[:space:]][[:space:]][[:space:]]}}
38 BSD-NEXT: #1/20 0 0 0 644 28 `
39 BSD-NEXT: 0123456789abcdef{{....}}zed.
47 DARWIN-NEXT: 0123456789abcde{{.....}}bar.{{[[:space:]][[:space:]][[:space:]]}}
48 DARWIN-NEXT: #1/20 0 0 0 644 28 `
49 DARWIN-NEXT: 0123456789abcdef{{....}}zed.
50
4051
4152 RUN: rm -f test.a
4253 RUN: llvm-ar --format=gnu rcT test.a 0123456789abcde 0123456789abcdef
0 Test that only the darwin format needs to modify archive members to
1 avoid a ld64 bug.
2
3 RUN: echo foo > %t.o
4
5 RUN: rm -f %t.a
6 RUN: llvm-ar -format=bsd rc %t.a %t.o
7 RUN: llvm-ar p %t.a > %bsd.o
8 RUN: cmp %bsd.o %t.o
9
10 RUN: rm -f %t.a
11 RUN: llvm-ar -format=gnu rc %t.a %t.o
12 RUN: llvm-ar p %t.a > %gnu.o
13 RUN: cmp %gnu.o %t.o
14
15 RUN: rm -f %t.a
16 RUN: llvm-ar -format=darwin rc %t.a %t.o
17 RUN: llvm-ar p %t.a > %darwin.o
18 RUN: not cmp %darwin.o %t.o
8686 static cl::opt Plugin("plugin", cl::desc("plugin (ignored for compatibility"));
8787
8888 namespace {
89 enum Format { Default, GNU, BSD };
89 enum Format { Default, GNU, BSD, DARWIN };
9090 }
9191
9292 static cl::opt
9393 FormatOpt("format", cl::desc("Archive format to create"),
9494 cl::values(clEnumValN(Default, "default", "default"),
9595 clEnumValN(GNU, "gnu", "gnu"),
96 clEnumValN(DARWIN, "darwin", "darwin"),
9697 clEnumValN(BSD, "bsd", "bsd")));
9798
9899 static std::string Options;
622623 }
623624
624625 static object::Archive::Kind getDefaultForHost() {
625 return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_BSD
626 : object::Archive::K_GNU;
626 return Triple(sys::getProcessTriple()).isOSDarwin()
627 ? object::Archive::K_DARWIN
628 : object::Archive::K_GNU;
627629 }
628630
629631 static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
632634
633635 if (OptionalObject)
634636 return isa(**OptionalObject)
635 ? object::Archive::K_BSD
637 ? object::Archive::K_DARWIN
636638 : object::Archive::K_GNU;
637639
638640 // squelch the error in case we had a non-object file
671673 fail("Only the gnu format has a thin mode");
672674 Kind = object::Archive::K_BSD;
673675 break;
676 case DARWIN:
677 if (Thin)
678 fail("Only the gnu format has a thin mode");
679 Kind = object::Archive::K_DARWIN;
680 break;
674681 }
675682
676683 std::pair Result =