[llvm-branch-commits] [llvm] 141906f - [llvm-readelf/obj] - Add support of multiple SHT_SYMTAB_SHNDX sections.

Georgii Rymar via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jan 13 00:42:00 PST 2021


Author: Georgii Rymar
Date: 2021-01-13T11:36:43+03:00
New Revision: 141906fa149ffaa37bb5b65e9890ab1f0f3effd5

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

LOG: [llvm-readelf/obj] - Add support of multiple SHT_SYMTAB_SHNDX sections.

Currently we don't support multiple SHT_SYMTAB_SHNDX sections
and the DT_SYMTAB_SHNDX tag currently.

This patch implements it and fixes the
https://bugs.llvm.org/show_bug.cgi?id=43991.

I had to introduce the `struct DataRegion` to ELF.h,
it is used to represent a region that might have no known size.
It is needed, because we don't know the size of the extended
section indices table when it is located via DT_SYMTAB_SHNDX.
In this case we still want to validate that we don't read
past the end of the file.

Differential revision: https://reviews.llvm.org/D92923

Added: 
    llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test

Modified: 
    llvm/include/llvm/Object/ELF.h
    llvm/test/Object/invalid.test
    llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
    llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
    llvm/test/tools/llvm-readobj/ELF/mips-got.test
    llvm/test/tools/llvm-readobj/ELF/mips-plt.test
    llvm/test/tools/llvm-readobj/ELF/section-symbols.test
    llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
    llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
    llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
    llvm/tools/llvm-readobj/ELFDumper.cpp
    llvm/unittests/Object/ELFTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index bd224ada7783..86359ff44d56 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -57,6 +57,36 @@ enum PPCInstrMasks : uint64_t {
 
 template <class ELFT> class ELFFile;
 
+template <class T> struct DataRegion {
+  // This constructor is used when we know the start and the size of a data
+  // region. We assume that Arr does not go past the end of the file.
+  DataRegion(ArrayRef<T> Arr) : First(Arr.data()), Size(Arr.size()) {}
+
+  // Sometimes we only know the start of a data region. We still don't want to
+  // read past the end of the file, so we provide the end of a buffer.
+  DataRegion(const T *Data, const uint8_t *BufferEnd)
+      : First(Data), BufEnd(BufferEnd) {}
+
+  Expected<T> operator[](uint64_t N) {
+    assert(Size || BufEnd);
+    if (Size) {
+      if (N >= *Size)
+        return createError(
+            "the index is greater than or equal to the number of entries (" +
+            Twine(*Size) + ")");
+    } else {
+      const uint8_t *EntryStart = (const uint8_t *)First + N * sizeof(T);
+      if (EntryStart + sizeof(T) > BufEnd)
+        return createError("can't read past the end of the file");
+    }
+    return *(First + N);
+  }
+
+  const T *First;
+  Optional<uint64_t> Size = None;
+  const uint8_t *BufEnd = nullptr;
+};
+
 template <class ELFT>
 std::string getSecIndexForError(const ELFFile<ELFT> &Obj,
                                 const typename ELFT::Shdr &Sec) {
@@ -99,6 +129,7 @@ class ELFFile {
   using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>;
 
   const uint8_t *base() const { return Buf.bytes_begin(); }
+  const uint8_t *end() const { return base() + getBufSize(); }
 
   size_t getBufSize() const { return Buf.size(); }
 
@@ -274,13 +305,13 @@ class ELFFile {
       Elf_Shdr_Range Sections,
       WarningHandler WarnHandler = &defaultWarningHandler) const;
   Expected<uint32_t> getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
-                                     ArrayRef<Elf_Word> ShndxTable) const;
+                                     DataRegion<Elf_Word> ShndxTable) const;
   Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym,
                                         const Elf_Shdr *SymTab,
-                                        ArrayRef<Elf_Word> ShndxTable) const;
+                                        DataRegion<Elf_Word> ShndxTable) const;
   Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym,
                                         Elf_Sym_Range Symtab,
-                                        ArrayRef<Elf_Word> ShndxTable) const;
+                                        DataRegion<Elf_Word> ShndxTable) const;
   Expected<const Elf_Shdr *> getSection(uint32_t Index) const;
 
   Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec,
@@ -313,22 +344,25 @@ getSection(typename ELFT::ShdrRange Sections, uint32_t Index) {
 template <class ELFT>
 inline Expected<uint32_t>
 getExtendedSymbolTableIndex(const typename ELFT::Sym &Sym, unsigned SymIndex,
-                            ArrayRef<typename ELFT::Word> ShndxTable) {
+                            DataRegion<typename ELFT::Word> ShndxTable) {
   assert(Sym.st_shndx == ELF::SHN_XINDEX);
-  if (SymIndex >= ShndxTable.size())
+  if (!ShndxTable.First)
     return createError(
-        "extended symbol index (" + Twine(SymIndex) +
-        ") is past the end of the SHT_SYMTAB_SHNDX section of size " +
-        Twine(ShndxTable.size()));
+        "found an extended symbol index (" + Twine(SymIndex) +
+        "), but unable to locate the extended symbol index table");
 
-  // The size of the table was checked in getSHNDXTable.
-  return ShndxTable[SymIndex];
+  Expected<typename ELFT::Word> TableOrErr = ShndxTable[SymIndex];
+  if (!TableOrErr)
+    return createError("unable to read an extended symbol table at index " +
+                       Twine(SymIndex) + ": " +
+                       toString(TableOrErr.takeError()));
+  return *TableOrErr;
 }
 
 template <class ELFT>
 Expected<uint32_t>
 ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
-                               ArrayRef<Elf_Word> ShndxTable) const {
+                               DataRegion<Elf_Word> ShndxTable) const {
   uint32_t Index = Sym.st_shndx;
   if (Index == ELF::SHN_XINDEX) {
     Expected<uint32_t> ErrorOrIndex =
@@ -345,7 +379,7 @@ ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
 template <class ELFT>
 Expected<const typename ELFT::Shdr *>
 ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab,
-                          ArrayRef<Elf_Word> ShndxTable) const {
+                          DataRegion<Elf_Word> ShndxTable) const {
   auto SymsOrErr = symbols(SymTab);
   if (!SymsOrErr)
     return SymsOrErr.takeError();
@@ -355,7 +389,7 @@ ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab,
 template <class ELFT>
 Expected<const typename ELFT::Shdr *>
 ELFFile<ELFT>::getSection(const Elf_Sym &Sym, Elf_Sym_Range Symbols,
-                          ArrayRef<Elf_Word> ShndxTable) const {
+                          DataRegion<Elf_Word> ShndxTable) const {
   auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable);
   if (!IndexOrErr)
     return IndexOrErr.takeError();

diff  --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test
index 95b677fae293..89bb4b5c5a62 100644
--- a/llvm/test/Object/invalid.test
+++ b/llvm/test/Object/invalid.test
@@ -244,7 +244,7 @@ Symbols: []
 # RUN: llvm-readobj --symbols %p/Inputs/invalid-ext-symtab-index.elf-x86-64 2>&1 | \
 # RUN:   FileCheck -DFILE=%p/Inputs/invalid-ext-symtab-index.elf-x86-64 --check-prefix=INVALID-EXT-SYMTAB-INDEX %s
 
-# INVALID-EXT-SYMTAB-INDEX: warning: '[[FILE]]': extended symbol index (0) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# INVALID-EXT-SYMTAB-INDEX: warning: '[[FILE]]': found an extended symbol index (0), but unable to locate the extended symbol index table
 # INVALID-EXT-SYMTAB-INDEX: Section: Reserved (0xFFFF)
 
 ## Check that llvm-readobj reports an error if a relocation section

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
index 4b4a4bed4c8b..d8ad0200316e 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
@@ -364,14 +364,14 @@ DynamicSymbols:
 
 # VERSIONED-SEC-SYM-XINDEX-LLVM:       Name: (0)
 # VERSIONED-SEC-SYM-XINDEX-LLVM:       Name: foo (12)
-# VERSIONED-SEC-SYM-XINDEX-LLVM:      warning: '[[FILE]]': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# VERSIONED-SEC-SYM-XINDEX-LLVM:      warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
 # VERSIONED-SEC-SYM-XINDEX-LLVM-NEXT: Symbol {
 # VERSIONED-SEC-SYM-XINDEX-LLVM-NEXT:  Name: <?> (0)
 # VERSIONED-SEC-SYM-XINDEX-LLVM:       Name: <?> (0)
 
 # VERSIONED-SEC-SYM-XINDEX-GNU:      Symbol table '.dynsym' contains 4 entries:
 # VERSIONED-SEC-SYM-XINDEX-GNU:         Num: {{.*}} Ndx Name
-# VERSIONED-SEC-SYM-XINDEX-GNU:      warning: '[[FILE]]': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# VERSIONED-SEC-SYM-XINDEX-GNU:      warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
 # VERSIONED-SEC-SYM-XINDEX-GNU-NEXT:      2: {{.*}} RSV[0xffff] <?>
 
 ## Case 8: Check what we print when:

diff  --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
index 49ea8631a4ba..b83007912914 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
@@ -487,6 +487,7 @@ Sections:
 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': DT_SYMENT value of 0x987 is not the size of a symbol (0x18)
 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_REL: invalid e_phentsize: 1
 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_JMPREL: invalid e_phentsize: 1
+# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_SYMTAB_SHNDX: invalid e_phentsize: 1
 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_RELR: invalid e_phentsize: 1
 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_ANDROID_RELR: invalid e_phentsize: 1
 # PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_GNU_HASH: invalid e_phentsize: 1

diff  --git a/llvm/test/tools/llvm-readobj/ELF/mips-got.test b/llvm/test/tools/llvm-readobj/ELF/mips-got.test
index 01bff1b914f8..6e6d80834a08 100644
--- a/llvm/test/tools/llvm-readobj/ELF/mips-got.test
+++ b/llvm/test/tools/llvm-readobj/ELF/mips-got.test
@@ -558,7 +558,7 @@ DynamicSymbols:
 # SEC-SYMS-LLVM-NEXT:   }
 # SEC-SYMS-LLVM-NEXT: Entry {
 # SEC-SYMS-LLVM:          Type: Section (0x3)
-# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
 # SEC-SYMS-LLVM-NEXT:     Section: Reserved (0xFFFF)
 # SEC-SYMS-LLVM-NEXT:     Name: <?> (0)
 # SEC-SYMS-LLVM-NEXT:   }
@@ -571,7 +571,7 @@ DynamicSymbols:
 # SEC-SYMS-GNU-NEXT:  {{.*}}   1 .got
 # SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': unable to get section index for symbol with st_shndx = 0xfff2 (SHN_COMMON)
 # SEC-SYMS-GNU-NEXT:  {{.*}} COM <?>
-# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
 # SEC-SYMS-GNU-NEXT:  {{.*}} RSV[0xffff] <?>
 
 --- !ELF

diff  --git a/llvm/test/tools/llvm-readobj/ELF/mips-plt.test b/llvm/test/tools/llvm-readobj/ELF/mips-plt.test
index 607388cb852b..90c826346f49 100644
--- a/llvm/test/tools/llvm-readobj/ELF/mips-plt.test
+++ b/llvm/test/tools/llvm-readobj/ELF/mips-plt.test
@@ -189,7 +189,7 @@ DynamicSymbols: []
 # SEC-SYMS-LLVM-NEXT:     }
 # SEC-SYMS-LLVM-NEXT:     Entry {
 # SEC-SYMS-LLVM:            Type: Section (0x3)
-# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
 # SEC-SYMS-LLVM-NEXT:       Section: Reserved (0xFFFF)
 # SEC-SYMS-LLVM-NEXT:       Name: <?> (0)
 # SEC-SYMS-LLVM-NEXT:     }
@@ -204,7 +204,7 @@ DynamicSymbols: []
 # SEC-SYMS-GNU-NEXT:   0000000000002018 {{.*}}   2 .got.plt
 # SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': unable to get section index for symbol with st_shndx = 0xfff2 (SHN_COMMON)
 # SEC-SYMS-GNU-NEXT:   0000000000002020 {{.*}} COM <?>
-# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
 # SEC-SYMS-GNU-NEXT:   0000000000002028 {{.*}} RSV[0xffff] <?>
 
 --- !ELF

diff  --git a/llvm/test/tools/llvm-readobj/ELF/section-symbols.test b/llvm/test/tools/llvm-readobj/ELF/section-symbols.test
index 61f5991dafcd..1e40746b7303 100644
--- a/llvm/test/tools/llvm-readobj/ELF/section-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/section-symbols.test
@@ -150,7 +150,7 @@ Symbols:
 # GNU2-NEXT:      0: {{.*}} NOTYPE  {{.*}} UND {{$}}
 # GNU2-NEXT:      1: {{.*}} SECTION {{.*}} RSV[0xffff] <?>
 
-# WARN2: warning: '{{.*}}.tmp2': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# WARN2: warning: '{{.*}}.tmp2': found an extended symbol index (1), but unable to locate the extended symbol index table
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
index 62085b6c1883..97caf60207ff 100644
--- a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
+++ b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
@@ -241,8 +241,8 @@ Symbols:
 # GNU3-NEXT:     1: {{.*}} RSV[0xffff] no_shndx
 # GNU3-NEXT:     2: {{.*}} RSV[0xffff] no_shndx2
 
-# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
-# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': found an extended symbol index (1), but unable to locate the extended symbol index table
+# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': found an extended symbol index (2), but unable to locate the extended symbol index table
 
 --- !ELF
 FileHeader:
@@ -267,7 +267,7 @@ Symbols:
 #  SHNDX-ERR-GNU-NEXT: Symbol table '.symtab' contains 2 entries:
 #  SHNDX-ERR-GNU-NEXT:    Num:    Value          Size Type    Bind   Vis       Ndx Name
 #  SHNDX-ERR-GNU-NEXT:      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   UND
-#  SHNDX-ERR-GNU-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+#  SHNDX-ERR-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
 #  SHNDX-ERR-GNU-NEXT:      1: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   RSV[0xffff]
 # SHNDX-ERR-GNU-EMPTY:
 #   SHNDX-ERR-GNU-NOT:{{.}}
@@ -294,7 +294,7 @@ Symbols:
 # SHNDX-ERR-LLVM-NEXT:     Binding: Local (0x0)
 # SHNDX-ERR-LLVM-NEXT:     Type: None (0x0)
 # SHNDX-ERR-LLVM-NEXT:     Other: 0
-# SHNDX-ERR-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# SHNDX-ERR-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
 # SHNDX-ERR-LLVM-NEXT:     Section: Reserved (0xFFFF)
 # SHNDX-ERR-LLVM-NEXT:   }
 # SHNDX-ERR-LLVM-NEXT: ]

diff  --git a/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test
new file mode 100644
index 000000000000..7ee9c2c0296a
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test
@@ -0,0 +1,331 @@
+## In this file we have tests for the SHT_SYMTAB_SHNDX section
+## and the DT_SYMTAB_SHNDX dynamic tag.
+
+## Check that 
diff erent SHT_SYMTAB_SHNDX sections can be used with 
diff erent symbol tables.
+## In this test we check that we print 
diff erent section indexes for regular and dynamic
+## symbol tables that are linked to 
diff erent SHT_SYMTAB_SHNDX sections.
+
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-readelf --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=GNU
+# RUN: llvm-readobj --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=LLVM
+
+# GNU:      Symbol table '.dynsym' contains 3 entries:
+# GNU-NEXT:    Num:    Value  Size Type    Bind   Vis       Ndx Name
+# GNU-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT   UND
+# GNU-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT     3 dynsym1
+# GNU-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT     2 dynsym2
+# GNU:      Symbol table '.symtab' contains 3 entries:
+# GNU-NEXT:    Num:    Value  Size Type    Bind   Vis       Ndx Name
+# GNU-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT   UND
+# GNU-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT     2 sym1
+# GNU-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT     1 sym2
+
+# LLVM:      Symbols [
+# LLVM-NEXT:   Symbol {
+# LLVM-NEXT:     Name:  (0)
+# LLVM:          Section: Undefined (0x0)
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Symbol {
+# LLVM-NEXT:     Name: sym1 (6)
+# LLVM:          Section: .section2 (0x2)
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Symbol {
+# LLVM-NEXT:     Name: sym2 (1)
+# LLVM:          Section: .section1 (0x1)
+# LLVM-NEXT:   }
+# LLVM-NEXT: ]
+# LLVM:      DynamicSymbols [
+# LLVM-NEXT:   Symbol {
+# LLVM-NEXT:     Name:  (0)
+# LLVM:          Section: Undefined (0x0)
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Symbol {
+# LLVM-NEXT:     Name: dynsym1 (9)
+# LLVM:          Section: .section3 (0x3)
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Symbol {
+# LLVM-NEXT:     Name: dynsym2 (1)
+# LLVM:          Section: .section2 (0x2)
+# LLVM-NEXT:   }
+# LLVM-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS32
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+  - Name: .section1
+    Type: SHT_PROGBITS
+  - Name: .section2
+    Type: SHT_PROGBITS
+  - Name: .section3
+    Type: SHT_PROGBITS
+  - Name:    .dynamic
+    Type:    SHT_DYNAMIC
+    Flags:   [ SHF_ALLOC ]
+    Address: 0x1000
+    Offset:  0x1000
+    Entries:
+      - Tag:   [[TAGNAME=DT_SYMTAB_SHNDX]]
+        Value: [[SYMTABSHNDX=0x2100]] ## Address of .bar section.
+      - Tag:   DT_NULL
+        Value: 0
+## By naming the SHT_SYMTAB_SHNDX sections to .foo and .bar we verify that we
+## don't use their names to locate them.
+  - Name:    .foo
+    Type:    SHT_SYMTAB_SHNDX
+    Flags:   [ SHF_ALLOC ]
+    Link:    [[SHNDXLINK=.symtab]]
+    Entries: [ 0, 2, 1 ]
+    Offset:  0x2000
+    Address: 0x2000
+  - Name:    .bar
+    Type:    SHT_SYMTAB_SHNDX
+    Flags:   [ SHF_ALLOC ]
+    Link:    .dynsym
+    Entries: [ 0, 3, 2 ]
+    Offset:  0x2100
+    Address: 0x2100
+Symbols:
+  - Name:  sym1
+    Index: SHN_XINDEX
+  - Name:  sym2
+    Index: SHN_XINDEX
+DynamicSymbols:
+  - Name:  dynsym1
+    Index: SHN_XINDEX
+  - Name:  dynsym2
+    Index: SHN_XINDEX
+ProgramHeaders:
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .bar
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+
+## Check that we locate the SHT_SYMTAB_SHNDX section using the DT_SYMTAB_SHNDX
+## dynamic tag when dumping dynamic symbols. In this case we make the value of
+## DT_SYMTAB_SHNDX point to the SHT_SYMTAB_SHNDX section that is
+## linked with the static symbol table and check that we use it.
+
+# RUN: yaml2obj --docnum=1 -DSYMTABSHNDX=0x2000 %s -o %t2
+# RUN: llvm-readelf --dyn-syms %t2 2>&1 | FileCheck %s --check-prefix=DYNTAG-GNU
+# RUN: llvm-readobj --dyn-syms %t2 2>&1 | FileCheck %s --check-prefix=DYNTAG-LLVM
+
+# DYNTAG-GNU:      Symbol table '.dynsym' contains 3 entries:
+# DYNTAG-GNU-NEXT:    Num:    Value  Size Type    Bind   Vis     Ndx Name
+# DYNTAG-GNU-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT UND
+# DYNTAG-GNU-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT   2 dynsym1
+# DYNTAG-GNU-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT   1 dynsym2
+
+# DYNTAG-LLVM:          Name: dynsym1 (9)
+# DYNTAG-LLVM:          Section: .section2 (0x2)
+# DYNTAG-LLVM-NEXT:   }
+# DYNTAG-LLVM-NEXT:   Symbol {
+# DYNTAG-LLVM-NEXT:     Name: dynsym2 (1)
+# DYNTAG-LLVM:          Section: .section1 (0x1)
+# DYNTAG-LLVM-NEXT:   }
+# DYNTAG-LLVM-NEXT: ]
+
+## Check that we report a warning when we dump a dynamic symbol table that
+## contains symbols with extended indices, but we don't have a DT_SYMTAB_SHNDX tag to locate
+## the corresponding extended indexes table.
+
+# RUN: yaml2obj --docnum=1 -DTAGNAME=0x0 -DSYMTABSHNDX=0x0 %s -o %t3
+# RUN: llvm-readelf --symbols --dyn-syms %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=NOTAG-GNU
+# RUN: llvm-readobj --symbols --dyn-syms %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=NOTAG-LLVM
+
+# NOTAG-GNU:      Symbol table '.dynsym' contains 3 entries:
+# NOTAG-GNU-NEXT:    Num:    Value  Size Type    Bind   Vis       Ndx Name
+# NOTAG-GNU-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT   UND
+# NOTAG-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
+# NOTAG-GNU-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT   RSV[0xffff] dynsym1
+# NOTAG-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
+# NOTAG-GNU-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT   RSV[0xffff] dynsym2
+
+# NOTAG-LLVM:      Symbol {
+# NOTAG-LLVM:          Name: dynsym1 (9)
+# NOTAG-LLVM-NEXT:     Value: 0x0
+# NOTAG-LLVM-NEXT:     Size: 0
+# NOTAG-LLVM-NEXT:     Binding: Local (0x0)
+# NOTAG-LLVM-NEXT:     Type: None (0x0)
+# NOTAG-LLVM-NEXT:     Other: 0
+# NOTAG-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
+# NOTAG-LLVM-NEXT:     Section: Reserved (0xFFFF)
+# NOTAG-LLVM-NEXT:   }
+# NOTAG-LLVM-NEXT:   Symbol {
+# NOTAG-LLVM-NEXT:     Name: dynsym2 (1)
+# NOTAG-LLVM-NEXT:     Value: 0x0
+# NOTAG-LLVM-NEXT:     Size: 0
+# NOTAG-LLVM-NEXT:     Binding: Local (0x0)
+# NOTAG-LLVM-NEXT:     Type: None (0x0)
+# NOTAG-LLVM-NEXT:     Other: 0
+# NOTAG-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
+# NOTAG-LLVM-NEXT:     Section: Reserved (0xFFFF)
+# NOTAG-LLVM-NEXT:   }
+
+## In this case we have a SHT_SYMTAB_SHNDX section with a sh_link field that has a
+## value that is larger than the number of sections. Check we report a warning.
+
+# RUN: yaml2obj --docnum=1 -DSHNDXLINK=0xFF %s -o %t4
+# RUN: llvm-readelf --symbols --dyn-syms %t4 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t4 --check-prefixes=BROKENLINK,BROKENLINK-GNU --implicit-check-not=warning:
+# RUN: llvm-readobj --symbols --dyn-syms %t4 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t4 --check-prefixes=BROKENLINK,BROKENLINK-LLVM --implicit-check-not=warning:
+
+# BROKENLINK: warning: '[[FILE]]': unable to get the associated symbol table for SHT_SYMTAB_SHNDX section with index 5: sh_link (255) is greater than or equal to the total number of sections (12)
+
+# BROKENLINK-GNU:      warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
+# BROKENLINK-GNU-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT   RSV[0xffff] sym1
+# BROKENLINK-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
+# BROKENLINK-GNU-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT   RSV[0xffff] sym2
+
+# BROKENLINK-LLVM:      Symbol {
+# BROKENLINK-LLVM:        Name: sym1 (6)
+# BROKENLINK-LLVM:      warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
+# BROKENLINK-LLVM-NEXT:   Section: Reserved (0xFFFF)
+# BROKENLINK-LLVM-NEXT: }
+# BROKENLINK-LLVM-NEXT: Symbol {
+# BROKENLINK-LLVM-NEXT:   Name: sym2 (1)
+# BROKENLINK-LLVM:      warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
+# BROKENLINK-LLVM-NEXT:   Section: Reserved (0xFFFF)
+# BROKENLINK-LLVM-NEXT: }
+
+## Check we report a warning when multiple SHT_SYMTAB_SHNDX sections are linked to a symbol table.
+## In this case, 2 sections are linked to the dynamic symbol table. Check it doesn't affect
+## anything, because the SHT_SYMTAB_SHNDX section specified by the DT_SYMTAB_SHNDX tag is still used.
+
+# RUN: yaml2obj --docnum=1 -DSHNDXLINK=.dynsym %s -o %t.multiple
+# RUN: llvm-readelf --symbols --dyn-syms %t.multiple 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.multiple --check-prefix=MULTIPLE-GNU
+# RUN: llvm-readobj --symbols --dyn-syms %t.multiple 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.multiple --check-prefix=MULTIPLE-LLVM
+
+# MULTIPLE-GNU:      warning: '[[FILE]]': multiple SHT_SYMTAB_SHNDX sections are linked to SHT_SYMTAB_SHNDX section with index 6
+# MULTIPLE-GNU:      Symbol table '.dynsym' contains 3 entries:
+# MULTIPLE-GNU-NEXT:    Num:    Value  Size Type    Bind   Vis     Ndx Name
+# MULTIPLE-GNU-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT UND
+# MULTIPLE-GNU-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT   3 dynsym1
+# MULTIPLE-GNU-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT   2 dynsym2
+
+# MULTIPLE-LLVM:      Symbol {
+# MULTIPLE-LLVM:        Name: dynsym1 (9)
+# MULTIPLE-LLVM-NEXT:   Value: 0x0
+# MULTIPLE-LLVM-NEXT:   Size: 0
+# MULTIPLE-LLVM-NEXT:   Binding: Local (0x0)
+# MULTIPLE-LLVM-NEXT:   Type: None (0x0)
+# MULTIPLE-LLVM-NEXT:   Other: 0
+# MULTIPLE-LLVM-NEXT:   Section: .section3 (0x3)
+# MULTIPLE-LLVM-NEXT: }
+# MULTIPLE-LLVM-NEXT: Symbol {
+# MULTIPLE-LLVM-NEXT:   Name: dynsym2 (1)
+# MULTIPLE-LLVM-NEXT:   Value: 0x0
+# MULTIPLE-LLVM-NEXT:   Size: 0
+# MULTIPLE-LLVM-NEXT:   Binding: Local (0x0)
+# MULTIPLE-LLVM-NEXT:   Type: None (0x0)
+# MULTIPLE-LLVM-NEXT:   Other: 0
+# MULTIPLE-LLVM-NEXT:   Section: .section2 (0x2)
+# MULTIPLE-LLVM-NEXT: }
+
+## In this case we have a SHT_SYMTAB_SHNDX section placed right before
+## the end of the file. This table is broken: it contains fewer entries than
+## the number of dynamic symbols.
+## Check we report a warning when trying to read an extended symbol index past
+## the end of the file.
+
+# RUN: yaml2obj --docnum=2 %s -o %t.pastend
+# RUN: llvm-readelf --dyn-syms %t.pastend 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.pastend --check-prefix=PASTEND-GNU --implicit-check-not=warning:
+# RUN: llvm-readobj --dyn-syms %t.pastend 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.pastend --check-prefix=PASTEND-LLVM --implicit-check-not=warning:
+
+# PASTEND-GNU:      1: 00000000 0 NOTYPE  LOCAL  DEFAULT 1 dynsym1
+# PASTEND-GNU-NEXT: warning: '[[FILE]]': unable to read an extended symbol table at index 2: can't read past the end of the file
+# PASTEND-GNU-NEXT: 2: 00000000 0 NOTYPE  LOCAL  DEFAULT RSV[0xffff] dynsym2
+
+# PASTEND-LLVM:      Symbol {
+# PASTEND-LLVM:       Name: dynsym2 (1)
+# PASTEND-LLVM-NEXT:  Value: 0x0
+# PASTEND-LLVM-NEXT:  Size: 0
+# PASTEND-LLVM-NEXT:  Binding: Local (0x0)
+# PASTEND-LLVM-NEXT:  Type: None (0x0)
+# PASTEND-LLVM-NEXT:  Other: 0
+# PASTEND-LLVM-NEXT: warning: '[[FILE]]': unable to read an extended symbol table at index 2: can't read past the end of the file
+# PASTEND-LLVM-NEXT:  Section: Reserved (0xFFFF)
+# PASTEND-LLVM-NEXT: }
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS32
+  Data:  ELFDATA2LSB
+  Type:  ET_REL
+Sections:
+  - Name: .section1
+    Type: SHT_PROGBITS
+  - Name: .section2
+    Type: SHT_PROGBITS
+  - Name:    .dynamic
+    Type:    SHT_DYNAMIC
+    Flags:   [ SHF_ALLOC ]
+    Address: 0x1000
+    Offset:  0x1000
+    Entries:
+      - Tag:   DT_SYMTAB
+        Value: 0x1500
+      - Tag:   DT_HASH
+        Value: 0x1600
+      - Tag:   DT_STRTAB
+        Value: 0x1700
+      - Tag:   DT_STRSZ
+        Value: 17 ## ".dynsym1.dynsym2."
+      - Tag:   DT_SYMTAB_SHNDX
+        Value: 0x2000
+      - Tag:   DT_NULL
+        Value: 0
+  - Name:    .dynsym
+    Type:    SHT_DYNSYM
+    Flags:   [ SHF_ALLOC ]
+    Offset:  0x1500
+    Address: 0x1500
+## We need the .hash table to infer the number
+## of dynamic symbols.
+  - Name:    .hash
+    Type:    SHT_HASH
+    Flags:   [ SHF_ALLOC ]
+    Offset:  0x1600
+    Address: 0x1600
+    Bucket:  [ 1 ]
+    Chain:   [ 1, 2, 3 ]
+  - Name:    .dynstr
+    Type:    SHT_STRTAB
+    Flags:   [ SHF_ALLOC ]
+    Offset:  0x1700
+    Address: 0x1700
+  - Name: .strtab
+    Type: SHT_STRTAB
+  - Name:    .symtab_shndx
+    Type:    SHT_SYMTAB_SHNDX
+    Flags:   [ SHF_ALLOC ]
+    Entries: [ 0, 1 ]
+    Offset:  0x2000
+    Address: 0x2000
+DynamicSymbols:
+  - Name:  dynsym1
+    Index: SHN_XINDEX
+  - Name:  dynsym2
+    Index: SHN_XINDEX
+ProgramHeaders:
+  - Type:     PT_LOAD
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .symtab_shndx
+  - Type:     PT_DYNAMIC
+    VAddr:    0x1000
+    FirstSec: .dynamic
+    LastSec:  .dynamic
+SectionHeaderTable:
+  NoHeaders: true

diff  --git a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
index 1c1e95e5bacb..12fba6c13714 100644
--- a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
@@ -51,7 +51,7 @@ Symbols:
 # RUN: yaml2obj --docnum=2 %s -o %t2
 # RUN: not obj2yaml %t2 2>&1 | FileCheck %s -DFILE=%t2 --check-prefix=CASE2
 
-# CASE2: Error reading file: [[FILE]]: extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# CASE2: Error reading file: [[FILE]]: found an extended symbol index (1), but unable to locate the extended symbol index table
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
index ec754de0e40a..3780fba5dd2e 100644
--- a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
@@ -5,7 +5,7 @@
 # RUN: yaml2obj --docnum=1 %s -o %t1
 # RUN: llvm-readobj --symbols 2>&1 %t1 | FileCheck -DFILE=%t1 %s --check-prefix=CASE1
 
-# CASE1: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
+# CASE1: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
 
 --- !ELF
 FileHeader:

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 5e27a14d0475..e03a3d1edc7e 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -314,6 +314,7 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset,
                                   bool NonVisibilityBitsUsed) const {};
   virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
+                           DataRegion<Elf_Word> ShndxTable,
                            Optional<StringRef> StrTable, bool IsDynamic,
                            bool NonVisibilityBitsUsed) const = 0;
 
@@ -321,9 +322,9 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
   virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
 
-  Expected<ArrayRef<Elf_Versym>> getVersionTable(const Elf_Shdr &Sec,
-                                                 ArrayRef<Elf_Sym> *SymTab,
-                                                 StringRef *StrTab) const;
+  Expected<ArrayRef<Elf_Versym>>
+  getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
+                  StringRef *StrTab, const Elf_Shdr **SymTabSec) const;
   StringRef getPrintableSectionName(const Elf_Shdr &Sec) const;
 
   std::vector<GroupSection> getGroups();
@@ -372,6 +373,7 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   DynRegionInfo DynRelrRegion;
   DynRegionInfo DynPLTRelRegion;
   Optional<DynRegionInfo> DynSymRegion;
+  DynRegionInfo DynSymTabShndxRegion;
   DynRegionInfo DynamicTable;
   StringRef DynamicStringTable;
   const Elf_Hash *HashTable = nullptr;
@@ -380,7 +382,7 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   const Elf_Shdr *DotDynsymSec = nullptr;
   const Elf_Shdr *DotCGProfileSec = nullptr;
   const Elf_Shdr *DotAddrsigSec = nullptr;
-  ArrayRef<Elf_Word> ShndxTable;
+  DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables;
   Optional<uint64_t> SONameOffset;
 
   const Elf_Shdr *SymbolVersionSection = nullptr;   // .gnu.version
@@ -394,10 +396,12 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   mutable SmallVector<Optional<VersionEntry>, 16> VersionMap;
 
   std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex,
+                                DataRegion<Elf_Word> ShndxTable,
                                 Optional<StringRef> StrTable,
                                 bool IsDynamic) const;
-  Expected<unsigned> getSymbolSectionIndex(const Elf_Sym &Symbol,
-                                           unsigned SymIndex) const;
+  Expected<unsigned>
+  getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex,
+                        DataRegion<Elf_Word> ShndxTable) const;
   Expected<StringRef> getSymbolSectionName(const Elf_Sym &Symbol,
                                            unsigned SectionIndex) const;
   std::string getStaticSymbolName(uint32_t Index) const;
@@ -415,6 +419,8 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
 
   Expected<RelSymbol<ELFT>> getRelocationTarget(const Relocation<ELFT> &R,
                                                 const Elf_Shdr *SymTab) const;
+
+  ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const;
 };
 
 template <class ELFT>
@@ -432,9 +438,11 @@ std::string ELFDumper<ELFT>::describe(const Elf_Shdr &Sec) const {
   return ::describe(Obj, Sec);
 }
 
+namespace {
+
 template <class ELFT>
-static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> &Obj,
-                                           const typename ELFT::Shdr &Sec) {
+Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> &Obj,
+                                    const typename ELFT::Shdr &Sec) {
   Expected<const typename ELFT::Shdr *> StrTabSecOrErr =
       Obj.getSection(Sec.sh_link);
   if (!StrTabSecOrErr)
@@ -448,11 +456,18 @@ static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> &Obj,
   return *StrTabOrErr;
 }
 
-// Returns the linked symbol table and associated string table for a given section.
+template <class ELFT> struct SymtabLink {
+  typename ELFT::SymRange Symbols;
+  StringRef StringTable;
+  const typename ELFT::Shdr *SymTab;
+};
+
+// Returns the linked symbol table, symbols and associated string table for a
+// given section.
 template <class ELFT>
-static Expected<std::pair<typename ELFT::SymRange, StringRef>>
-getLinkAsSymtab(const ELFFile<ELFT> &Obj, const typename ELFT::Shdr &Sec,
-                unsigned ExpectedType) {
+Expected<SymtabLink<ELFT>> getLinkAsSymtab(const ELFFile<ELFT> &Obj,
+                                           const typename ELFT::Shdr &Sec,
+                                           unsigned ExpectedType) {
   Expected<const typename ELFT::Shdr *> SymtabOrErr =
       Obj.getSection(Sec.sh_link);
   if (!SymtabOrErr)
@@ -478,14 +493,17 @@ getLinkAsSymtab(const ELFFile<ELFT> &Obj, const typename ELFT::Shdr &Sec,
     return createError("unable to read symbols from the " + describe(Obj, Sec) +
                        ": " + toString(SymsOrErr.takeError()));
 
-  return std::make_pair(*SymsOrErr, *StrTabOrErr);
+  return SymtabLink<ELFT>{*SymsOrErr, *StrTabOrErr, *SymtabOrErr};
 }
 
+} // namespace
+
 template <class ELFT>
 Expected<ArrayRef<typename ELFT::Versym>>
 ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
-                                 StringRef *StrTab) const {
-  assert((!SymTab && !StrTab) || (SymTab && StrTab));
+                                 StringRef *StrTab,
+                                 const Elf_Shdr **SymTabSec) const {
+  assert((!SymTab && !StrTab && !SymTabSec) || (SymTab && StrTab && SymTabSec));
   if (reinterpret_cast<uintptr_t>(Obj.base() + Sec.sh_offset) %
           sizeof(uint16_t) !=
       0)
@@ -497,23 +515,26 @@ ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
     return createError("cannot read content of " + describe(Sec) + ": " +
                        toString(VersionsOrErr.takeError()));
 
-  Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr =
+  Expected<SymtabLink<ELFT>> SymTabOrErr =
       getLinkAsSymtab(Obj, Sec, SHT_DYNSYM);
   if (!SymTabOrErr) {
     reportUniqueWarning(SymTabOrErr.takeError());
     return *VersionsOrErr;
   }
 
-  if (SymTabOrErr->first.size() != VersionsOrErr->size())
+  if (SymTabOrErr->Symbols.size() != VersionsOrErr->size())
     reportUniqueWarning(describe(Sec) + ": the number of entries (" +
                         Twine(VersionsOrErr->size()) +
                         ") does not match the number of symbols (" +
-                        Twine(SymTabOrErr->first.size()) +
+                        Twine(SymTabOrErr->Symbols.size()) +
                         ") in the symbol table with index " +
                         Twine(Sec.sh_link));
 
-  if (SymTab)
-    std::tie(*SymTab, *StrTab) = *SymTabOrErr;
+  if (SymTab) {
+    *SymTab = SymTabOrErr->Symbols;
+    *StrTab = SymTabOrErr->StringTable;
+    *SymTabSec = SymTabOrErr->SymTab;
+  }
   return *VersionsOrErr;
 }
 
@@ -720,9 +741,15 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
   bool NonVisibilityBitsUsed =
       llvm::any_of(Syms, [](const Elf_Sym &S) { return S.st_other & ~0x3; });
 
+  DataRegion<Elf_Word> ShndxTable =
+      IsDynamic ? DataRegion<Elf_Word>(
+                      (const Elf_Word *)this->DynSymTabShndxRegion.Addr,
+                      this->getElfObject().getELFFile().end())
+                : DataRegion<Elf_Word>(this->getShndxTable(SymtabSec));
+
   printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed);
   for (const Elf_Sym &Sym : Syms)
-    printSymbol(Sym, &Sym - Syms.begin(), StrTable, IsDynamic,
+    printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, IsDynamic,
                 NonVisibilityBitsUsed);
 }
 
@@ -819,18 +846,20 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
     return OS;
   }
   void printHashedSymbol(const Elf_Sym *Sym, unsigned SymIndex,
-                         StringRef StrTable, uint32_t Bucket);
+                         DataRegion<Elf_Word> ShndxTable, StringRef StrTable,
+                         uint32_t Bucket);
   void printRelrReloc(const Elf_Relr &R) override;
   void printRelRelaReloc(const Relocation<ELFT> &R,
                          const RelSymbol<ELFT> &RelSym) override;
   void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
+                   DataRegion<Elf_Word> ShndxTable,
                    Optional<StringRef> StrTable, bool IsDynamic,
                    bool NonVisibilityBitsUsed) const override;
   void printDynamicRelocHeader(unsigned Type, StringRef Name,
                                const DynRegionInfo &Reg) override;
 
-  std::string getSymbolSectionNdx(const Elf_Sym &Symbol,
-                                  unsigned SymIndex) const;
+  std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex,
+                                  DataRegion<Elf_Word> ShndxTable) const;
   void printProgramHeaders() override;
   void printSectionMapping() override;
   void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec,
@@ -875,8 +904,10 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
   void printRelRelaReloc(const Relocation<ELFT> &R,
                          const RelSymbol<ELFT> &RelSym) override;
 
-  void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex) const;
+  void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex,
+                          DataRegion<Elf_Word> ShndxTable) const;
   void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
+                   DataRegion<Elf_Word> ShndxTable,
                    Optional<StringRef> StrTable, bool IsDynamic,
                    bool /*NonVisibilityBitsUsed*/) const override;
   void printProgramHeaders() override;
@@ -1011,11 +1042,23 @@ ELFDumper<ELFT>::getRelocationTarget(const Relocation<ELFT> &R,
 
   const Elf_Sym *FirstSym =
       cantFail(Obj.template getEntry<Elf_Sym>(*SymTab, 0));
-  std::string SymbolName = getFullSymbolName(
-      *Sym, Sym - FirstSym, *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM);
+  std::string SymbolName =
+      getFullSymbolName(*Sym, Sym - FirstSym, getShndxTable(SymTab),
+                        *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM);
   return RelSymbol<ELFT>(Sym, SymbolName);
 }
 
+template <typename ELFT>
+ArrayRef<typename ELFT::Word>
+ELFDumper<ELFT>::getShndxTable(const Elf_Shdr *Symtab) const {
+  if (Symtab) {
+    auto It = ShndxTables.find(Symtab);
+    if (It != ShndxTables.end())
+      return It->second;
+  }
+  return {};
+}
+
 static std::string maybeDemangle(StringRef Name) {
   return opts::Demangle ? demangle(std::string(Name)) : Name.str();
 }
@@ -1073,6 +1116,7 @@ ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex,
 template <typename ELFT>
 std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
                                                unsigned SymIndex,
+                                               DataRegion<Elf_Word> ShndxTable,
                                                Optional<StringRef> StrTable,
                                                bool IsDynamic) const {
   if (!StrTable)
@@ -1087,7 +1131,8 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
   }
 
   if (SymbolName.empty() && Symbol.getType() == ELF::STT_SECTION) {
-    Expected<unsigned> SectionIndex = getSymbolSectionIndex(Symbol, SymIndex);
+    Expected<unsigned> SectionIndex =
+        getSymbolSectionIndex(Symbol, SymIndex, ShndxTable);
     if (!SectionIndex) {
       reportUniqueWarning(SectionIndex.takeError());
       return "<?>";
@@ -1119,8 +1164,8 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
 
 template <typename ELFT>
 Expected<unsigned>
-ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym &Symbol,
-                                       unsigned SymIndex) const {
+ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex,
+                                       DataRegion<Elf_Word> ShndxTable) const {
   unsigned Ndx = Symbol.st_shndx;
   if (Ndx == SHN_XINDEX)
     return object::getExtendedSymbolTableIndex<ELFT>(Symbol, SymIndex,
@@ -1900,7 +1945,8 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
     : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()),
       FileName(O.getFileName()), DynRelRegion(O, *this),
       DynRelaRegion(O, *this), DynRelrRegion(O, *this),
-      DynPLTRelRegion(O, *this), DynamicTable(O, *this) {
+      DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this),
+      DynamicTable(O, *this) {
   if (!O.IsContentValid())
     return;
 
@@ -1934,12 +1980,29 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
         }
       }
       break;
-    case ELF::SHT_SYMTAB_SHNDX:
-      if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = Obj.getSHNDXTable(Sec))
-        ShndxTable = *ShndxTableOrErr;
-      else
-        this->reportUniqueWarning(ShndxTableOrErr.takeError());
+    case ELF::SHT_SYMTAB_SHNDX: {
+      uint32_t SymtabNdx = Sec.sh_link;
+      if (SymtabNdx >= Sections.size()) {
+        reportUniqueWarning(
+            "unable to get the associated symbol table for " + describe(Sec) +
+            ": sh_link (" + Twine(SymtabNdx) +
+            ") is greater than or equal to the total number of sections (" +
+            Twine(Sections.size()) + ")");
+        continue;
+      }
+
+      if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr =
+              Obj.getSHNDXTable(Sec)) {
+        if (!ShndxTables.insert({&Sections[SymtabNdx], *ShndxTableOrErr})
+                 .second)
+          reportUniqueWarning(
+              "multiple SHT_SYMTAB_SHNDX sections are linked to " +
+              describe(Sec));
+      } else {
+        reportUniqueWarning(ShndxTableOrErr.takeError());
+      }
       break;
+    }
     case ELF::SHT_GNU_versym:
       if (!SymbolVersionSection)
         SymbolVersionSection = &Sec;
@@ -2081,6 +2144,10 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {
       DynPLTRelRegion.Size = Dyn.getVal();
       DynPLTRelRegion.SizePrintName = "DT_PLTRELSZ value";
       break;
+    case ELF::DT_SYMTAB_SHNDX:
+      DynSymTabShndxRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
+      DynSymTabShndxRegion.EntSize = sizeof(Elf_Word);
+      break;
     }
   }
 
@@ -3781,8 +3848,10 @@ void GNUELFDumper<ELFT>::printSymtabMessage(const Elf_Shdr *Symtab,
 }
 
 template <class ELFT>
-std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
-                                                    unsigned SymIndex) const {
+std::string
+GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
+                                        unsigned SymIndex,
+                                        DataRegion<Elf_Word> ShndxTable) const {
   unsigned SectionIndex = Symbol.st_shndx;
   switch (SectionIndex) {
   case ELF::SHN_UNDEF:
@@ -3792,8 +3861,8 @@ std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
   case ELF::SHN_COMMON:
     return "COM";
   case ELF::SHN_XINDEX: {
-    Expected<uint32_t> IndexOrErr = object::getExtendedSymbolTableIndex<ELFT>(
-        Symbol, SymIndex, this->ShndxTable);
+    Expected<uint32_t> IndexOrErr =
+        object::getExtendedSymbolTableIndex<ELFT>(Symbol, SymIndex, ShndxTable);
     if (!IndexOrErr) {
       assert(Symbol.st_shndx == SHN_XINDEX &&
              "getExtendedSymbolTableIndex should only fail due to an invalid "
@@ -3825,6 +3894,7 @@ std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
 
 template <class ELFT>
 void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
+                                     DataRegion<Elf_Word> ShndxTable,
                                      Optional<StringRef> StrTable,
                                      bool IsDynamic,
                                      bool NonVisibilityBitsUsed) const {
@@ -3865,10 +3935,10 @@ void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
   }
 
   Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0;
-  Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex);
+  Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex, ShndxTable);
 
-  Fields[7].Str =
-      this->getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic);
+  Fields[7].Str = this->getFullSymbolName(Symbol, SymIndex, ShndxTable,
+                                          StrTable, IsDynamic);
   for (const Field &Entry : Fields)
     printField(Entry);
   OS << "\n";
@@ -3877,6 +3947,7 @@ void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
 template <class ELFT>
 void GNUELFDumper<ELFT>::printHashedSymbol(const Elf_Sym *Symbol,
                                            unsigned SymIndex,
+                                           DataRegion<Elf_Word> ShndxTable,
                                            StringRef StrTable,
                                            uint32_t Bucket) {
   unsigned Bias = ELFT::Is64Bits ? 8 : 0;
@@ -3900,8 +3971,9 @@ void GNUELFDumper<ELFT>::printHashedSymbol(const Elf_Sym *Symbol,
       printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
   Fields[6].Str =
       printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities));
-  Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex);
-  Fields[8].Str = this->getFullSymbolName(*Symbol, SymIndex, StrTable, true);
+  Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex, ShndxTable);
+  Fields[8].Str =
+      this->getFullSymbolName(*Symbol, SymIndex, ShndxTable, StrTable, true);
 
   for (const Field &Entry : Fields)
     printField(Entry);
@@ -3940,6 +4012,8 @@ void GNUELFDumper<ELFT>::printHashTableSymbols(const Elf_Hash &SysVHash) {
     return;
   }
 
+  DataRegion<Elf_Word> ShndxTable(
+      (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
   auto Buckets = SysVHash.buckets();
   auto Chains = SysVHash.chains();
   for (uint32_t Buc = 0; Buc < SysVHash.nbucket; Buc++) {
@@ -3957,7 +4031,8 @@ void GNUELFDumper<ELFT>::printHashTableSymbols(const Elf_Hash &SysVHash) {
         break;
       }
 
-      printHashedSymbol(FirstSym + Ch, Ch, this->DynamicStringTable, Buc);
+      printHashedSymbol(FirstSym + Ch, Ch, ShndxTable, this->DynamicStringTable,
+                        Buc);
       Visited[Ch] = true;
     }
   }
@@ -4001,6 +4076,8 @@ void GNUELFDumper<ELFT>::printGnuHashTableSymbols(const Elf_GnuHash &GnuHash) {
   else
     Values = *ValuesOrErr;
 
+  DataRegion<Elf_Word> ShndxTable(
+      (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
   ArrayRef<Elf_Word> Buckets = GnuHash.buckets();
   for (uint32_t Buc = 0; Buc < GnuHash.nbuckets; Buc++) {
     if (Buckets[Buc] == ELF::STN_UNDEF)
@@ -4010,7 +4087,8 @@ void GNUELFDumper<ELFT>::printGnuHashTableSymbols(const Elf_GnuHash &GnuHash) {
     while (true) {
       uint32_t SymIndex = Index++;
       if (const Elf_Sym *Sym = GetSymbol(SymIndex, DynSyms.size()))
-        printHashedSymbol(Sym, SymIndex, this->DynamicStringTable, Buc);
+        printHashedSymbol(Sym, SymIndex, ShndxTable, this->DynamicStringTable,
+                          Buc);
       else
         break;
 
@@ -4549,7 +4627,7 @@ void GNUELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
                                Sec->sh_size / sizeof(Elf_Versym));
   Expected<ArrayRef<Elf_Versym>> VerTableOrErr =
       this->getVersionTable(*Sec, /*SymTab=*/nullptr,
-                            /*StrTab=*/nullptr);
+                            /*StrTab=*/nullptr, /*SymTabSec=*/nullptr);
   if (!VerTableOrErr) {
     this->reportUniqueWarning(VerTableOrErr.takeError());
     return;
@@ -5667,7 +5745,8 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
         // means "any section".
         if (FunctionSec) {
           if (Expected<const Elf_Shdr *> SecOrErr =
-                  Obj.getSection(Sym, this->DotSymtabSec, this->ShndxTable)) {
+                  Obj.getSection(Sym, this->DotSymtabSec,
+                                 this->getShndxTable(this->DotSymtabSec))) {
             if (*FunctionSec != *SecOrErr)
               continue;
           } else {
@@ -5742,7 +5821,7 @@ void ELFDumper<ELFT>::printStackSize(const Relocation<ELFT> &R,
   uint64_t RelocSymValue = 0;
   if (Sym) {
     Expected<const Elf_Shdr *> SectionOrErr =
-        this->Obj.getSection(*Sym, SymTab, this->ShndxTable);
+        this->Obj.getSection(*Sym, SymTab, this->getShndxTable(SymTab));
     if (!SectionOrErr) {
       reportUniqueWarning(
           "cannot identify the section for relocation symbol '" +
@@ -5966,11 +6045,14 @@ void GNUELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
          << " Type    Ndx Name\n";
     else
       OS << "   Address     Access  Initial Sym.Val. Type    Ndx Name\n";
+
+    DataRegion<Elf_Word> ShndxTable(
+        (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
     for (auto &E : Parser.getGlobalEntries()) {
       const Elf_Sym &Sym = *Parser.getGotSym(&E);
       const Elf_Sym &FirstSym = this->dynamic_symbols()[0];
       std::string SymName = this->getFullSymbolName(
-          Sym, &Sym - &FirstSym, this->DynamicStringTable, false);
+          Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false);
 
       OS.PadToColumn(2);
       OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias));
@@ -5983,7 +6065,8 @@ void GNUELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
       OS.PadToColumn(40 + 3 * Bias);
       OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes));
       OS.PadToColumn(48 + 3 * Bias);
-      OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin());
+      OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(),
+                                ShndxTable);
       OS.PadToColumn(52 + 3 * Bias);
       OS << SymName << "\n";
     }
@@ -6018,12 +6101,14 @@ void GNUELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
     OS << "\n";
     OS << " Entries:\n";
     OS << "   Address  Initial Sym.Val. Type    Ndx Name\n";
+    DataRegion<Elf_Word> ShndxTable(
+        (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
     for (auto &E : Parser.getPltEntries()) {
       const Elf_Sym &Sym = *Parser.getPltSym(&E);
       const Elf_Sym &FirstSym = *cantFail(
           this->Obj.template getEntry<Elf_Sym>(*Parser.getPltSymTable(), 0));
       std::string SymName = this->getFullSymbolName(
-          Sym, &Sym - &FirstSym, this->DynamicStringTable, false);
+          Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false);
 
       OS.PadToColumn(2);
       OS << to_string(format_hex_no_prefix(Parser.getPltAddress(&E), 8 + Bias));
@@ -6034,7 +6119,8 @@ void GNUELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
       OS.PadToColumn(29 + 3 * Bias);
       OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes));
       OS.PadToColumn(37 + 3 * Bias);
-      OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin());
+      OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(),
+                                ShndxTable);
       OS.PadToColumn(41 + 3 * Bias);
       OS << SymName << "\n";
     }
@@ -6276,15 +6362,17 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printSectionHeaders() {
         StringRef StrTable = unwrapOrError(
             this->FileName,
             this->Obj.getStringTableForSymtab(*this->DotSymtabSec));
+        ArrayRef<Elf_Word> ShndxTable = this->getShndxTable(this->DotSymtabSec);
 
         typename ELFT::SymRange Symbols = unwrapOrError(
             this->FileName, this->Obj.symbols(this->DotSymtabSec));
         for (const Elf_Sym &Sym : Symbols) {
           const Elf_Shdr *SymSec = unwrapOrError(
               this->FileName,
-              this->Obj.getSection(Sym, this->DotSymtabSec, this->ShndxTable));
+              this->Obj.getSection(Sym, this->DotSymtabSec, ShndxTable));
           if (SymSec == &Sec)
-            printSymbol(Sym, &Sym - &Symbols[0], StrTable, false, false);
+            printSymbol(Sym, &Sym - &Symbols[0], ShndxTable, StrTable, false,
+                        false);
         }
       }
     }
@@ -6300,8 +6388,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printSectionHeaders() {
 }
 
 template <class ELFT>
-void LLVMELFDumper<ELFT>::printSymbolSection(const Elf_Sym &Symbol,
-                                             unsigned SymIndex) const {
+void LLVMELFDumper<ELFT>::printSymbolSection(
+    const Elf_Sym &Symbol, unsigned SymIndex,
+    DataRegion<Elf_Word> ShndxTable) const {
   auto GetSectionSpecialType = [&]() -> Optional<StringRef> {
     if (Symbol.isUndefined())
       return StringRef("Undefined");
@@ -6324,7 +6413,7 @@ void LLVMELFDumper<ELFT>::printSymbolSection(const Elf_Sym &Symbol,
   }
 
   Expected<unsigned> SectionIndex =
-      this->getSymbolSectionIndex(Symbol, SymIndex);
+      this->getSymbolSectionIndex(Symbol, SymIndex, ShndxTable);
   if (!SectionIndex) {
     assert(Symbol.st_shndx == SHN_XINDEX &&
            "getSymbolSectionIndex should only fail due to an invalid "
@@ -6351,11 +6440,12 @@ void LLVMELFDumper<ELFT>::printSymbolSection(const Elf_Sym &Symbol,
 
 template <class ELFT>
 void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
+                                      DataRegion<Elf_Word> ShndxTable,
                                       Optional<StringRef> StrTable,
                                       bool IsDynamic,
                                       bool /*NonVisibilityBitsUsed*/) const {
-  std::string FullSymbolName =
-      this->getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic);
+  std::string FullSymbolName = this->getFullSymbolName(
+      Symbol, SymIndex, ShndxTable, StrTable, IsDynamic);
   unsigned char SymbolType = Symbol.getType();
 
   DictScope D(W, "Symbol");
@@ -6394,7 +6484,7 @@ void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
     }
     W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u);
   }
-  printSymbolSection(Symbol, SymIndex);
+  printSymbolSection(Symbol, SymIndex, ShndxTable);
 }
 
 template <class ELFT>
@@ -6488,8 +6578,9 @@ void LLVMELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
 
   StringRef StrTable;
   ArrayRef<Elf_Sym> Syms;
+  const Elf_Shdr *SymTabSec;
   Expected<ArrayRef<Elf_Versym>> VerTableOrErr =
-      this->getVersionTable(*Sec, &Syms, &StrTable);
+      this->getVersionTable(*Sec, &Syms, &StrTable, &SymTabSec);
   if (!VerTableOrErr) {
     this->reportUniqueWarning(VerTableOrErr.takeError());
     return;
@@ -6498,11 +6589,13 @@ void LLVMELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
   if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size())
     return;
 
+  ArrayRef<Elf_Word> ShNdxTable = this->getShndxTable(SymTabSec);
   for (size_t I = 0, E = Syms.size(); I < E; ++I) {
     DictScope S(W, "Symbol");
     W.printNumber("Version", (*VerTableOrErr)[I].vs_index & VERSYM_VERSION);
-    W.printString("Name", this->getFullSymbolName(Syms[I], I, StrTable,
-                                                           /*IsDynamic=*/true));
+    W.printString("Name",
+                  this->getFullSymbolName(Syms[I], I, ShNdxTable, StrTable,
+                                          /*IsDynamic=*/true));
   }
 }
 
@@ -6830,10 +6923,12 @@ void LLVMELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
       W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes));
 
       const unsigned SymIndex = &Sym - this->dynamic_symbols().begin();
-      printSymbolSection(Sym, SymIndex);
+      DataRegion<Elf_Word> ShndxTable(
+          (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
+      printSymbolSection(Sym, SymIndex, ShndxTable);
 
       std::string SymName = this->getFullSymbolName(
-          Sym, SymIndex, this->DynamicStringTable, true);
+          Sym, SymIndex, ShndxTable, this->DynamicStringTable, true);
       W.printNumber("Name", SymName, Sym.st_name);
     }
   }
@@ -6867,6 +6962,8 @@ void LLVMELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
   }
   {
     ListScope LS(W, "Entries");
+    DataRegion<Elf_Word> ShndxTable(
+        (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
     for (auto &E : Parser.getPltEntries()) {
       DictScope D(W, "Entry");
       PrintEntry(&E);
@@ -6874,12 +6971,13 @@ void LLVMELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
       const Elf_Sym &Sym = *Parser.getPltSym(&E);
       W.printHex("Value", Sym.st_value);
       W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes));
-      printSymbolSection(Sym, &Sym - this->dynamic_symbols().begin());
+      printSymbolSection(Sym, &Sym - this->dynamic_symbols().begin(),
+                         ShndxTable);
 
       const Elf_Sym *FirstSym = cantFail(
           this->Obj.template getEntry<Elf_Sym>(*Parser.getPltSymTable(), 0));
       std::string SymName = this->getFullSymbolName(
-          Sym, &Sym - FirstSym, Parser.getPltStrTable(), true);
+          Sym, &Sym - FirstSym, ShndxTable, Parser.getPltStrTable(), true);
       W.printNumber("Name", SymName, Sym.st_name);
     }
   }

diff  --git a/llvm/unittests/Object/ELFTest.cpp b/llvm/unittests/Object/ELFTest.cpp
index b815d5cdd839..f85e866deeb5 100644
--- a/llvm/unittests/Object/ELFTest.cpp
+++ b/llvm/unittests/Object/ELFTest.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Object/ELF.h"
+#include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -54,3 +55,35 @@ TEST(ELFTest, getELFRelocationTypeNameForVE) {
 TEST(ELFTest, getELFRelativeRelocationType) {
   EXPECT_EQ(0U, getELFRelativeRelocationType(EM_VE));
 }
+
+// This is a test for the DataRegion helper struct, defined in ELF.h header.
+TEST(ELFTest, DataRegionTest) {
+  std::vector<uint8_t> Data = {0, 1, 2};
+
+  // Used to check that the operator[] works properly.
+  auto CheckOperator = [&](DataRegion<uint8_t> &R) {
+    for (size_t I = 0, E = Data.size(); I != E; ++I) {
+      Expected<uint8_t> ValOrErr = R[I];
+      ASSERT_THAT_EXPECTED(ValOrErr, Succeeded());
+      EXPECT_EQ(*ValOrErr, I);
+    }
+  };
+
+  // Check we can use the constructor that takes an ArrayRef<T>.
+  DataRegion<uint8_t> Region(Data);
+
+  CheckOperator(Region);
+  const char *ErrMsg1 =
+      "the index is greater than or equal to the number of entries (3)";
+  EXPECT_THAT_ERROR(Region[3].takeError(), FailedWithMessage(ErrMsg1));
+  EXPECT_THAT_ERROR(Region[4].takeError(), FailedWithMessage(ErrMsg1));
+
+  // Check we can use the constructor that takes the data begin and the
+  // data end pointers.
+  Region = {Data.data(), Data.data() + Data.size()};
+
+  CheckOperator(Region);
+  const char *ErrMsg2 = "can't read past the end of the file";
+  EXPECT_THAT_ERROR(Region[3].takeError(), FailedWithMessage(ErrMsg2));
+  EXPECT_THAT_ERROR(Region[4].takeError(), FailedWithMessage(ErrMsg2));
+}


        


More information about the llvm-branch-commits mailing list