[llvm] [llvm-objdump] Fix lma display issue for non-bss sections (PR #72141)

Jason Liu via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 27 09:00:10 PST 2023


https://github.com/jasonliudev updated https://github.com/llvm/llvm-project/pull/72141

>From 484b735dc513075858152924e755cde69c78ac1b Mon Sep 17 00:00:00 2001
From: Jason Liu <jasonliu.development at gmail.com>
Date: Mon, 13 Nov 2023 12:07:00 -0500
Subject: [PATCH] [llvm-objdump] Fix lma display issue for non-bss sections

llvm-readobj and llvm-objdump have inconsistent handling of display
lma for sections.
This patch tries to common code up and adapt the same approach for
both tools.
---
 llvm/include/llvm/Object/ELF.h                | 44 +++++++++++++++
 .../tools/llvm-objdump/X86/phdrs-lma3.test    | 54 +++++++++++++++++++
 llvm/tools/llvm-objdump/ELFDump.cpp           |  6 ++-
 llvm/tools/llvm-readobj/ELFDumper.cpp         | 42 ++-------------
 4 files changed, 105 insertions(+), 41 deletions(-)
 create mode 100644 llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test

diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 927deeea2cd6aef..3fca00592f73b4c 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -163,6 +163,50 @@ static inline Error defaultWarningHandler(const Twine &Msg) {
   return createError(Msg);
 }
 
+template <class ELFT>
+bool checkSectionOffsets(const typename ELFT::Phdr &Phdr,
+                         const typename ELFT::Shdr &Sec) {
+  // SHT_NOBITS sections don't need to have an offset inside the segment.
+  if (Sec.sh_type == ELF::SHT_NOBITS)
+    return true;
+
+  if (Sec.sh_offset < Phdr.p_offset)
+    return false;
+
+  // Only non-empty sections can be at the end of a segment.
+  if (Sec.sh_size == 0)
+    return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
+  return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
+}
+
+// Check that an allocatable section belongs to a virtual address
+// space of a segment.
+template <class ELFT>
+bool checkSectionVMA(const typename ELFT::Phdr &Phdr,
+                     const typename ELFT::Shdr &Sec) {
+  if (!(Sec.sh_flags & ELF::SHF_ALLOC))
+    return true;
+
+  if (Sec.sh_addr < Phdr.p_vaddr)
+    return false;
+
+  bool IsTbss =
+      (Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
+  // .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
+  bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
+  // Only non-empty sections can be at the end of a segment.
+  if (Sec.sh_size == 0 || IsTbssInNonTLS)
+    return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
+  return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
+}
+
+template <class ELFT>
+bool isSectionInSegment(const typename ELFT::Phdr &Phdr,
+                        const typename ELFT::Shdr &Sec) {
+  return checkSectionOffsets<ELFT>(Phdr, Sec) &&
+         checkSectionVMA<ELFT>(Phdr, Sec);
+}
+
 template <class ELFT>
 class ELFFile {
 public:
diff --git a/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test b/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test
new file mode 100644
index 000000000000000..663882ecd529029
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test
@@ -0,0 +1,54 @@
+# RUN: yaml2obj %s -o %t
+
+## .data and .data_copy have the same VMA but different sh_offset values.
+## Check that we can still print LMA correctly.
+# RUN: llvm-objdump --section-headers %t | FileCheck %s
+
+# CHECK:      Sections:
+# CHECK-NEXT: Idx Name          Size     VMA              LMA              Type
+# CHECK-NEXT:   0               00000000 0000000000000000 0000000000000000
+# CHECK-NEXT:   1 .text         00000004 0000000000001000 0000000000002000 TEXT
+# CHECK-NEXT:   2 .data         00000004 0000000000002000 0000000000003000 DATA
+# CHECK-NEXT:   3 .data_copy    00000004 0000000000002000 0000000000004000 DATA
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content:         "00000000"
+    Address:         0x00001000
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Content:         "00000000"
+    Address:         0x00002000
+  - Name:            .data_copy
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Content:         "00000000"
+    Address:         0x00002000
+ProgramHeaders:
+  - Type:     PT_LOAD
+    Flags:    [ PF_X, PF_R ]
+    VAddr:    0x00001000
+    PAddr:    0x00002000
+    FirstSec: .text
+    LastSec:  .text
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x00002000
+    PAddr:    0x00003000
+    FirstSec: .data
+    LastSec:  .data
+  - Type:     PT_LOAD
+    Flags:    [ PF_R ]
+    VAddr:    0x00002000
+    PAddr:    0x00004000
+    FirstSec: .data_copy
+    LastSec:  .data_copy
diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp
index 299a7e3cf3fa523..34861ee92128fdd 100644
--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -181,8 +181,10 @@ static uint64_t getSectionLMA(const ELFFile<ELFT> &Obj,
   // Search for a PT_LOAD segment containing the requested section. Use this
   // segment's p_addr to calculate the section's LMA.
   for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
-    if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) &&
-        (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress()))
+    if ((Phdr.p_type == ELF::PT_LOAD) &&
+        (isSectionInSegment<ELFT>(
+            Phdr, *cast<const ELFObjectFile<ELFT>>(Sec.getObject())
+                       ->getSection(Sec.getRawDataRefImpl()))))
       return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr;
 
   // Return section's VMA if it isn't in a PT_LOAD segment.
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 64f343a9b37a343..7a3c1381f8d8ca4 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -4507,43 +4507,6 @@ static bool checkTLSSections(const typename ELFT::Phdr &Phdr,
   return Phdr.p_type != ELF::PT_TLS;
 }
 
-template <class ELFT>
-static bool checkOffsets(const typename ELFT::Phdr &Phdr,
-                         const typename ELFT::Shdr &Sec) {
-  // SHT_NOBITS sections don't need to have an offset inside the segment.
-  if (Sec.sh_type == ELF::SHT_NOBITS)
-    return true;
-
-  if (Sec.sh_offset < Phdr.p_offset)
-    return false;
-
-  // Only non-empty sections can be at the end of a segment.
-  if (Sec.sh_size == 0)
-    return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
-  return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
-}
-
-// Check that an allocatable section belongs to a virtual address
-// space of a segment.
-template <class ELFT>
-static bool checkVMA(const typename ELFT::Phdr &Phdr,
-                     const typename ELFT::Shdr &Sec) {
-  if (!(Sec.sh_flags & ELF::SHF_ALLOC))
-    return true;
-
-  if (Sec.sh_addr < Phdr.p_vaddr)
-    return false;
-
-  bool IsTbss =
-      (Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
-  // .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
-  bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
-  // Only non-empty sections can be at the end of a segment.
-  if (Sec.sh_size == 0 || IsTbssInNonTLS)
-    return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
-  return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
-}
-
 template <class ELFT>
 static bool checkPTDynamic(const typename ELFT::Phdr &Phdr,
                            const typename ELFT::Shdr &Sec) {
@@ -4675,8 +4638,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printSectionMapping() {
       // readelf additionally makes sure it does not print zero sized sections
       // at end of segments and for PT_DYNAMIC both start and end of section
       // .tbss must only be shown in PT_TLS section.
-      if (checkTLSSections<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) &&
-          checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) {
+      if (isSectionInSegment<ELFT>(Phdr, Sec) &&
+          checkTLSSections<ELFT>(Phdr, Sec) &&
+          checkPTDynamic<ELFT>(Phdr, Sec)) {
         Sections +=
             unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() +
             " ";



More information about the llvm-commits mailing list