[llvm] c56b4cf - [llvm-objdump] -T: print symbol versions

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 17 09:10:54 PDT 2021


Author: Fangrui Song
Date: 2021-08-17T09:10:50-07:00
New Revision: c56b4cfd4b2d74ce3b54fe0b1c5fb557b7c60200

URL: https://github.com/llvm/llvm-project/commit/c56b4cfd4b2d74ce3b54fe0b1c5fb557b7c60200
DIFF: https://github.com/llvm/llvm-project/commit/c56b4cfd4b2d74ce3b54fe0b1c5fb557b7c60200.diff

LOG: [llvm-objdump] -T: print symbol versions

Similar to D94907 (llvm-nm -D).

The output will match GNU objdump 2.37.
Older versions don't use ` (version)` for undefined symbols.

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D108097

Added: 
    llvm/test/tools/llvm-objdump/ELF/dynsym-version.test

Modified: 
    llvm/tools/llvm-objdump/llvm-objdump.cpp
    llvm/tools/llvm-objdump/llvm-objdump.h

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-objdump/ELF/dynsym-version.test b/llvm/test/tools/llvm-objdump/ELF/dynsym-version.test
new file mode 100644
index 0000000000000..e21b3544be854
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ELF/dynsym-version.test
@@ -0,0 +1,155 @@
+## Check we print symbol versions, when they are available.
+
+## Test undefined symbols.
+# RUN: yaml2obj %s -o %t-undef.o
+# RUN: llvm-objdump -T %t-undef.o 2>&1 | tr '\t' '|' | FileCheck %s \
+# RUN:   -DFILE=%t-undef.o --check-prefix=UNDEF --match-full-lines --strict-whitespace
+
+## version2sym and version3sym are invalid: undefined symbols cannot refer to .gnu.version_d.
+## We still check their behaviors.
+#      UNDEF:DYNAMIC SYMBOL TABLE:
+# UNDEF-NEXT:0000000000000000      D  *UND*|0000000000000000              localversym
+# UNDEF-NEXT:0000000000000000      D  *UND*|0000000000000000              globalversym
+# UNDEF-NEXT:0000000000000000      D  *UND*|0000000000000000 (v2)         version2sym
+# UNDEF-NEXT:0000000000000000      D  *UND*|0000000000000000 (v3hidden)   version3sym
+# UNDEF-NEXT:0000000000000000      D  *UND*|0000000000000000 (v4)         version4sym
+# UNDEF-NEXT:0000000000000000      D  *UND*|0000000000000000 (v5hidden)   .hidden version5sym
+
+## Test defined symbols.
+# RUN: yaml2obj -DINDEX=0x1 %s -o %t-def.o
+# RUN: llvm-objdump -T %t-def.o 2>&1 | tr '\t' '|' | FileCheck %s \
+# RUN:   -DFILE=%t-def.o --check-prefix=DEF --match-full-lines --strict-whitespace
+
+#      DEF:DYNAMIC SYMBOL TABLE:
+# DEF-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000              localversym
+# DEF-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000              globalversym
+# DEF-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000  v2          version2sym
+# DEF-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000 (v3hidden)   version3sym
+# DEF-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000 (v4)         version4sym
+# DEF-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000 (v5hidden)   .hidden version5sym
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_DYN
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Flags:   [ SHF_ALLOC ]
+## 0x8000 is a special VERSYM_HIDDEN bit.
+    Entries: [ 0, 0, 1, 2, 0x8003, 4, 0x8005 ]
+    ShSize:  [[VERSYMSIZE=<none>]]
+  - Name:         .gnu.version_d
+    Type:         SHT_GNU_verdef
+    Flags:        [ SHF_ALLOC ]
+    Link:         .dynstr
+    AddressAlign: 0x4
+    Info:         0x2
+    ShOffset:     [[VERDEFOFFSET=<none>]]
+    Entries:
+      - VersionNdx: 2
+        Names:
+          - v2
+      - VersionNdx: 3
+        Names:
+          - v3hidden
+  - Name:  .gnu.version_r
+    Type:  SHT_GNU_verneed
+    Flags: [ SHF_ALLOC ]
+    Link:  .dynstr
+    Info:  0x2
+    Dependencies:
+      - Version: 1
+        File:    file1.so
+        Entries:
+          - Name:  v4
+            Hash:  0
+            Flags: 0
+            Other: 4
+      - Version: 1
+        File:    file2.0
+        Entries:
+          - Name:  v5hidden
+            Hash:  0
+            Flags: 0
+            Other: 5
+  - Name:    .dynsym
+    Type:    SHT_DYNSYM
+    EntSize: [[ENTSIZE=<none>]]
+DynamicSymbols:
+  - Name:  localversym
+    Index: [[INDEX=<none>]]
+    Binding: STB_GLOBAL
+  - Name:  globalversym
+    Index: [[INDEX=<none>]]
+    Binding: STB_GLOBAL
+  - Name:  version2sym
+    Index: [[INDEX=<none>]]
+    Binding: STB_GLOBAL
+  - Name:  version3sym
+    Index: [[INDEX=<none>]]
+    Binding: STB_GLOBAL
+  - Name:  version4sym
+    Index: [[INDEX=<none>]]
+    Binding: STB_GLOBAL
+  - Name:  version5sym
+    Index: [[INDEX=<none>]]
+    Other: [ STV_HIDDEN ]
+    Binding: STB_GLOBAL
+
+## Test the output with a long version name.
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-objdump -T %t2 2>&1 | tr '\t' '|' | FileCheck %s \
+# RUN:   --check-prefix=LONGNAME --match-full-lines --strict-whitespace
+
+#      LONGNAME:DYNAMIC SYMBOL TABLE:
+# LONGNAME-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000  v2          sym1
+# LONGNAME-NEXT:0000000000000000 g    D  .gnu.version|0000000000000000  v3withverylongname sym2
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_DYN
+Sections:
+  - Name:    .gnu.version
+    Type:    SHT_GNU_versym
+    Flags:   [ SHF_ALLOC ]
+    Entries: [ 1, 2, 3 ]
+  - Name:         .gnu.version_d
+    Type:         SHT_GNU_verdef
+    Flags:        [ SHF_ALLOC ]
+    Link:         .dynstr
+    AddressAlign: 0x4
+    Info:         0x2
+    Entries:
+      - VersionNdx: 2
+        Names:
+          - v2
+      - VersionNdx: 3
+        Names:
+          - v3withverylongname
+  - Name:    .dynsym
+    Type:    SHT_DYNSYM
+DynamicSymbols:
+  - Name:  sym1
+    Index: 1
+    Binding: STB_GLOBAL
+  - Name:  sym2
+    Index: 1
+    Binding: STB_GLOBAL
+
+## Check we report a warning when we are unable to read a SHT_GNU_versym section entry.
+## In this case, the section has a size that is not a multiple of its sh_entsize.
+
+# RUN: yaml2obj -DVERSYMSIZE=0xff %s -o %t2-broken-versym.o
+# RUN: llvm-objdump -T %t2-broken-versym.o 2>&1 | FileCheck %s --check-prefixes=VERSION-ERR1,NOVER
+
+# VERSION-ERR1:warning: {{.*}}: unable to read an entry with index 1 from SHT_GNU_versym section
+# NOVER-NEXT:0000000000000000      D  *UND*  0000000000000000 localversym
+# NOVER-NEXT:0000000000000000      D  *UND*  0000000000000000 globalversym
+# NOVER-NEXT:0000000000000000      D  *UND*  0000000000000000 version2sym
+# NOVER-NEXT:0000000000000000      D  *UND*  0000000000000000 version3sym
+# NOVER-NEXT:0000000000000000      D  *UND*  0000000000000000 version4sym
+# NOVER-NEXT:0000000000000000      D  *UND*  0000000000000000 .hidden version5sym

diff  --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index a062957cc7430..330597d04f0e5 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -1921,7 +1921,8 @@ void objdump::printSymbolTable(const ObjectFile *O, StringRef ArchiveName,
   if (!DumpDynamic) {
     outs() << "\nSYMBOL TABLE:\n";
     for (auto I = O->symbol_begin(); I != O->symbol_end(); ++I)
-      printSymbol(O, *I, FileName, ArchiveName, ArchitectureName, DumpDynamic);
+      printSymbol(O, *I, {}, FileName, ArchiveName, ArchitectureName,
+                  DumpDynamic);
     return;
   }
 
@@ -1934,12 +1935,21 @@ void objdump::printSymbolTable(const ObjectFile *O, StringRef ArchiveName,
   }
 
   const ELFObjectFileBase *ELF = cast<const ELFObjectFileBase>(O);
-  for (auto I = ELF->getDynamicSymbolIterators().begin();
-       I != ELF->getDynamicSymbolIterators().end(); ++I)
-    printSymbol(O, *I, FileName, ArchiveName, ArchitectureName, DumpDynamic);
+  auto Symbols = ELF->getDynamicSymbolIterators();
+  Expected<std::vector<VersionEntry>> SymbolVersionsOrErr =
+      ELF->readDynsymVersions();
+  if (!SymbolVersionsOrErr) {
+    reportWarning(toString(SymbolVersionsOrErr.takeError()), FileName);
+    SymbolVersionsOrErr = std::vector<VersionEntry>();
+    (void)!SymbolVersionsOrErr;
+  }
+  for (auto &Sym : Symbols)
+    printSymbol(O, Sym, *SymbolVersionsOrErr, FileName, ArchiveName,
+                ArchitectureName, DumpDynamic);
 }
 
 void objdump::printSymbol(const ObjectFile *O, const SymbolRef &Symbol,
+                          ArrayRef<VersionEntry> SymbolVersions,
                           StringRef FileName, StringRef ArchiveName,
                           StringRef ArchitectureName, bool DumpDynamic) {
   const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(O);
@@ -2044,6 +2054,15 @@ void objdump::printSymbol(const ObjectFile *O, const SymbolRef &Symbol,
   }
 
   if (O->isELF()) {
+    if (!SymbolVersions.empty()) {
+      const VersionEntry &Ver =
+          SymbolVersions[Symbol.getRawDataRefImpl().d.b - 1];
+      std::string Str;
+      if (!Ver.Name.empty())
+        Str = Ver.IsVerDef ? ' ' + Ver.Name : '(' + Ver.Name + ')';
+      outs() << ' ' << left_justify(Str, 12);
+    }
+
     uint8_t Other = ELFSymbolRef(Symbol).getOther();
     switch (Other) {
     case ELF::STV_DEFAULT:

diff  --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h
index 3796878558dec..d9fc3bfe66a5d 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -26,6 +26,7 @@ class ELFSectionRef;
 class MachOObjectFile;
 class MachOUniversalBinary;
 class RelocationRef;
+struct VersionEntry;
 } // namespace object
 
 namespace objdump {
@@ -137,6 +138,7 @@ void printSymbolTable(const object::ObjectFile *O, StringRef ArchiveName,
                       StringRef ArchitectureName = StringRef(),
                       bool DumpDynamic = false);
 void printSymbol(const object::ObjectFile *O, const object::SymbolRef &Symbol,
+                 ArrayRef<object::VersionEntry> SymbolVersions,
                  StringRef FileName, StringRef ArchiveName,
                  StringRef ArchitectureName, bool DumpDynamic);
 [[noreturn]] void reportError(StringRef File, const Twine &Message);


        


More information about the llvm-commits mailing list