[llvm] b21ed75 - [llvm-readobj][XCOFF] Add support for `--needed-libs` option.

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 26 00:17:34 PDT 2021


Author: Esme-Yi
Date: 2021-08-26T07:17:06Z
New Revision: b21ed75e107b10e7b82aa3da87c918214a4f0c0d

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

LOG: [llvm-readobj][XCOFF] Add support for `--needed-libs` option.

Summary: This patch is trying to add support for llvm-readobj
--needed-libs option under XCOFF.
For XCOFF, the needed libraries can be found from the Import
File ID Name Table of the Loader Section.
Currently, I am using binary inputs in the test since yaml2obj
does not yet support for writing the Loader Section and the
import file table.

Reviewed By: jhenderson

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

Added: 
    llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-32.o
    llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-64.o
    llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-empty.o
    llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test

Modified: 
    llvm/include/llvm/Object/XCOFFObjectFile.h
    llvm/lib/Object/XCOFFObjectFile.cpp
    llvm/tools/llvm-readobj/XCOFFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h
index c51c438d7470..8765832461fa 100644
--- a/llvm/include/llvm/Object/XCOFFObjectFile.h
+++ b/llvm/include/llvm/Object/XCOFFObjectFile.h
@@ -97,6 +97,31 @@ struct XCOFFSectionHeader64 : XCOFFSectionHeader<XCOFFSectionHeader64> {
   char Padding[4];
 };
 
+struct LoaderSectionHeader32 {
+  support::ubig32_t Version;
+  support::ubig32_t NumberOfSymTabEnt;
+  support::ubig32_t NumberOfRelTabEnt;
+  support::ubig32_t LengthOfImpidStrTbl;
+  support::ubig32_t NumberOfImpid;
+  support::big32_t OffsetToImpid;
+  support::ubig32_t LengthOfStrTbl;
+  support::big32_t OffsetToStrTbl;
+};
+
+struct LoaderSectionHeader64 {
+  support::ubig32_t Version;
+  support::ubig32_t NumberOfSymTabEnt;
+  support::ubig32_t NumberOfRelTabEnt;
+  support::ubig32_t LengthOfImpidStrTbl;
+  support::ubig32_t NumberOfImpid;
+  support::ubig32_t LengthOfStrTbl;
+  support::big64_t OffsetToImpid;
+  support::big64_t OffsetToStrTbl;
+  support::big64_t OffsetToSymTbl;
+  char Padding[16];
+  support::big32_t OffsetToRelEnt;
+};
+
 struct XCOFFStringTable {
   uint32_t Size;
   const char *Data;
@@ -290,6 +315,7 @@ class XCOFFObjectFile : public ObjectFile {
   const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const;
   uintptr_t getSectionHeaderTableAddress() const;
   uintptr_t getEndOfSymbolTableAddress() const;
+  Expected<uintptr_t> getLoaderSectionAddress() const;
 
   // This returns a pointer to the start of the storage for the name field of
   // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily
@@ -429,6 +455,9 @@ class XCOFFObjectFile : public ObjectFile {
   template <typename Shdr, typename Reloc>
   Expected<ArrayRef<Reloc>> relocations(const Shdr &Sec) const;
 
+  // Loader section related interfaces.
+  Expected<StringRef> getImportFileTable() const;
+
   // This function returns string table entry.
   Expected<StringRef> getStringTableEntry(uint32_t Offset) const;
 

diff  --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
index 7ec418c7b2f0..dfb48e60550f 100644
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -307,6 +307,38 @@ uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
   return Result;
 }
 
+Expected<uintptr_t> XCOFFObjectFile::getLoaderSectionAddress() const {
+  uint64_t OffsetToLoaderSection = 0;
+  uint64_t SizeOfLoaderSection = 0;
+
+  if (is64Bit()) {
+    for (const auto &Sec64 : sections64())
+      if (Sec64.getSectionType() == XCOFF::STYP_LOADER) {
+        OffsetToLoaderSection = Sec64.FileOffsetToRawData;
+        SizeOfLoaderSection = Sec64.SectionSize;
+        break;
+      }
+  } else {
+    for (const auto &Sec32 : sections32())
+      if (Sec32.getSectionType() == XCOFF::STYP_LOADER) {
+        OffsetToLoaderSection = Sec32.FileOffsetToRawData;
+        SizeOfLoaderSection = Sec32.SectionSize;
+        break;
+      }
+  }
+
+  // No loader section is not an error.
+  if (!SizeOfLoaderSection)
+    return 0;
+
+  uintptr_t LoderSectionStart =
+      reinterpret_cast<uintptr_t>(base() + OffsetToLoaderSection);
+  if (Error E =
+          Binary::checkOffset(Data, LoderSectionStart, SizeOfLoaderSection))
+    return std::move(E);
+  return LoderSectionStart;
+}
+
 bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
   return false;
 }
@@ -794,6 +826,47 @@ XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
   return XCOFFStringTable{Size, StringTablePtr};
 }
 
+// This function returns the import file table. Each entry in the import file
+// table consists of: "path_name\0base_name\0archive_member_name\0".
+Expected<StringRef> XCOFFObjectFile::getImportFileTable() const {
+  Expected<uintptr_t> LoaderSectionAddrOrError = getLoaderSectionAddress();
+  if (!LoaderSectionAddrOrError)
+    return LoaderSectionAddrOrError.takeError();
+
+  uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
+  if (!LoaderSectionAddr)
+    return StringRef();
+
+  uint64_t OffsetToImportFileTable = 0;
+  uint64_t LengthOfImportFileTable = 0;
+  if (is64Bit()) {
+    const LoaderSectionHeader64 *LoaderSec64 =
+        viewAs<LoaderSectionHeader64>(LoaderSectionAddr);
+    OffsetToImportFileTable = LoaderSec64->OffsetToImpid;
+    LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl;
+  } else {
+    const LoaderSectionHeader32 *LoaderSec32 =
+        viewAs<LoaderSectionHeader32>(LoaderSectionAddr);
+    OffsetToImportFileTable = LoaderSec32->OffsetToImpid;
+    LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl;
+  }
+
+  auto ImportTableOrErr = getObject<char>(
+      Data,
+      reinterpret_cast<void *>(LoaderSectionAddr + OffsetToImportFileTable),
+      LengthOfImportFileTable);
+  if (Error E = ImportTableOrErr.takeError())
+    return std::move(E);
+
+  const char *ImportTablePtr = ImportTableOrErr.get();
+  if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0')
+    return createStringError(
+        object_error::parse_failed,
+        "the import file table must end with a null terminator");
+
+  return StringRef(ImportTablePtr, LengthOfImportFileTable);
+}
+
 Expected<std::unique_ptr<XCOFFObjectFile>>
 XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
   // Can't use std::make_unique because of the private constructor.

diff  --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-32.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-32.o
new file mode 100755
index 000000000000..6137aee2a48d
Binary files /dev/null and b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-32.o 
diff er

diff  --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-64.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-64.o
new file mode 100755
index 000000000000..98504eb02e46
Binary files /dev/null and b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-64.o 
diff er

diff  --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-empty.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-empty.o
new file mode 100644
index 000000000000..98f2ce1a26c6
Binary files /dev/null and b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/needed-libs-empty.o 
diff er

diff  --git a/llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test b/llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test
new file mode 100644
index 000000000000..3dea70a36879
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/XCOFF/needed-libs.test
@@ -0,0 +1,29 @@
+## In this test we check the --needed-libs option.
+
+# RUN: llvm-readobj --needed-libs %p/Inputs/needed-libs-32.o \
+# RUN:   %p/Inputs/needed-libs-64.o %p/Inputs/needed-libs-empty.o |\
+# RUN:   FileCheck %s --strict-whitespace --match-full-lines
+
+## Check 32-bit.
+
+#      CHECK:NeededLibraries [
+# CHECK-NEXT:  BASE             MEMBER
+# CHECK-NEXT:  libc.a           shr.o
+# CHECK-NEXT:  libpthreads.a    shr_xpg5.o
+# CHECK-NEXT:  libabcdefghijk.a 
+# CHECK-NEXT:]
+
+## Check 64-bit.
+
+#      CHECK:NeededLibraries [
+# CHECK-NEXT:  BASE               MEMBER
+# CHECK-NEXT:  libc.a             shr_64.o
+# CHECK-NEXT:  libpthreads.a      shr_xpg5_64.o
+# CHECK-NEXT:  libabcdefghijk64.a 
+# CHECK-NEXT:]
+
+## Check no lib.
+
+#      CHECK:NeededLibraries [
+# CHECK-NEXT:  BASE          MEMBER
+# CHECK-NEXT:]

diff  --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
index 9371901b1d34..3d9e9e6aac40 100644
--- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -13,6 +13,7 @@
 #include "ObjDumper.h"
 #include "llvm-readobj.h"
 #include "llvm/Object/XCOFFObjectFile.h"
+#include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/ScopedPrinter.h"
 
 using namespace llvm;
@@ -494,7 +495,43 @@ void XCOFFDumper::printStackMap() const {
 }
 
 void XCOFFDumper::printNeededLibraries() {
-  llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+  ListScope D(W, "NeededLibraries");
+  auto ImportFilesOrError = Obj.getImportFileTable();
+  if (!ImportFilesOrError) {
+    reportUniqueWarning(ImportFilesOrError.takeError());
+    return;
+  }
+
+  StringRef ImportFileTable = ImportFilesOrError.get();
+  const char *CurrentStr = ImportFileTable.data();
+  const char *TableEnd = ImportFileTable.end();
+  // Default column width for names is 13 even if no names are that long.
+  size_t BaseWidth = 13;
+
+  // Get the max width of BASE columns.
+  for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) {
+    size_t CurrentLen = strlen(CurrentStr);
+    CurrentStr += strlen(CurrentStr) + 1;
+    if (StrIndex % 3 == 1)
+      BaseWidth = std::max(BaseWidth, CurrentLen);
+  }
+
+  auto &OS = static_cast<formatted_raw_ostream &>(W.startLine());
+  // Each entry consists of 3 strings: the path_name, base_name and
+  // archive_member_name. The first entry is a default LIBPATH value and other
+  // entries have no path_name. We just dump the base_name and
+  // archive_member_name here.
+  OS << left_justify("BASE", BaseWidth)  << " MEMBER\n";
+  CurrentStr = ImportFileTable.data();
+  for (size_t StrIndex = 0; CurrentStr < TableEnd;
+       ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) {
+    if (StrIndex >= 3 && StrIndex % 3 != 0) {
+      if (StrIndex % 3 == 1)
+        OS << "  " << left_justify(CurrentStr, BaseWidth) << " ";
+      else
+        OS << CurrentStr << "\n";
+    }
+  }
 }
 
 static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {


        


More information about the llvm-commits mailing list