]> granicus.if.org Git - llvm/commitdiff
Add support for Darwin’s static library table of contents with 64-bit offsets to...
authorKevin Enderby <enderby@apple.com>
Fri, 17 Jun 2016 22:16:06 +0000 (22:16 +0000)
committerKevin Enderby <enderby@apple.com>
Fri, 17 Jun 2016 22:16:06 +0000 (22:16 +0000)
Darwin added support in its Xcode 8.0 tools (released in the beta) for static
library table of contents with 64-bit offsets to the archive members.  The
change is very straight forward.  The table of contents member is named
___.SYMDEF_64 or "___.SYMDEF_64 SORTED" and same layout is used but with
fields using 64 bit values instead of 32 bit values.

rdar://26869808

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273058 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/Archive.h
lib/Object/Archive.cpp
test/Object/Inputs/macho-toc64-archive-x86_64.a [new file with mode: 0644]
test/Object/archive-symtab.test

index 585773472303bfeeda9731d2fd903260aff53561..231d56a6b5f75a3a6552bc836fdb08b5229baf77 100644 (file)
@@ -183,6 +183,7 @@ public:
     K_GNU,
     K_MIPS64,
     K_BSD,
+    K_DARWIN64,
     K_COFF
   };
 
@@ -225,7 +226,7 @@ private:
   uint16_t FirstRegularStartOfFile = -1;
   void setFirstRegular(const Child &C);
 
-  unsigned Format : 2;
+  unsigned Format : 3;
   unsigned IsThin : 1;
   mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers;
 };
index 21621c189cf931dfdd9edc1c2d513dbd29907404..15db95123ac3dc7f6d1e24dc708c8ec4a09558b8 100644 (file)
@@ -330,8 +330,11 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec)
   //  seem to create the third member if there's no member whose filename
   //  exceeds 15 characters. So the third member is optional.
 
-  if (Name == "__.SYMDEF") {
-    Format = K_BSD;
+  if (Name == "__.SYMDEF" || Name == "__.SYMDEF_64") {
+    if (Name == "__.SYMDEF")
+      Format = K_BSD;
+    else // Name == "__.SYMDEF_64"
+      Format = K_DARWIN64;
     // We know that the symbol table is not an external file, so we just assert
     // there is no error.
     SymbolTable = *C->getBuffer();
@@ -358,6 +361,14 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec)
       if (Increment())
         return;
     }
+    else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64") {
+      Format = K_DARWIN64;
+      // We know that the symbol table is not an external file, so we just
+      // assert there is no error.
+      SymbolTable = *C->getBuffer();
+      if (Increment())
+        return;
+    }
     setFirstRegular(*C);
     return;
   }
@@ -462,7 +473,7 @@ StringRef Archive::Symbol::getName() const {
 ErrorOr<Archive::Child> Archive::Symbol::getMember() const {
   const char *Buf = Parent->getSymbolTable().begin();
   const char *Offsets = Buf;
-  if (Parent->kind() == K_MIPS64)
+  if (Parent->kind() == K_MIPS64 || Parent->kind() == K_DARWIN64)
     Offsets += sizeof(uint64_t);
   else
     Offsets += sizeof(uint32_t);
@@ -479,6 +490,14 @@ ErrorOr<Archive::Child> Archive::Symbol::getMember() const {
     // the archive of the member that defines the symbol.  Which is what
     // is needed here.
     Offset = read32le(Offsets + SymbolIndex * 8 + 4);
+  } else if (Parent->kind() == K_DARWIN64) {
+    // The SymbolIndex is an index into the ranlib_64 structs that start at
+    // Offsets (the first uint64_t is the number of bytes of the ranlib_64
+    // structs).  The ranlib_64 structs are a pair of uint64_t's the first
+    // being a string table offset and the second being the offset into
+    // the archive of the member that defines the symbol.  Which is what
+    // is needed here.
+    Offset = read64le(Offsets + SymbolIndex * 16 + 8);
   } else {
     // Skip offsets.
     uint32_t MemberCount = read32le(Buf);
@@ -578,6 +597,22 @@ Archive::symbol_iterator Archive::symbol_begin() const {
     // Skip the byte count of the string table.
     buf += sizeof(uint32_t);
     buf += ran_strx;
+  } else if (kind() == K_DARWIN64) {
+    // The __.SYMDEF_64 or "__.SYMDEF_64 SORTED" member starts with a uint64_t
+    // which is the number of bytes of ranlib_64 structs that follow.  The
+    // ranlib_64 structs are a pair of uint64_t's the first being a string
+    // table offset and the second being the offset into the archive of the
+    // member that define the symbol. After that the next uint64_t is the byte
+    // count of the string table followed by the string table.
+    uint64_t ranlib_count = 0;
+    ranlib_count = read64le(buf) / 16;
+    const char *ranlibs = buf + 8;
+    uint64_t ran_strx = 0;
+    ran_strx = read64le(ranlibs);
+    buf += sizeof(uint64_t) + (ranlib_count * (2 * (sizeof(uint64_t))));
+    // Skip the byte count of the string table.
+    buf += sizeof(uint64_t);
+    buf += ran_strx;
   } else {
     uint32_t member_count = 0;
     uint32_t symbol_count = 0;
@@ -604,6 +639,8 @@ uint32_t Archive::getNumberOfSymbols() const {
     return read64be(buf);
   if (kind() == K_BSD)
     return read32le(buf) / 8;
+  if (kind() == K_DARWIN64)
+    return read64le(buf) / 16;
   uint32_t member_count = 0;
   member_count = read32le(buf);
   buf += 4 + (member_count * 4); // Skip offsets.
diff --git a/test/Object/Inputs/macho-toc64-archive-x86_64.a b/test/Object/Inputs/macho-toc64-archive-x86_64.a
new file mode 100644 (file)
index 0000000..e73f3dc
Binary files /dev/null and b/test/Object/Inputs/macho-toc64-archive-x86_64.a differ
index 6bad783a8c82c12ef1acd23d1c05d65293ef0af5..0fcf9adf916c4786e341116d61946307f7c66aac 100644 (file)
@@ -99,6 +99,12 @@ MACHO-NEXT: 0000000000000000 t _bar
 MACHO-NEXT: 0000000000000001 T _foo
 MACHO-NEXT: 0000000000000002 T _main
 
+RUN: llvm-nm -M %p/Inputs/macho-toc64-archive-x86_64.a | FileCheck --check-prefix=MACHO-TOC64 %s
+
+MACHO-TOC64: Archive map
+MACHO-TOC64-NEXT: _test in test.o
+MACHO-TOC64-NEXT: _test in xtest.o
+
 RUN: rm -f %t.a
 RUN: llvm-ar --format=gnu rcsU %t.a %p/Inputs/coff-short-import-code %p/Inputs/coff-short-import-data
 RUN: llvm-nm -M %t.a | FileCheck --check-prefix=COFF-SHORT-IMPORT %s