[llvm] r344183 - llvm-ar: Darwin archive format fixes.

James Y Knight via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 10 14:07:02 PDT 2018


Author: jyknight
Date: Wed Oct 10 14:07:02 2018
New Revision: 344183

URL: http://llvm.org/viewvc/llvm-project?rev=344183&view=rev
Log:
llvm-ar: Darwin archive format fixes.

* Support writing the DARWIN64 symbol table format.

* In darwin archives, emit a symbol table whenever requested, even
  when there are no members, as the apple linker will abort if given
  an archive without a symbol table.

Added tests for same, and also simplified and moved the GNU 64-bit
symbol table test into archive-symtab.test.

Removed:
    llvm/trunk/test/Object/archive-GNU64-write.test
Modified:
    llvm/trunk/lib/Object/ArchiveWriter.cpp
    llvm/trunk/test/Object/archive-format.test
    llvm/trunk/test/Object/archive-symtab.test

Modified: llvm/trunk/lib/Object/ArchiveWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/ArchiveWriter.cpp?rev=344183&r1=344182&r2=344183&view=diff
==============================================================================
--- llvm/trunk/lib/Object/ArchiveWriter.cpp (original)
+++ llvm/trunk/lib/Object/ArchiveWriter.cpp Wed Oct 10 14:07:02 2018
@@ -121,6 +121,11 @@ static void printWithSpacePadding(raw_os
   OS.indent(Size - SizeSoFar);
 }
 
+static bool isDarwin(object::Archive::Kind Kind) {
+  return Kind == object::Archive::K_DARWIN ||
+         Kind == object::Archive::K_DARWIN64;
+}
+
 static bool isBSDLike(object::Archive::Kind Kind) {
   switch (Kind) {
   case object::Archive::K_GNU:
@@ -128,8 +133,8 @@ static bool isBSDLike(object::Archive::K
     return false;
   case object::Archive::K_BSD:
   case object::Archive::K_DARWIN:
-    return true;
   case object::Archive::K_DARWIN64:
+    return true;
   case object::Archive::K_COFF:
     break;
   }
@@ -314,7 +319,9 @@ static void printNBits(raw_ostream &Out,
 static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
                              bool Deterministic, ArrayRef<MemberData> Members,
                              StringRef StringTable) {
-  if (StringTable.empty())
+  // We don't write a symbol table on an archive with no members -- except on
+  // Darwin, where the linker will abort unless the archive has a symbol table.
+  if (StringTable.empty() && !isDarwin(Kind))
     return;
 
   unsigned NumSyms = 0;
@@ -322,15 +329,15 @@ static void writeSymbolTable(raw_ostream
     NumSyms += M.Symbols.size();
 
   unsigned Size = 0;
-  Size += is64BitKind(Kind) ? 8 : 4; // Number of entries
+  unsigned OffsetSize = is64BitKind(Kind) ? sizeof(uint64_t) : sizeof(uint32_t);
+
+  Size += OffsetSize; // Number of entries
   if (isBSDLike(Kind))
-    Size += NumSyms * 8; // Table
-  else if (is64BitKind(Kind))
-    Size += NumSyms * 8; // Table
+    Size += NumSyms * OffsetSize * 2; // Table
   else
-    Size += NumSyms * 4; // Table
+    Size += NumSyms * OffsetSize; // Table
   if (isBSDLike(Kind))
-    Size += 4; // byte count
+    Size += OffsetSize; // byte count
   Size += StringTable.size();
   // ld64 expects the members to be 8-byte aligned for 64-bit content and at
   // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
@@ -340,25 +347,26 @@ static void writeSymbolTable(raw_ostream
   unsigned Pad = OffsetToAlignment(Size, Alignment);
   Size += Pad;
 
-  if (isBSDLike(Kind))
-    printBSDMemberHeader(Out, Out.tell(), "__.SYMDEF", now(Deterministic), 0, 0,
-                         0, Size);
-  else if (is64BitKind(Kind))
-    printGNUSmallMemberHeader(Out, "/SYM64", now(Deterministic), 0, 0, 0, Size);
-  else
-    printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size);
+  if (isBSDLike(Kind)) {
+    const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
+    printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
+                         Size);
+  } else {
+    const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
+    printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
+  }
 
   uint64_t Pos = Out.tell() + Size;
 
   if (isBSDLike(Kind))
-    print<uint32_t>(Out, Kind, NumSyms * 8);
+    printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
   else
     printNBits(Out, Kind, NumSyms);
 
   for (const MemberData &M : Members) {
     for (unsigned StringOffset : M.Symbols) {
       if (isBSDLike(Kind))
-        print<uint32_t>(Out, Kind, StringOffset);
+        printNBits(Out, Kind, StringOffset);
       printNBits(Out, Kind, Pos); // member offset
     }
     Pos += M.Header.size() + M.Data.size() + M.Padding.size();
@@ -366,7 +374,7 @@ static void writeSymbolTable(raw_ostream
 
   if (isBSDLike(Kind))
     // byte count of the string table
-    print<uint32_t>(Out, Kind, StringTable.size());
+    printNBits(Out, Kind, StringTable.size());
   Out << StringTable;
 
   while (Pad--)
@@ -466,9 +474,7 @@ computeMemberData(raw_ostream &StringTab
   // See also the functions that handle the lookup:
   // in lldb: ObjectContainerBSDArchive::Archive::FindObject()
   // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
-  bool UniqueTimestamps =
-      Deterministic && (Kind == object::Archive::K_DARWIN ||
-                        Kind == object::Archive::K_DARWIN64);
+  bool UniqueTimestamps = Deterministic && isDarwin(Kind);
   std::map<StringRef, unsigned> FilenameCount;
   if (UniqueTimestamps) {
     for (const NewArchiveMember &M : NewMembers)
@@ -488,9 +494,8 @@ computeMemberData(raw_ostream &StringTab
     // least 4-byte aligned for 32-bit content.  Opt for the larger encoding
     // uniformly.  This matches the behaviour with cctools and ensures that ld64
     // is happy with archives that we generate.
-    unsigned MemberPadding = Kind == object::Archive::K_DARWIN
-                                 ? OffsetToAlignment(Data.size(), 8)
-                                 : 0;
+    unsigned MemberPadding =
+        isDarwin(Kind) ? OffsetToAlignment(Data.size(), 8) : 0;
     unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2);
     StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
 
@@ -569,8 +574,12 @@ Error llvm::writeArchive(StringRef ArcNa
     // If LastOffset isn't going to fit in a 32-bit varible we need to switch
     // to 64-bit. Note that the file can be larger than 4GB as long as the last
     // member starts before the 4GB offset.
-    if (LastOffset >= (1ULL << Sym64Threshold))
-      Kind = object::Archive::K_GNU64;
+    if (LastOffset >= (1ULL << Sym64Threshold)) {
+      if (Kind == object::Archive::K_DARWIN)
+        Kind = object::Archive::K_DARWIN64;
+      else
+        Kind = object::Archive::K_GNU64;
+    }
   }
 
   Expected<sys::fs::TempFile> Temp =

Removed: llvm/trunk/test/Object/archive-GNU64-write.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/archive-GNU64-write.test?rev=344182&view=auto
==============================================================================
--- llvm/trunk/test/Object/archive-GNU64-write.test (original)
+++ llvm/trunk/test/Object/archive-GNU64-write.test (removed)
@@ -1,40 +0,0 @@
-# REQUIRES: llvm-64-bits
-# REQUIRES: system-linux
-# REQUIRES: shell
-
-# RUN: yaml2obj %s > %t
-# RUN: dd if=%t of=%t bs=1 count=0 seek=1M
-# RUN: rm -f %t.lib
-# RUN: cp %t %t2
-# RUN: SYM64_THRESHOLD=19 llvm-ar cr %t.lib %t %t2 %p/Inputs/trivial-object-test.elf-x86-64
-# RUN: llvm-nm --print-armap %t.lib | FileCheck %s
-# RUN: grep SYM64 %t.lib
-
-# Delete temp files. They are too large.
-# RUN: rm -f %t %t2 %t.lib
-
-!ELF
-FileHeader:
-  Class:           ELFCLASS64
-  Data:            ELFDATA2LSB
-  Type:            ET_EXEC
-  Machine:         EM_X86_64
-Sections:
-  - Name:            .data
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC ]
-    AddressAlign:    0x0000000000000001
-    Content:         "00"
-    Size:            32
-
-# CHECK:      Archive map
-# CHECK-NEXT: main in trivial-object-test.elf-x86-64
-
-# CHECK:    archive-GNU64-write.test.tmp:
-
-# CHECK:    archive-GNU64-write.test.tmp2:
-
-# CHECK:    trivial-object-test.elf-x86-64:
-# CHECK-NEXT:                     U SomeOtherFunction
-# CHECK-NEXT:    0000000000000000 T main
-# CHECK-NEXT:                     U puts

Modified: llvm/trunk/test/Object/archive-format.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/archive-format.test?rev=344183&r1=344182&r2=344183&view=diff
==============================================================================
--- llvm/trunk/test/Object/archive-format.test (original)
+++ llvm/trunk/test/Object/archive-format.test Wed Oct 10 14:07:02 2018
@@ -38,7 +38,7 @@ BSD-SAME: #1/16           0           0
 BSD-NEXT: 0123456789abcdefzed.
 
 RUN: rm -f %t.a
-RUN: llvm-ar --format=darwin rc %t.a 0123456789abcde 0123456789abcdef
+RUN: llvm-ar --format=darwin rcS %t.a 0123456789abcde 0123456789abcdef
 RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=DARWIN %s
 
 DARWIN:      !<arch>

Modified: llvm/trunk/test/Object/archive-symtab.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/archive-symtab.test?rev=344183&r1=344182&r2=344183&view=diff
==============================================================================
--- llvm/trunk/test/Object/archive-symtab.test (original)
+++ llvm/trunk/test/Object/archive-symtab.test Wed Oct 10 14:07:02 2018
@@ -2,6 +2,11 @@ RUN: rm -f %t.a
 RUN: llvm-ar rcsU %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64
 RUN: llvm-nm -M %t.a | FileCheck %s
 
+RUN: rm -f %t.a
+RUN: env SYM64_THRESHOLD=1 llvm-ar rcsU %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64
+RUN: llvm-nm -M %t.a | FileCheck %s
+RUXX: grep SYM64 %t.a
+
 CHECK: Archive map
 CHECK-NEXT: main in trivial-object-test.elf-x86-64
 CHECK-NEXT: foo in trivial-object-test2.elf-x86-64
@@ -82,6 +87,11 @@ RUN: rm -f %t.a
 RUN: llvm-ar --format=bsd rcsU %t.a %p/Inputs/trivial-object-test.macho-x86-64 %p/Inputs/trivial-object-test2.macho-x86-64
 RUN: llvm-nm -M %t.a | FileCheck --check-prefix=MACHO %s
 
+RUN: rm -f %t.a
+RUN: env SYM64_THRESHOLD=1 llvm-ar --format=darwin rcsU %t.a %p/Inputs/trivial-object-test.macho-x86-64 %p/Inputs/trivial-object-test2.macho-x86-64
+RUN: llvm-nm -M %t.a | FileCheck --check-prefix=MACHO %s
+RUN: grep '__\.SYMDEF_64' %t.a
+
 MACHO: Archive map
 MACHO-NEXT: _main in trivial-object-test.macho-x86-64
 MACHO-NEXT: _foo in trivial-object-test2.macho-x86-64
@@ -138,3 +148,21 @@ RUN: llvm-ar --format=gnu rcsD %t.a %p/I
 RUN: FileCheck --check-prefix=GNU-SYMTAB-ALIGN %s < %t.a
 GNU-SYMTAB-ALIGN: !<arch>
 GNU-SYMTAB-ALIGN-NEXT: /               0           0     0     0       14        `
+
+
+** Test the behavior of an empty archive:
+
+No symbol table emitted for GNU archives
+RUN: rm -f %t.a
+RUN: llvm-ar rcs --format=gnu %t.a
+RUN: not grep -q '/               ' %t.a
+
+No symbol table for BSD archives
+RUN: rm -f %t.a
+RUN: llvm-ar rcs --format=bsd %t.a
+RUN: not grep -q '__\.SYMDEF' %t.a
+
+And we do emit a symbol table for DARWIN archives
+RUN: rm -f %t.a
+RUN: llvm-ar rcs --format=darwin %t.a
+RUN: grep -q '__\.SYMDEF' %t.a




More information about the llvm-commits mailing list