[llvm-branch-commits] [llvm] [llvm-readobj][ELF] Print the relocation of each --stack-sizes entry (PR #232332)

Prabhu Rajasekaran via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Oct 15 15:48:16 PDT 2026


https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/232332

>From 865b06eacda0db0a6264aa1f5a80a20891464b91 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 06:57:12 -0700
Subject: [PATCH 1/6] [llvm-readobj][ELF] Print the relocation of each
 --stack-sizes entry

In a relocatable file, print the relocation that applies to each
.stack_sizes entry as a Relocation object in the LLVM and JSON output,
with the same fields as in --call-graph-info. The code that prints the
object is shared with --call-graph-info, so the addend of a SHT_REL
relocation is again the value stored in the address field.

Assisted-by: Gemini
---
 .../tools/llvm-readobj/ELF/stack-sizes.test   | 138 +++++++++++++++++-
 llvm/tools/llvm-readobj/ELFDumper.cpp         | 105 ++++++++-----
 2 files changed, 207 insertions(+), 36 deletions(-)

diff --git a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
index c9c5fd52142ea..15225bf8c445b 100644
--- a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
+++ b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
@@ -1,10 +1,13 @@
 ## Check that we correctly display the contents of the .stack_sizes section
-## in a relocatable object file.
+## in a relocatable object file, with the relocation for each function in the
+## LLVM and JSON output.
 
 # RUN: yaml2obj --docnum=1 %s -o %t01
 # RUN: llvm-readelf --stack-sizes %t01 \
 # RUN:   | FileCheck %s --check-prefix=RELOC-GNU --strict-whitespace --match-full-lines
 # RUN: llvm-readobj --stack-sizes %t01 | FileCheck %s --check-prefix=RELOC-LLVM
+# RUN: llvm-readobj --elf-output-style=JSON --pretty-print --stack-sizes %t01 \
+# RUN:   | FileCheck %s --check-prefix=RELOC-JSON
 
 #      RELOC-GNU:         Size     Functions
 # RELOC-GNU-NEXT:           16     referenced_by_symbol_foo
@@ -15,18 +18,45 @@
 # RELOC-LLVM:      StackSizes [
 # RELOC-LLVM-NEXT:   Entry {
 # RELOC-LLVM-NEXT:     Functions: [referenced_by_symbol_foo]
+# RELOC-LLVM-NEXT:     Relocation {
+# RELOC-LLVM-NEXT:       SymbolIndex: 3{{$}}
+# RELOC-LLVM-NEXT:       SymbolName: referenced_by_symbol_foo
+# RELOC-LLVM-NEXT:     }
 # RELOC-LLVM-NEXT:     Size: 0x10
 # RELOC-LLVM-NEXT:   }
 # RELOC-LLVM-NEXT:   Entry {
 # RELOC-LLVM-NEXT:     Functions: [referenced_via_section_bar]
+# RELOC-LLVM-NEXT:     Relocation {
+# RELOC-LLVM-NEXT:       SymbolIndex: 2{{$}}
+# RELOC-LLVM-NEXT:       SymbolName: .text
+# RELOC-LLVM-NEXT:       Addend: 16{{$}}
+# RELOC-LLVM-NEXT:     }
 # RELOC-LLVM-NEXT:     Size: 0x20
 # RELOC-LLVM-NEXT:   }
 # RELOC-LLVM-NEXT:   Entry {
 # RELOC-LLVM-NEXT:     Functions: [separate_text_section_baz]
+# RELOC-LLVM-NEXT:     Relocation {
+# RELOC-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# RELOC-LLVM-NEXT:       SymbolName: separate_text_section_baz
+# RELOC-LLVM-NEXT:     }
 # RELOC-LLVM-NEXT:     Size: 0x8
 # RELOC-LLVM-NEXT:   }
 # RELOC-LLVM-NEXT: ]
 
+# RELOC-JSON:      "StackSizes": [
+# RELOC-JSON-NEXT:   {
+# RELOC-JSON-NEXT:     "Entry": {
+# RELOC-JSON-NEXT:       "Functions": [
+# RELOC-JSON-NEXT:         "referenced_by_symbol_foo"
+# RELOC-JSON-NEXT:       ],
+# RELOC-JSON-NEXT:       "Relocation": {
+# RELOC-JSON-NEXT:         "SymbolIndex": 3,
+# RELOC-JSON-NEXT:         "SymbolName": "referenced_by_symbol_foo"
+# RELOC-JSON-NEXT:       },
+# RELOC-JSON-NEXT:       "Size": 16
+# RELOC-JSON-NEXT:     }
+# RELOC-JSON-NEXT:   },
+
 --- !ELF
 FileHeader:
   Class:   ELFCLASS64
@@ -122,17 +152,27 @@ Symbols:
 # SYMTAB-LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 3
 # SYMTAB-LLVM-NEXT:   Entry {
 # SYMTAB-LLVM-NEXT:     Functions: [?]
+# SYMTAB-LLVM-NEXT:     Relocation {
+# SYMTAB-LLVM-NEXT:       SymbolIndex: 3{{$}}
+# SYMTAB-LLVM-NEXT:     }
 # SYMTAB-LLVM-NEXT:     Size: 0x10
 # SYMTAB-LLVM-NEXT:   }
 # SYMTAB-LLVM-NEXT: warning: '[[FILE]]': unable to get the target of relocation with index 1 in SHT_RELA section with index 5: unable to read an entry with index 2 from SHT_SYMTAB section with index 7: section [index 7] has a sh_offset (0xffffeeee) + sh_size (0x78) that is greater than the file size (0x450)
 # SYMTAB-LLVM-NEXT:   Entry {
 # SYMTAB-LLVM-NEXT:     Functions: [?]
+# SYMTAB-LLVM-NEXT:     Relocation {
+# SYMTAB-LLVM-NEXT:       SymbolIndex: 2{{$}}
+# SYMTAB-LLVM-NEXT:       Addend: 16{{$}}
+# SYMTAB-LLVM-NEXT:     }
 # SYMTAB-LLVM-NEXT:     Size: 0x20
 # SYMTAB-LLVM-NEXT:   }
 # SYMTAB-LLVM-NEXT: warning: '[[FILE]]': unable to get the target of relocation with index 0 in SHT_RELA section with index 6: unable to read an entry with index 1 from SHT_SYMTAB section with index 7: section [index 7] has a sh_offset (0xffffeeee) + sh_size (0x78) that is greater than the file size (0x450)
 # SYMTAB-LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 4
 # SYMTAB-LLVM-NEXT:   Entry {
 # SYMTAB-LLVM-NEXT:     Functions: [?]
+# SYMTAB-LLVM-NEXT:     Relocation {
+# SYMTAB-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# SYMTAB-LLVM-NEXT:     }
 # SYMTAB-LLVM-NEXT:     Size: 0x8
 # SYMTAB-LLVM-NEXT:   }
 # SYMTAB-LLVM-NEXT: ]
@@ -161,16 +201,29 @@ Symbols:
 # SYM-LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 3
 # SYM-LLVM-NEXT:   Entry {
 # SYM-LLVM-NEXT:     Functions: [?]
+# SYM-LLVM-NEXT:     Relocation {
+# SYM-LLVM-NEXT:       SymbolIndex: 3{{$}}
+# SYM-LLVM-NEXT:       SymbolName: referenced_by_symbol_foo
+# SYM-LLVM-NEXT:     }
 # SYM-LLVM-NEXT:     Size: 0x10
 # SYM-LLVM-NEXT:   }
 # SYM-LLVM-NEXT:   Entry {
 # SYM-LLVM-NEXT:     Functions: [?]
+# SYM-LLVM-NEXT:     Relocation {
+# SYM-LLVM-NEXT:       SymbolIndex: 2{{$}}
+# SYM-LLVM-NEXT:       SymbolName: .text
+# SYM-LLVM-NEXT:       Addend: 16{{$}}
+# SYM-LLVM-NEXT:     }
 # SYM-LLVM-NEXT:     Size: 0x20
 # SYM-LLVM-NEXT:   }
 # SYM-LLVM-NEXT: warning: '[[FILE]]': cannot identify the section for relocation symbol 'separate_text_section_baz': invalid section index: 255
 # SYM-LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 4
 # SYM-LLVM-NEXT:   Entry {
 # SYM-LLVM-NEXT:     Functions: [?]
+# SYM-LLVM-NEXT:     Relocation {
+# SYM-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# SYM-LLVM-NEXT:       SymbolName: separate_text_section_baz
+# SYM-LLVM-NEXT:     }
 # SYM-LLVM-NEXT:     Size: 0x8
 # SYM-LLVM-NEXT:   }
 # SYM-LLVM-NEXT: ]
@@ -285,11 +338,19 @@ Symbols:
 # SHORT-LLVM:     StackSizes [
 # SHORT-LLVM-NEXT:   Entry {
 # SHORT-LLVM-NEXT:     Functions: [foo]
+# SHORT-LLVM-NEXT:     Relocation {
+# SHORT-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# SHORT-LLVM-NEXT:       SymbolName: foo
+# SHORT-LLVM-NEXT:     }
 # SHORT-LLVM-NEXT:     Size: 0x8
 # SHORT-LLVM-NEXT:   }
 # SHORT-LLVM-NEXT: warning: '[[FILE]]': found invalid relocation offset (0x1) into SHT_PROGBITS section with index 2 while trying to extract a stack size entry
 # SHORT-LLVM-NEXT:   Entry {
 # SHORT-LLVM-NEXT:     Functions: [foo]
+# SHORT-LLVM-NEXT:     Relocation {
+# SHORT-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# SHORT-LLVM-NEXT:       SymbolName: foo
+# SHORT-LLVM-NEXT:     }
 # SHORT-LLVM-NEXT:     Size: 0x8
 # SHORT-LLVM-NEXT:   }
 # SHORT-LLVM-NEXT: ]
@@ -343,7 +404,8 @@ Symbols:
 # RUN: FileCheck %s < %t04-llvm.err --check-prefix=WRONGSECTION-ERR -DFILE=%t04
 
 # RUN: llvm-readelf --stack-sizes --demangle %t04 2>&1 | FileCheck %s --check-prefix=WRONGSECTION-DEMANGLE-ERR -DFILE=%t04
-# RUN: llvm-readobj --stack-sizes --demangle %t04 2>&1 | FileCheck %s --check-prefix=WRONGSECTION-DEMANGLE-ERR -DFILE=%t04
+# RUN: llvm-readobj --stack-sizes --demangle %t04 2>&1 | \
+# RUN:   FileCheck %s --check-prefixes=WRONGSECTION-DEMANGLE-ERR,WRONGSECTION-DEMANGLE-LLVM -DFILE=%t04
 
 # WRONGSECTION-GNU:      Size Functions
 # WRONGSECTION-GNU-NEXT: 8 _Z3foof
@@ -351,6 +413,10 @@ Symbols:
 # WRONGSECTION-LLVM:      StackSizes [
 # WRONGSECTION-LLVM-NEXT:   Entry {
 # WRONGSECTION-LLVM-NEXT:     Functions: [_Z3foof]
+# WRONGSECTION-LLVM-NEXT:     Relocation {
+# WRONGSECTION-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# WRONGSECTION-LLVM-NEXT:       SymbolName: _Z3foof
+# WRONGSECTION-LLVM-NEXT:     }
 # WRONGSECTION-LLVM-NEXT:     Size: 0x8
 # WRONGSECTION-LLVM-NEXT:   }
 # WRONGSECTION-LLVM-NEXT: ]
@@ -358,6 +424,15 @@ Symbols:
 # WRONGSECTION-ERR:           warning: '[[FILE]]': relocation symbol '_Z3foof' is not in the expected section
 # WRONGSECTION-DEMANGLE-ERR:  warning: '[[FILE]]': relocation symbol 'foo(float)' is not in the expected section
 
+## With --demangle, the relocation's symbol name is still printed as it is in the
+## symbol table, followed by its demangled form.
+# WRONGSECTION-DEMANGLE-LLVM:      Functions: [foo(float)]
+# WRONGSECTION-DEMANGLE-LLVM-NEXT: Relocation {
+# WRONGSECTION-DEMANGLE-LLVM-NEXT:   SymbolIndex: 1{{$}}
+# WRONGSECTION-DEMANGLE-LLVM-NEXT:   SymbolName: _Z3foof
+# WRONGSECTION-DEMANGLE-LLVM-NEXT:   DemangledName: foo(float)
+# WRONGSECTION-DEMANGLE-LLVM-NEXT: }
+
 --- !ELF
 FileHeader:
   Class:   ELFCLASS64
@@ -513,16 +588,26 @@ Symbols:
 # BADSECTION-OUT-LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for stack size entry in SHT_PROGBITS section with index 2
 # BADSECTION-OUT-LLVM-NEXT:   Entry {
 # BADSECTION-OUT-LLVM-NEXT:     Functions: [?]
+# BADSECTION-OUT-LLVM-NEXT:     Relocation {
+# BADSECTION-OUT-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# BADSECTION-OUT-LLVM-NEXT:       SymbolName: _Z3foof
+# BADSECTION-OUT-LLVM-NEXT:     }
 # BADSECTION-OUT-LLVM-NEXT:     Size: 0x8
 # BADSECTION-OUT-LLVM-NEXT:   }
 # BADSECTION-OUT-LLVM-NEXT: warning: '[[FILE]]': unable to get the target of relocation with index 1 in SHT_RELA section with index 3: unable to read an entry with index 255 from SHT_SYMTAB section with index 4: can't read an entry at 0x17e8: it goes past the end of the section (0x30)
 # BADSECTION-OUT-LLVM-NEXT:   Entry {
 # BADSECTION-OUT-LLVM-NEXT:     Functions: [?]
+# BADSECTION-OUT-LLVM-NEXT:     Relocation {
+# BADSECTION-OUT-LLVM-NEXT:       SymbolIndex: 255{{$}}
+# BADSECTION-OUT-LLVM-NEXT:     }
 # BADSECTION-OUT-LLVM-NEXT:     Size: 0x16
 # BADSECTION-OUT-LLVM-NEXT:   }
 # BADSECTION-OUT-LLVM-NEXT: warning: '[[FILE]]': unable to get the target of relocation with index 2 in SHT_RELA section with index 3: unable to read an entry with index 255 from SHT_SYMTAB section with index 4: can't read an entry at 0x17e8: it goes past the end of the section (0x30)
 # BADSECTION-OUT-LLVM-NEXT:   Entry {
 # BADSECTION-OUT-LLVM-NEXT:     Functions: [?]
+# BADSECTION-OUT-LLVM-NEXT:     Relocation {
+# BADSECTION-OUT-LLVM-NEXT:       SymbolIndex: 255{{$}}
+# BADSECTION-OUT-LLVM-NEXT:     }
 # BADSECTION-OUT-LLVM-NEXT:     Size: 0x24
 # BADSECTION-OUT-LLVM-NEXT:   }
 # BADSECTION-OUT-LLVM-NEXT: ]
@@ -631,14 +716,27 @@ Sections:
 # MULTIPLE-LLVM:      StackSizes [
 # MULTIPLE-LLVM-NEXT:   Entry {
 # MULTIPLE-LLVM-NEXT:     Functions: [referenced_by_symbol_foo]
+# MULTIPLE-LLVM-NEXT:     Relocation {
+# MULTIPLE-LLVM-NEXT:       SymbolIndex: 3{{$}}
+# MULTIPLE-LLVM-NEXT:       SymbolName: referenced_by_symbol_foo
+# MULTIPLE-LLVM-NEXT:     }
 # MULTIPLE-LLVM-NEXT:     Size: 0x10
 # MULTIPLE-LLVM-NEXT:   }
 # MULTIPLE-LLVM-NEXT:   Entry {
 # MULTIPLE-LLVM-NEXT:     Functions: [referenced_via_section_bar]
+# MULTIPLE-LLVM-NEXT:     Relocation {
+# MULTIPLE-LLVM-NEXT:       SymbolIndex: 2{{$}}
+# MULTIPLE-LLVM-NEXT:       SymbolName: .text
+# MULTIPLE-LLVM-NEXT:       Addend: 16{{$}}
+# MULTIPLE-LLVM-NEXT:     }
 # MULTIPLE-LLVM-NEXT:     Size: 0x20
 # MULTIPLE-LLVM-NEXT:   }
 # MULTIPLE-LLVM-NEXT:   Entry {
 # MULTIPLE-LLVM-NEXT:     Functions: [separate_text_section_baz]
+# MULTIPLE-LLVM-NEXT:     Relocation {
+# MULTIPLE-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# MULTIPLE-LLVM-NEXT:       SymbolName: separate_text_section_baz
+# MULTIPLE-LLVM-NEXT:     }
 # MULTIPLE-LLVM-NEXT:     Size: 0x8
 # MULTIPLE-LLVM-NEXT:   }
 # MULTIPLE-LLVM-NEXT: ]
@@ -686,6 +784,10 @@ Sections:
 # NONFUNCTIONSYM-LLVM:      StackSizes [
 # NONFUNCTIONSYM-LLVM-NEXT:   Entry {
 # NONFUNCTIONSYM-LLVM-NEXT:     Functions: [?]
+# NONFUNCTIONSYM-LLVM-NEXT:     Relocation {
+# NONFUNCTIONSYM-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# NONFUNCTIONSYM-LLVM-NEXT:       SymbolName: foo
+# NONFUNCTIONSYM-LLVM-NEXT:     }
 # NONFUNCTIONSYM-LLVM-NEXT:     Size: 0x0
 # NONFUNCTIONSYM-LLVM-NEXT:   }
 # NONFUNCTIONSYM-LLVM-NEXT: ]
@@ -737,6 +839,10 @@ Symbols:
 # UNSUPPRELOC-LLVM-NEXT: warning: '[[FILE]]': SHT_RELA section with index 3 contains an unsupported relocation with index 0: R_X86_64_RELATIVE
 # UNSUPPRELOC-LLVM-NEXT:   Entry {
 # UNSUPPRELOC-LLVM-NEXT:     Functions: [foo]
+# UNSUPPRELOC-LLVM-NEXT:     Relocation {
+# UNSUPPRELOC-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# UNSUPPRELOC-LLVM-NEXT:       SymbolName: foo
+# UNSUPPRELOC-LLVM-NEXT:     }
 # UNSUPPRELOC-LLVM-NEXT:     Size: 0x0
 # UNSUPPRELOC-LLVM-NEXT:   }
 # UNSUPPRELOC-LLVM-NEXT: warning: '[[FILE]]': SHT_RELA section with index 3 contains an unsupported relocation with index 2: R_X86_64_RELATIVE
@@ -804,6 +910,10 @@ Symbols:
 # ARCHIVEWARN-LLVM:      warning: '{{.*04}}': relocation symbol '_Z3foof' is not in the expected section
 # ARCHIVEWARN-LLVM-NEXT:   Entry {
 # ARCHIVEWARN-LLVM-NEXT:     Functions: [_Z3foof]
+# ARCHIVEWARN-LLVM-NEXT:     Relocation {
+# ARCHIVEWARN-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# ARCHIVEWARN-LLVM-NEXT:       SymbolName: _Z3foof
+# ARCHIVEWARN-LLVM-NEXT:     }
 # ARCHIVEWARN-LLVM-NEXT:     Size: 0x8
 # ARCHIVEWARN-LLVM-NEXT:   }
 # ARCHIVEWARN-LLVM-NEXT: ]
@@ -811,14 +921,27 @@ Symbols:
 # ARCHIVEWARN-LLVM:      StackSizes [
 # ARCHIVEWARN-LLVM-NEXT:   Entry {
 # ARCHIVEWARN-LLVM-NEXT:     Functions: [referenced_by_symbol_foo]
+# ARCHIVEWARN-LLVM-NEXT:     Relocation {
+# ARCHIVEWARN-LLVM-NEXT:       SymbolIndex: 3{{$}}
+# ARCHIVEWARN-LLVM-NEXT:       SymbolName: referenced_by_symbol_foo
+# ARCHIVEWARN-LLVM-NEXT:     }
 # ARCHIVEWARN-LLVM-NEXT:     Size: 0x10
 # ARCHIVEWARN-LLVM-NEXT:   }
 # ARCHIVEWARN-LLVM-NEXT:   Entry {
 # ARCHIVEWARN-LLVM-NEXT:     Functions: [referenced_via_section_bar]
+# ARCHIVEWARN-LLVM-NEXT:     Relocation {
+# ARCHIVEWARN-LLVM-NEXT:       SymbolIndex: 2{{$}}
+# ARCHIVEWARN-LLVM-NEXT:       SymbolName: .text
+# ARCHIVEWARN-LLVM-NEXT:       Addend: 16{{$}}
+# ARCHIVEWARN-LLVM-NEXT:     }
 # ARCHIVEWARN-LLVM-NEXT:     Size: 0x20
 # ARCHIVEWARN-LLVM-NEXT:   }
 # ARCHIVEWARN-LLVM-NEXT:   Entry {
 # ARCHIVEWARN-LLVM-NEXT:     Functions: [separate_text_section_baz]
+# ARCHIVEWARN-LLVM-NEXT:     Relocation {
+# ARCHIVEWARN-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# ARCHIVEWARN-LLVM-NEXT:       SymbolName: separate_text_section_baz
+# ARCHIVEWARN-LLVM-NEXT:     }
 # ARCHIVEWARN-LLVM-NEXT:     Size: 0x8
 # ARCHIVEWARN-LLVM-NEXT:   }
 # ARCHIVEWARN-LLVM-NEXT: ]
@@ -1010,7 +1133,8 @@ Symbols:
 
 ## Check that on ARM the Thumb bit is also cleared from the address that a
 ## relocation resolves to, so that Thumb functions are found in relocatable
-## object files too.
+## object files too. The addend of a SHT_REL relocation is the value stored in
+## the address field, as in --call-graph-info.
 
 # RUN: yaml2obj --docnum=16 %s -o %t21
 # RUN: llvm-readelf --stack-sizes %t21 2>&1 | \
@@ -1025,10 +1149,18 @@ Symbols:
 # THUMB-REL-LLVM:      StackSizes [
 # THUMB-REL-LLVM-NEXT:   Entry {
 # THUMB-REL-LLVM-NEXT:     Functions: [foo]
+# THUMB-REL-LLVM-NEXT:     Relocation {
+# THUMB-REL-LLVM-NEXT:       SymbolIndex: 2{{$}}
+# THUMB-REL-LLVM-NEXT:       SymbolName: foo
+# THUMB-REL-LLVM-NEXT:     }
 # THUMB-REL-LLVM-NEXT:     Size: 0x10
 # THUMB-REL-LLVM-NEXT:   }
 # THUMB-REL-LLVM-NEXT:   Entry {
 # THUMB-REL-LLVM-NEXT:     Functions: [bar]
+# THUMB-REL-LLVM-NEXT:     Relocation {
+# THUMB-REL-LLVM-NEXT:       SymbolIndex: 1{{$}}
+# THUMB-REL-LLVM-NEXT:       Addend: 17{{$}}
+# THUMB-REL-LLVM-NEXT:     }
 # THUMB-REL-LLVM-NEXT:     Size: 0x20
 # THUMB-REL-LLVM-NEXT:   }
 # THUMB-REL-LLVM-NEXT: ]
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 77f2eaa28b3fa..3b7ac5916ef11 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -229,6 +229,17 @@ template <class ELFT> struct FunctionCallGraphInfo {
   bool IsIndirectTarget;
 };
 
+// The relocation that applies to the address field of a .stack_sizes entry in
+// a relocatable file.
+template <class ELFT> struct StackSizeRelocation {
+  const Relocation<ELFT> &R;
+  // The symbol of the relocation, if it could be read, and its symbol table.
+  const typename ELFT::Sym *Sym;
+  const typename ELFT::Shdr &SymTab;
+  // The value stored in the address field.
+  uint64_t FieldValue;
+};
+
 template <class ELFT> class MipsGOTParser;
 
 template <typename ELFT> class ELFDumper : public ObjDumper {
@@ -363,17 +374,19 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   bool printFunctionStackSize(uint64_t SymValue,
                               std::optional<const Elf_Shdr *> FunctionSec,
                               const Elf_Shdr &StackSizeSec, DataExtractor Data,
-                              uint64_t *Offset);
+                              uint64_t *Offset,
+                              const StackSizeRelocation<ELFT> *Reloc);
   void printStackSize(const Relocation<ELFT> &R, const Elf_Shdr &RelocSec,
                       unsigned Ndx, const Elf_Shdr *SymTab,
                       const Elf_Shdr *FunctionSec, const Elf_Shdr &StackSizeSec,
                       const RelocationResolver &Resolver, DataExtractor Data);
   // Prints a stack size entry. Address is the function's address: the value
   // stored in the entry in a linked file, or the value that its relocation
-  // resolves to in a relocatable file.
+  // resolves to in a relocatable file. Reloc is that relocation, if any.
   virtual void printStackSizeEntry(uint64_t Size,
                                    ArrayRef<std::string> FuncNames,
-                                   uint64_t Address) = 0;
+                                   uint64_t Address,
+                                   const StackSizeRelocation<ELFT> *Reloc) = 0;
 
   void printRelocatableStackSizes(std::function<void()> PrintHeader);
   void printNonRelocatableStackSizes(std::function<void()> PrintHeader);
@@ -754,7 +767,8 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
                                     const Twine &Label, unsigned EntriesNum);
 
   void printStackSizeEntry(uint64_t Size, ArrayRef<std::string> FuncNames,
-                           uint64_t Address) override;
+                           uint64_t Address,
+                           const StackSizeRelocation<ELFT> *Reloc) override;
 
   void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override;
   void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override;
@@ -811,9 +825,16 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
   void printProgramHeaders() override;
   void printSectionMapping() override {}
   void printStackSizeEntry(uint64_t Size, ArrayRef<std::string> FuncNames,
-                           uint64_t Address) override;
+                           uint64_t Address,
+                           const StackSizeRelocation<ELFT> *Reloc) override;
   void printCallGraphRelocation(const CallGraphFunc<ELFT> &Func,
                                 const Elf_Shdr &RelSec, const Elf_Shdr &SymTab);
+  // Prints R as a Relocation object: its symbol index, the name of its symbol
+  // Sym exactly as recorded in st_name if Sym could be read, and its addend.
+  // FieldValue is the value stored in the field that R applies to, which is
+  // the addend of a relocation without an explicit one.
+  void printRelocationObject(const Relocation<ELFT> &R, const Elf_Sym *Sym,
+                             const Elf_Shdr &SymTab, uint64_t FieldValue);
   // Returns the names of the functions at the address that the relocation for
   // Func resolves to. Sym is the symbol of the relocation, and only functions
   // in its section are looked up.
@@ -7238,7 +7259,8 @@ SmallVector<uint32_t> ELFDumper<ELFT>::getSymbolIndexesForFunctionAddress(
 template <class ELFT>
 bool ELFDumper<ELFT>::printFunctionStackSize(
     uint64_t SymValue, std::optional<const Elf_Shdr *> FunctionSec,
-    const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) {
+    const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset,
+    const StackSizeRelocation<ELFT> *Reloc) {
   // As in --call-graph-info, clear the Thumb bit, which is not part of the
   // function's address.
   if (Obj.getHeader().e_machine == ELF::EM_ARM)
@@ -7262,21 +7284,21 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
   }
 
   if (FuncSymIndexes.empty()) {
-    printStackSizeEntry(StackSize, {"?"}, SymValue);
+    printStackSizeEntry(StackSize, {"?"}, SymValue, Reloc);
   } else {
     SmallVector<std::string> FuncSymNames;
     for (uint32_t Index : FuncSymIndexes)
       FuncSymNames.push_back(this->getStaticSymbolName(Index));
-    printStackSizeEntry(StackSize, FuncSymNames, SymValue);
+    printStackSizeEntry(StackSize, FuncSymNames, SymValue, Reloc);
   }
 
   return true;
 }
 
 template <class ELFT>
-void GNUELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
-                                             ArrayRef<std::string> FuncNames,
-                                             uint64_t /*Address*/) {
+void GNUELFDumper<ELFT>::printStackSizeEntry(
+    uint64_t Size, ArrayRef<std::string> FuncNames, uint64_t /*Address*/,
+    const StackSizeRelocation<ELFT> * /*Reloc*/) {
   OS.PadToColumn(2);
   OS << format_decimal(Size, 11);
   OS.PadToColumn(18);
@@ -7331,11 +7353,12 @@ void ELFDumper<ELFT>::printStackSize(const Relocation<ELFT> &R,
     return;
   }
 
-  uint64_t SymValue = Resolver(R.Type, Offset, RelocSymValue,
-                               Data.getUnsigned(&Offset, sizeof(Elf_Addr)),
+  uint64_t FieldValue = Data.getUnsigned(&Offset, sizeof(Elf_Addr));
+  uint64_t SymValue = Resolver(R.Type, R.Offset, RelocSymValue, FieldValue,
                                R.Addend.value_or(0));
+  StackSizeRelocation<ELFT> Reloc{R, Sym, *SymTab, FieldValue};
   this->printFunctionStackSize(SymValue, FunctionSec, StackSizeSec, Data,
-                               &Offset);
+                               &Offset, &Reloc);
 }
 
 template <class ELFT>
@@ -7362,7 +7385,7 @@ void ELFDumper<ELFT>::printNonRelocatableStackSizes(
       }
       uint64_t SymValue = Data.getUnsigned(&Offset, sizeof(Elf_Addr));
       if (!printFunctionStackSize(SymValue, /*FunctionSec=*/std::nullopt, Sec,
-                                  Data, &Offset))
+                                  Data, &Offset, /*Reloc=*/nullptr))
         break;
     }
   }
@@ -8461,14 +8484,33 @@ void LLVMELFDumper<ELFT>::printCallGraphRelocation(
     const CallGraphFunc<ELFT> &Func, const Elf_Shdr &RelSec,
     const Elf_Shdr &SymTab) {
   const Relocation<ELFT> &R = *Func.Reloc;
+  const Elf_Sym *Sym = nullptr;
+  Expected<RelSymbol<ELFT>> TargetOrErr = this->getRelocationTarget(R, &SymTab);
+  if (!TargetOrErr)
+    this->reportUniqueWarning(TargetOrErr.takeError());
+  else
+    Sym = TargetOrErr->Sym;
+
+  // As with Address, Names comes before the Relocation object.
+  if (Sym) {
+    SmallVector<std::string> Names =
+        getCallGraphTargetNames(Func, RelSec, SymTab, *Sym);
+    if (!Names.empty())
+      W.printList("Names", Names);
+  }
+  printRelocationObject(R, Sym, SymTab, Func.FieldValue);
+}
+
+template <class ELFT>
+void LLVMELFDumper<ELFT>::printRelocationObject(const Relocation<ELFT> &R,
+                                                const Elf_Sym *Sym,
+                                                const Elf_Shdr &SymTab,
+                                                uint64_t FieldValue) {
   // Print the symbol name exactly as recorded in st_name. RelSymbol::Name is
   // not used because it is demangled with --demangle, and is made up from the
   // section name for an unnamed STT_SECTION symbol.
   StringRef SymbolName;
-  Expected<RelSymbol<ELFT>> TargetOrErr = this->getRelocationTarget(R, &SymTab);
-  if (!TargetOrErr) {
-    this->reportUniqueWarning(TargetOrErr.takeError());
-  } else if (const Elf_Sym *Sym = TargetOrErr->Sym) {
+  if (Sym) {
     Expected<StringRef> StrTabOrErr = this->Obj.getStringTableForSymtab(SymTab);
     if (!StrTabOrErr)
       this->reportUniqueWarning(StrTabOrErr.takeError());
@@ -8476,12 +8518,6 @@ void LLVMELFDumper<ELFT>::printCallGraphRelocation(
       SymbolName = *NameOrErr;
     else
       this->reportUniqueWarning(NameOrErr.takeError());
-
-    // As with Address, Names comes before the Relocation object.
-    SmallVector<std::string> Names =
-        getCallGraphTargetNames(Func, RelSec, SymTab, *Sym);
-    if (!Names.empty())
-      W.printList("Names", Names);
   }
 
   DictScope D(W, "Relocation");
@@ -8492,9 +8528,9 @@ void LLVMELFDumper<ELFT>::printCallGraphRelocation(
       W.printString("DemangledName", demangle(SymbolName));
   }
   // Without an explicit addend, e.g. for SHT_REL, the addend is the value
-  // stored in the address field.
+  // stored in the field.
   int64_t Addend = R.Addend.value_or(
-      SignExtend64<sizeof(typename ELFT::uint) * 8>(Func.FieldValue));
+      SignExtend64<sizeof(typename ELFT::uint) * 8>(FieldValue));
   if (Addend != 0)
     W.printNumber("Addend", Addend);
 }
@@ -9005,14 +9041,17 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printStackSizes() {
 }
 
 template <class ELFT>
-void LLVMELFDumper<ELFT>::printStackSizeEntry(uint64_t Size,
-                                              ArrayRef<std::string> FuncNames,
-                                              uint64_t Address) {
+void LLVMELFDumper<ELFT>::printStackSizeEntry(
+    uint64_t Size, ArrayRef<std::string> FuncNames, uint64_t Address,
+    const StackSizeRelocation<ELFT> *Reloc) {
   DictScope D(W, "Entry");
   W.printList("Functions", FuncNames);
-  // In a linked file, the function is identified by its address, as in
-  // --call-graph-info.
-  if (this->Obj.getHeader().e_type != ELF::ET_REL)
+  // As in --call-graph-info, the function is identified by the relocation for
+  // the entry in a relocatable file, and by its address otherwise.
+  if (Reloc)
+    printRelocationObject(Reloc->R, Reloc->Sym, Reloc->SymTab,
+                          Reloc->FieldValue);
+  else
     W.printHex("Address", Address);
   W.printHex("Size", Size);
 }

>From 505d75b4717882ad6ff41a29aeb1336dce2ce7c9 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 08:55:08 -0700
Subject: [PATCH 2/6] [llvm-readobj] Update the BPF stack sizes test for the
 Relocation object

Assisted-by: Gemini
---
 llvm/test/Object/BPF/yaml2obj-elf-bpf-rel.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/llvm/test/Object/BPF/yaml2obj-elf-bpf-rel.yaml b/llvm/test/Object/BPF/yaml2obj-elf-bpf-rel.yaml
index ca49ba87e940f..79aa536a1706e 100644
--- a/llvm/test/Object/BPF/yaml2obj-elf-bpf-rel.yaml
+++ b/llvm/test/Object/BPF/yaml2obj-elf-bpf-rel.yaml
@@ -12,6 +12,10 @@
 # CHECK:      StackSizes [
 # CHECK-NEXT:   Entry {
 # CHECK-NEXT:     Functions: [test]
+# CHECK-NEXT:     Relocation {
+# CHECK-NEXT:       SymbolIndex: 2
+# CHECK-NEXT:       SymbolName: .text
+# CHECK-NEXT:     }
 # CHECK-NEXT:     Size: 0x0
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]

>From 99665a257dc3d79c61aeb073ac42a687d3d0786a Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 14:33:17 -0700
Subject: [PATCH 3/6] Merge branch 'users/Prabhuk/stack-sizes/1-address' into
 users/Prabhuk/stack-sizes/2-relocation

---
 llvm/tools/llvm-readobj/ELFDumper.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 3b7ac5916ef11..4ae637d65147b 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -380,9 +380,10 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
                       unsigned Ndx, const Elf_Shdr *SymTab,
                       const Elf_Shdr *FunctionSec, const Elf_Shdr &StackSizeSec,
                       const RelocationResolver &Resolver, DataExtractor Data);
-  // Prints a stack size entry. Address is the function's address: the value
-  // stored in the entry in a linked file, or the value that its relocation
-  // resolves to in a relocatable file. Reloc is that relocation, if any.
+  /// Prints a stack size entry for the functions in \p FuncNames. \p Address
+  /// is the function's address: the value stored in the entry in a linked
+  /// file, or the value that its relocation resolves to in a relocatable file.
+  /// \p Reloc is that relocation, if any.
   virtual void printStackSizeEntry(uint64_t Size,
                                    ArrayRef<std::string> FuncNames,
                                    uint64_t Address,
@@ -7261,8 +7262,7 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
     uint64_t SymValue, std::optional<const Elf_Shdr *> FunctionSec,
     const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset,
     const StackSizeRelocation<ELFT> *Reloc) {
-  // As in --call-graph-info, clear the Thumb bit, which is not part of the
-  // function's address.
+  // Clear the Thumb bit, which is not part of the function's address.
   if (Obj.getHeader().e_machine == ELF::EM_ARM)
     SymValue &= ~1;
   SmallVector<uint32_t> FuncSymIndexes =
@@ -9046,8 +9046,8 @@ void LLVMELFDumper<ELFT>::printStackSizeEntry(
     const StackSizeRelocation<ELFT> *Reloc) {
   DictScope D(W, "Entry");
   W.printList("Functions", FuncNames);
-  // As in --call-graph-info, the function is identified by the relocation for
-  // the entry in a relocatable file, and by its address otherwise.
+  // The entry is identified by its relocation if it has one, and by the
+  // address stored in it otherwise.
   if (Reloc)
     printRelocationObject(Reloc->R, Reloc->Sym, Reloc->SymTab,
                           Reloc->FieldValue);

>From 6b350aeec6999ace79443226baba2912a9cd6500 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 14:33:18 -0700
Subject: [PATCH 4/6] Drop the redundant member comments of StackSizeRelocation

---
 llvm/tools/llvm-readobj/ELFDumper.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 4ae637d65147b..7a67fa0097346 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -230,13 +230,11 @@ template <class ELFT> struct FunctionCallGraphInfo {
 };
 
 // The relocation that applies to the address field of a .stack_sizes entry in
-// a relocatable file.
+// a relocatable file. Sym is null if the symbol could not be read.
 template <class ELFT> struct StackSizeRelocation {
   const Relocation<ELFT> &R;
-  // The symbol of the relocation, if it could be read, and its symbol table.
   const typename ELFT::Sym *Sym;
   const typename ELFT::Shdr &SymTab;
-  // The value stored in the address field.
   uint64_t FieldValue;
 };
 

>From 3da1bbc8eb067b26b99ce48aa067ad9035eb1c68 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 15:29:48 -0700
Subject: [PATCH 5/6] Drop the call graph reference from the SHT_REL test
 comment

---
 llvm/test/tools/llvm-readobj/ELF/stack-sizes.test | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
index a47caf19f52d0..4492cbbc3b1f8 100644
--- a/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
+++ b/llvm/test/tools/llvm-readobj/ELF/stack-sizes.test
@@ -1133,8 +1133,8 @@ Symbols:
 
 ## Check that on ARM the Thumb bit is also cleared from the address that a
 ## relocation resolves to, so that Thumb functions are found in relocatable
-## object files too. The addend of a SHT_REL relocation is the value stored in
-## the address field, as in --call-graph-info.
+## object files too. The Addend of a SHT_REL relocation is the value stored in
+## the address field.
 
 # RUN: yaml2obj --docnum=16 %s -o %t21
 # RUN: llvm-readelf --stack-sizes %t21 2>&1 | \

>From 5b4d58456c66904b495da4680b3f9a268a75dc38 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 15 Oct 2026 15:47:56 -0700
Subject: [PATCH 6/6] Fold the Names block into the else branch

---
 llvm/tools/llvm-readobj/ELFDumper.cpp | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index a3e508456eb1c..95eddb18e487b 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -8487,13 +8487,10 @@ void LLVMELFDumper<ELFT>::printCallGraphRelocation(
   const Relocation<ELFT> &R = *Func.Reloc;
   const Elf_Sym *Sym = nullptr;
   Expected<RelSymbol<ELFT>> TargetOrErr = this->getRelocationTarget(R, &SymTab);
-  if (!TargetOrErr)
+  if (!TargetOrErr) {
     this->reportUniqueWarning(TargetOrErr.takeError());
-  else
-    Sym = TargetOrErr->Sym;
-
-  // As with Address, Names comes before the Relocation object.
-  if (Sym) {
+  } else if ((Sym = TargetOrErr->Sym)) {
+    // As with Address, Names comes before the Relocation object.
     SmallVector<std::string> Names =
         getCallGraphTargetNames(Func, RelSec, SymTab, *Sym);
     if (!Names.empty())



More information about the llvm-branch-commits mailing list