[PATCH v2 1/5] readelf: fold get_{32,64}bit_program_headers()

Jan Beulich <[email protected]> Fri, 31 Jul 2026 14:10:37 +0200
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
PR binutils/34356

They're identical except for the types used and the order of fields
processed. The latter doesn't matter for correctness, and the former can
be addressed by compiling the same code twice.
---
v2: Use new file readelf-nn.c.

--- a/binutils/Makefile.am
+++ b/binutils/Makefile.am
@@ -141,7 +141,7 @@ CFILES = \
 	nm.c not-ranlib.c not-strip.c \
 	objcopy.c objdump.c prdbg.c \
 	od-elf32_avr.c od-macho.c od-pe.c od-xcoff.c \
-	rclex.c rdcoff.c rddbg.c readelf.c rename.c \
+	rclex.c rdcoff.c rddbg.c readelf.c readelf-nn.c rename.c \
 	resbin.c rescoff.c resrc.c resres.c \
 	size.c srconv.c stabs.c strings.c sysdump.c \
 	syslex_wrap.c unwind-ia64.c elfedit.c version.c \
@@ -385,7 +385,7 @@ endif
 	$(AM_V_CC)$(COMPILE) $(DEBUGINFOD_CFLAGS) -c -o $@ $(srcdir)/dwarf.c
 endif
 
-readelf.@OBJEXT@: readelf.c
+readelf.@OBJEXT@: readelf.c readelf-nn.c
 if am__fastdepCC
 	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo $(MSGPACK_CFLAGS) -c -o $@ $(srcdir)/readelf.c
 	$(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -724,7 +724,7 @@ CFILES = \
 	nm.c not-ranlib.c not-strip.c \
 	objcopy.c objdump.c prdbg.c \
 	od-elf32_avr.c od-macho.c od-pe.c od-xcoff.c \
-	rclex.c rdcoff.c rddbg.c readelf.c rename.c \
+	rclex.c rdcoff.c rddbg.c readelf.c readelf-nn.c rename.c \
 	resbin.c rescoff.c resrc.c resres.c \
 	size.c srconv.c stabs.c strings.c sysdump.c \
 	syslex_wrap.c unwind-ia64.c elfedit.c version.c \
@@ -1196,6 +1196,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcparse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdcoff.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rddbg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readelf-nn.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readelf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rename.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resbin.Po@am__quote@
@@ -1936,7 +1937,7 @@ dwarf.@OBJEXT@: dwarf.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC)$(COMPILE) $(DEBUGINFOD_CFLAGS) -c -o $@ $(srcdir)/dwarf.c
 
-readelf.@OBJEXT@: readelf.c
+readelf.@OBJEXT@: readelf.c readelf-nn.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo $(MSGPACK_CFLAGS) -c -o $@ $(srcdir)/readelf.c
 @am__fastdepCC_TRUE@	$(AM_V_at)mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	source='readelf.c' object='$@' libtool=no @AMDEPBACKSLASH@
--- a/binutils/po/POTFILES.in
+++ b/binutils/po/POTFILES.in
@@ -50,6 +50,7 @@ rdcoff.c
 rddbg.c
 rddbg.c
 readelf.c
+readelf-nn.c
 rename.c
 resbin.c
 rescoff.c
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -3469,6 +3469,11 @@ get_dynamic_type (Filedata * filedata, u
     }
 }
 
+#define ElfXX(n) Elf32 ## n
+#include "readelf-nn.c"
+#define ElfXX(n) Elf64 ## n
+#include "readelf-nn.c"
+
 static bool get_program_headers (Filedata *);
 static bool get_dynamic_section (Filedata *);
 
@@ -7366,100 +7371,6 @@ process_file_header (Filedata * filedata
   return true;
 }
 
-/* Read in the program headers from FILEDATA and store them in PHEADERS.
-   Returns TRUE upon success, FALSE otherwise.  Loads 32-bit headers.  */
-
-static bool
-get_32bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
-{
-  Elf32_External_Phdr * phdrs;
-  Elf32_External_Phdr * external;
-  Elf_Internal_Phdr *   internal;
-  unsigned int i;
-  unsigned int size = filedata->file_header.e_phentsize;
-  unsigned int num  = filedata->file_header.e_phnum;
-
-  /* PR binutils/17531: Cope with unexpected section header sizes.  */
-  if (size == 0 || num == 0)
-    return false;
-  if (size < sizeof * phdrs)
-    {
-      error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
-      return false;
-    }
-  if (size > sizeof * phdrs)
-    warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
-
-  phdrs = (Elf32_External_Phdr *) get_data (NULL, filedata, filedata->file_header.e_phoff,
-                                            size, num, _("program headers"));
-  if (phdrs == NULL)
-    return false;
-
-  for (i = 0, internal = pheaders, external = phdrs;
-       i < filedata->file_header.e_phnum;
-       i++, internal++, external++)
-    {
-      internal->p_type   = BYTE_GET (external->p_type);
-      internal->p_offset = BYTE_GET (external->p_offset);
-      internal->p_vaddr  = BYTE_GET (external->p_vaddr);
-      internal->p_paddr  = BYTE_GET (external->p_paddr);
-      internal->p_filesz = BYTE_GET (external->p_filesz);
-      internal->p_memsz  = BYTE_GET (external->p_memsz);
-      internal->p_flags  = BYTE_GET (external->p_flags);
-      internal->p_align  = BYTE_GET (external->p_align);
-    }
-
-  free (phdrs);
-  return true;
-}
-
-/* Read in the program headers from FILEDATA and store them in PHEADERS.
-   Returns TRUE upon success, FALSE otherwise.  Loads 64-bit headers.  */
-
-static bool
-get_64bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
-{
-  Elf64_External_Phdr * phdrs;
-  Elf64_External_Phdr * external;
-  Elf_Internal_Phdr *   internal;
-  unsigned int i;
-  unsigned int size = filedata->file_header.e_phentsize;
-  unsigned int num  = filedata->file_header.e_phnum;
-
-  /* PR binutils/17531: Cope with unexpected section header sizes.  */
-  if (size == 0 || num == 0)
-    return false;
-  if (size < sizeof * phdrs)
-    {
-      error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
-      return false;
-    }
-  if (size > sizeof * phdrs)
-    warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
-
-  phdrs = (Elf64_External_Phdr *) get_data (NULL, filedata, filedata->file_header.e_phoff,
-                                            size, num, _("program headers"));
-  if (!phdrs)
-    return false;
-
-  for (i = 0, internal = pheaders, external = phdrs;
-       i < filedata->file_header.e_phnum;
-       i++, internal++, external++)
-    {
-      internal->p_type   = BYTE_GET (external->p_type);
-      internal->p_flags  = BYTE_GET (external->p_flags);
-      internal->p_offset = BYTE_GET (external->p_offset);
-      internal->p_vaddr  = BYTE_GET (external->p_vaddr);
-      internal->p_paddr  = BYTE_GET (external->p_paddr);
-      internal->p_filesz = BYTE_GET (external->p_filesz);
-      internal->p_memsz  = BYTE_GET (external->p_memsz);
-      internal->p_align  = BYTE_GET (external->p_align);
-    }
-
-  free (phdrs);
-  return true;
-}
-
 /* Returns TRUE if the program headers were read into `program_headers'.  */
 
 static bool
@@ -7492,8 +7403,8 @@ get_program_headers (Filedata * filedata
     }
 
   if (is_32bit_elf
-      ? get_32bit_program_headers (filedata, phdrs)
-      : get_64bit_program_headers (filedata, phdrs))
+      ? Elf32_get_program_headers (filedata, phdrs)
+      : Elf64_get_program_headers (filedata, phdrs))
     {
       filedata->program_headers = phdrs;
       return true;
--- /dev/null
+++ b/binutils/readelf-nn.c
@@ -0,0 +1,90 @@
+/* readelf-nn.c -- ELF32 / ELF64 helper of readelf.c
+   Copyright (C) 1998-2026 Free Software Foundation, Inc.
+
+   Originally developed by Eric Youngdale <[email protected]>
+   Modifications by Nick Clifton <[email protected]>
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* The difference between readelf and objdump:
+
+  Both programs are capable of displaying the contents of ELF format files,
+  so why does the binutils project have two file dumpers ?
+
+  The reason is that objdump sees an ELF file through a BFD filter of the
+  world; if BFD has a bug where, say, it disagrees about a machine constant
+  in e_flags, then the odds are good that it will remain internally
+  consistent.  The linker sees it the BFD way, objdump sees it the BFD way,
+  GAS sees it the BFD way.  There was need for a tool to go find out what
+  the file actually says.
+
+  This is why the readelf program does not link against the BFD library - it
+  exists as an independent program to help verify the correct working of BFD.
+
+  There is also the case that readelf can provide more information about an
+  ELF file than is provided by objdump.  In particular it can display DWARF
+  debugging information which (at the moment) objdump cannot.  */
+
+/* Read in the program headers from FILEDATA and store them in PHEADERS.
+   Returns TRUE upon success, FALSE otherwise.  */
+
+static bool
+ElfXX(_get_program_headers) (Filedata * filedata, Elf_Internal_Phdr * pheaders)
+{
+  ElfXX(_External_Phdr) * phdrs;
+  const ElfXX(_External_Phdr) * external;
+  Elf_Internal_Phdr *   internal;
+  unsigned int i;
+  unsigned int size = filedata->file_header.e_phentsize;
+  unsigned int num  = filedata->file_header.e_phnum;
+
+  /* PR binutils/17531: Cope with unexpected section header sizes.  */
+  if (size == 0 || num == 0)
+    return false;
+  if (size < sizeof * phdrs)
+    {
+      error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
+      return false;
+    }
+  if (size > sizeof * phdrs)
+    warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
+
+  phdrs = get_data (NULL, filedata, filedata->file_header.e_phoff, size, num,
+		    _("program headers"));
+  if (phdrs == NULL)
+    return false;
+
+  for (i = 0, internal = pheaders, external = phdrs;
+       i < filedata->file_header.e_phnum;
+       i++, internal++, external++)
+    {
+      internal->p_type   = BYTE_GET (external->p_type);
+      internal->p_offset = BYTE_GET (external->p_offset);
+      internal->p_vaddr  = BYTE_GET (external->p_vaddr);
+      internal->p_paddr  = BYTE_GET (external->p_paddr);
+      internal->p_filesz = BYTE_GET (external->p_filesz);
+      internal->p_memsz  = BYTE_GET (external->p_memsz);
+      internal->p_flags  = BYTE_GET (external->p_flags);
+      internal->p_align  = BYTE_GET (external->p_align);
+    }
+
+  free (phdrs);
+  return true;
+}
+
+#undef ElfXX