Basic support for BSD symbol tables in archives.
authorRafael Espindola <rafael.espindola@gmail.com>
Thu, 9 Jul 2015 15:56:23 +0000 (15:56 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Thu, 9 Jul 2015 15:56:23 +0000 (15:56 +0000)
This could be optimized and for now we only produce __.SYMDEF
and not "__.SYMDEF SORTED".

llvm-svn: 241814

llvm/lib/Object/ArchiveWriter.cpp
llvm/test/Object/archive-symtab.test

index ef8aaaf..c485b34 100644 (file)
@@ -184,10 +184,8 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
                  ArrayRef<NewArchiveIterator> Members,
                  ArrayRef<MemoryBufferRef> Buffers,
                  std::vector<unsigned> &MemberOffsetRefs) {
-  if (Kind != object::Archive::K_GNU)
-    return 0;
-
-  unsigned StartOffset = 0;
+  unsigned HeaderStartOffset = 0;
+  unsigned BodyStartOffset = 0;
   SmallString<128> NameBuf;
   raw_svector_ostream NameOS(NameBuf);
   LLVMContext Context;
@@ -200,10 +198,15 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
       continue;  // FIXME: check only for "not an object file" errors.
     object::SymbolicFile &Obj = *ObjOrErr.get();
 
-    if (!StartOffset) {
-      printGNUSmallMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0);
-      StartOffset = Out.tell();
-      print32(Out, Kind, 0);
+    if (!HeaderStartOffset) {
+      HeaderStartOffset = Out.tell();
+      if (Kind == object::Archive::K_GNU)
+        printGNUSmallMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0);
+      else
+        printBSDMemberHeader(Out, "__.SYMDEF", sys::TimeValue::now(), 0, 0, 0,
+                             0);
+      BodyStartOffset = Out.tell();
+      print32(Out, Kind, 0); // number of entries or bytes
     }
 
     for (const object::BasicSymbolRef &S : Obj.symbols()) {
@@ -214,29 +217,45 @@ writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind,
         continue;
       if (Symflags & object::SymbolRef::SF_Undefined)
         continue;
+
+      unsigned NameOffset = NameOS.tell();
       if (auto EC = S.printName(NameOS))
         return EC;
       NameOS << '\0';
       MemberOffsetRefs.push_back(MemberNum);
-      print32(Out, Kind, 0);
+      if (Kind == object::Archive::K_BSD)
+        print32(Out, Kind, NameOffset);
+      print32(Out, Kind, 0); // member offset
     }
   }
-  Out << NameOS.str();
 
-  if (StartOffset == 0)
+  if (HeaderStartOffset == 0)
     return 0;
 
+  StringRef StringTable = NameOS.str();
+  if (Kind == object::Archive::K_BSD)
+    print32(Out, Kind, StringTable.size()); // byte count of the string table
+  Out << StringTable;
+
   if (Out.tell() % 2)
     Out << '\0';
 
+  // Patch up the size of the symbol table now that we know how big it is.
   unsigned Pos = Out.tell();
-  Out.seek(StartOffset - 12);
-  printWithSpacePadding(Out, Pos - StartOffset, 10);
-  Out.seek(StartOffset);
+  const unsigned MemberHeaderSize = 60;
+  Out.seek(HeaderStartOffset + 48); // offset of the size field.
+  printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10);
+
+  // Patch up the number of symbols.
+  Out.seek(BodyStartOffset);
   unsigned NumSyms = MemberOffsetRefs.size();
-  print32(Out, Kind, NumSyms);
+  if (Kind == object::Archive::K_GNU)
+    print32(Out, Kind, NumSyms);
+  else
+    print32(Out, Kind, NumSyms * 8);
+
   Out.seek(Pos);
-  return StartOffset + 4;
+  return BodyStartOffset + 4;
 }
 
 std::pair<StringRef, std::error_code>
@@ -337,8 +356,11 @@ llvm::writeArchive(StringRef ArcName,
 
   if (MemberReferenceOffset) {
     Out.seek(MemberReferenceOffset);
-    for (unsigned MemberNum : MemberOffsetRefs)
+    for (unsigned MemberNum : MemberOffsetRefs) {
+      if (Kind == object::Archive::K_BSD)
+        Out.seek(Out.tell() + 4); // skip over the string offset
       print32(Out, Kind, MemberOffset[MemberNum]);
+    }
   }
 
   Output.keep();
index 01f17bc..5de2f2b 100644 (file)
@@ -66,3 +66,24 @@ RUN: llvm-nm -M %p/Inputs/macho-archive-unsorted-x86_64.a | FileCheck %s --check
 BSD-MachO: Archive map
 BSD-MachO: _bar in bar.o
 BSD-MachO: _foo in foo.o
+
+RUN: rm -f %t.a
+RUN: llvm-ar --format=bsd rcs %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
+
+MACHO: Archive map
+MACHO-NEXT: _main in trivial-object-test.macho-x86-64
+MACHO-NEXT: _foo in trivial-object-test2.macho-x86-64
+MACHO-NEXT: _main in trivial-object-test2.macho-x86-64
+MACHO-NOT: bar
+
+MACHO: trivial-object-test.macho-x86-64
+MACHO-NEXT: 0000000000000028 s L_.str
+MACHO-NEXT:                  U _SomeOtherFunction
+MACHO-NEXT: 0000000000000000 T _main
+MACHO-NEXT:                  U _puts
+
+MACHO: trivial-object-test2.macho-x86-64
+MACHO-NEXT: 0000000000000000 t _bar
+MACHO-NEXT: 0000000000000001 T _foo
+MACHO-NEXT: 0000000000000002 T _main