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

via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 13 09:55:30 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-binary-utilities

Author: Jason Liu (jasonliudev)

<details>
<summary>Changes</summary>

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.


---
Full diff: https://github.com/llvm/llvm-project/pull/72141.diff


5 Files Affected:

- (modified) llvm/include/llvm/Object/ELF.h (+2) 
- (modified) llvm/lib/Object/ELF.cpp (+43) 
- (added) llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test (+54) 
- (modified) llvm/tools/llvm-objdump/ELFDump.cpp (+4-2) 
- (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+3-39) 


``````````diff
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 927deeea2cd6aef..e5201c9439e59ab 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -425,6 +425,8 @@ class ELFFile {
       std::function<Expected<bool>(const Elf_Shdr &)> IsMatch) const;
 
   void createFakeSections();
+
+  static bool isSectionInSegment(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
 };
 
 using ELF32LEFile = ELFFile<ELF32LE>;
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 0d1862e573712f5..e3dc4329aad3268 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -799,6 +799,49 @@ ELFFile<ELFT>::getSectionAndRelocations(
   return SecToRelocMap;
 }
 
+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>
+bool ELFFile<ELFT>::isSectionInSegment(const Elf_Phdr &Phdr,
+                                       const Elf_Shdr &Sec) {
+  return checkOffsets<ELFT>(Phdr, Sec) && checkVMA<ELFT>(Phdr, Sec);
+}
+
 template class llvm::object::ELFFile<ELF32LE>;
 template class llvm::object::ELFFile<ELF32BE>;
 template class llvm::object::ELFFile<ELF64LE>;
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..e44d3f66310c0a8
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/X86/phdrs-lma3.test
@@ -0,0 +1,54 @@
+# RUN: yaml2obj %s > %t
+
+## Check when vma is the same, we could still print LMA correctly when dumping
+## section headers.
+# 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..8951bbc52ac94ed 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) &&
+        (Obj.isSectionInSegment(
+            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..3e6fa1d159210af 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 (this->Obj.isSectionInSegment(Phdr, Sec) &&
+          checkTLSSections<ELFT>(Phdr, Sec) &&
+          checkPTDynamic<ELFT>(Phdr, Sec)) {
         Sections +=
             unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() +
             " ";

``````````

</details>


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


More information about the llvm-commits mailing list