diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -188,7 +188,10 @@
 }
 
 StringRef XCOFFObjectFile::getStringTable() const {
-  return StringRef(StringTable.Data, StringTable.Size);
+  // If the size is less than or equal to 4, then the string table contains no
+  // string data.
+  return StringRef(StringTable.Data,
+                   StringTable.Size <= 4 ? 0 : StringTable.Size);
 }
 
 Expected<StringRef>
diff --git a/llvm/test/tools/llvm-readobj/XCOFF/string-table.yaml b/llvm/test/tools/llvm-readobj/XCOFF/string-table.yaml
--- a/llvm/test/tools/llvm-readobj/XCOFF/string-table.yaml
+++ b/llvm/test/tools/llvm-readobj/XCOFF/string-table.yaml
@@ -0,0 +1,57 @@
+## Test that the string table is dumped correctly.
+
+## The string table just contains a single-byte sized string entry.
+# RUN: yaml2obj --docnum=1 %s -o %t1
+# RUN: llvm-readobj --string-table %t1 | FileCheck %s --check-prefix=SINGLE-BYTE
+
+# SINGLE-BYTE:      StringTable {
+# SINGLE-BYTE-NEXT:   [     4]   n
+# SINGLE-BYTE-NEXT: }
+
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x01F7
+Symbols:
+  - Name: n
+
+## There is no string table.
+# RUN: yaml2obj --docnum=2 %s -o %t2
+# RUN: llvm-readobj --string-table %t2 | FileCheck %s --check-prefix=NO-STRTBL
+
+# NO-STRTBL:      StringTable {
+# NO-STRTBL-NEXT: }
+
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x01F7
+
+## There is an empty string table with just the length field.
+## TODO: Print the string table size to check the length field.
+# RUN: yaml2obj --docnum=3 %s -o %t3
+# RUN: llvm-readobj --string-table %t3 | FileCheck %s --check-prefix=EMPTY-TBL
+
+# EMPTY-TBL:      StringTable {
+# EMPTY-TBL-NEXT: }
+
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Symbols:
+  - Name: asymname
+
+## The string table contians more than one entry.
+# RUN: yaml2obj --docnum=4 %s -o %t4
+# RUN: llvm-readobj --string-table %t4 | FileCheck %s --check-prefix=BASIC
+
+# BASIC:      StringTable {
+# BASIC-NEXT:   [     4]   longname2
+# BASIC-NEXT:   [     e]   longname1
+# BASIC-NEXT: }
+
+--- !XCOFF
+FileHeader:
+  MagicNumber: 0x1DF
+Symbols:
+  - Name: asymname
+  - Name: longname1
+  - Name: longname2
diff --git a/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml b/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml
--- a/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml
+++ b/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml
@@ -2,8 +2,6 @@
 # RUN: yaml2obj %s -o %t
 # RUN: llvm-readobj --symbols --string-table %t | FileCheck %s
 
-## FIXME: The first item of StringTable should be `[     4]   .longname`.
-
 # CHECK:      AddressSize: 32bit
 # CHECK-NEXT: Symbols [
 # CHECK-NEXT:   Symbol {
@@ -26,7 +24,7 @@
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 # CHECK-NEXT: StringTable {
-# CHECK-NEXT:   [     3]   ..longname
+# CHECK-NEXT:   [     4]   .longname
 # CHECK-NEXT: }
 
 --- !XCOFF
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -110,7 +110,7 @@
 
   virtual void printStackMap() const = 0;
 
-  void printAsStringList(StringRef StringContent);
+  void printAsStringList(StringRef StringContent, size_t StringDataOffset = 0);
 
   void printSectionsAsString(const object::ObjectFile &Obj,
                              ArrayRef<std::string> Sections);
diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp
--- a/llvm/tools/llvm-readobj/ObjDumper.cpp
+++ b/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -53,9 +53,13 @@
     W << (isPrint(Start[i]) ? static_cast<char>(Start[i]) : '.');
 }
 
-void ObjDumper::printAsStringList(StringRef StringContent) {
+void ObjDumper::printAsStringList(StringRef StringContent,
+                                  size_t StringDataOffset) {
   const uint8_t *StrContent = StringContent.bytes_begin();
-  const uint8_t *CurrentWord = StrContent;
+  // Some formats contain additional metadata at the start which should not be
+  // interpreted as strings. Skip these bytes, but account for them in the
+  // string offsets.
+  const uint8_t *CurrentWord = StrContent + StringDataOffset;
   const uint8_t *StrEnd = StringContent.bytes_end();
 
   while (CurrentWord <= StrEnd) {
diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
--- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -460,7 +460,9 @@
 void XCOFFDumper::printStringTable() {
   DictScope DS(W, "StringTable");
   StringRef StrTable = Obj.getStringTable();
-  printAsStringList(StrTable);
+  // Print strings from byte 4, since the first three bytes contain the length
+  // (in bytes) of the string table (including the length field).
+  printAsStringList(StrTable, 4);
 }
 
 void XCOFFDumper::printDynamicSymbols() {