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

Message ID abc0183b-f794-435a-acb3-98a05e0b2bbd@suse.com
State New
Headers
Series readelf: reduce code duplication a little |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed

Commit Message

Jan Beulich July 27, 2026, 9:19 a.m. UTC
  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.
  

Comments

H.J. Lu July 27, 2026, 11:20 a.m. UTC | #1
On Mon, Jul 27, 2026 at 5:20 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> 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.
>
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -40,6 +40,8 @@
>    ELF file than is provided by objdump.  In particular it can display DWARF
>    debugging information which (at the moment) objdump cannot.  */
>
> +#ifndef ElfXX
> +
>  #include "sysdep.h"
>  #include <assert.h>
>  #include <time.h>
> @@ -7366,14 +7368,21 @@ process_file_header (Filedata * filedata
>    return true;
>  }
>
> +#define ElfXX(n) Elf32 ## n
> +#include "readelf.c"
> +#define ElfXX(n) Elf64 ## n
> +#include "readelf.c"

Can we extract this piece code into readelf.h and include
readelf.h instead?

> +#else /* ElfXX */
> +
>  /* Read in the program headers from FILEDATA and store them in PHEADERS.
> -   Returns TRUE upon success, FALSE otherwise.  Loads 32-bit headers.  */
> +   Returns TRUE upon success, FALSE otherwise.  */
>
>  static bool
> -get_32bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
> +ElfXX(_get_program_headers) (Filedata * filedata, Elf_Internal_Phdr * pheaders)
>  {
> -  Elf32_External_Phdr * phdrs;
> -  Elf32_External_Phdr * external;
> +  ElfXX(_External_Phdr) * phdrs;
> +  const ElfXX(_External_Phdr) * external;
>    Elf_Internal_Phdr *   internal;
>    unsigned int i;
>    unsigned int size = filedata->file_header.e_phentsize;
> @@ -7390,8 +7399,8 @@ get_32bit_program_headers (Filedata * fi
>    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"));
> +  phdrs = get_data (NULL, filedata, filedata->file_header.e_phoff, size, num,
> +                   _("program headers"));
>    if (phdrs == NULL)
>      return false;
>
> @@ -7413,52 +7422,9 @@ get_32bit_program_headers (Filedata * fi
>    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);
> -    }
> +#endif /* ElfXX */
>
> -  free (phdrs);
> -  return true;
> -}
> +#ifndef ElfXX
>
>  /* Returns TRUE if the program headers were read into `program_headers'.  */
>
> @@ -7492,8 +7458,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;
> @@ -25618,3 +25584,7 @@ main (int argc, char ** argv)
>
>    return err ? EXIT_FAILURE : EXIT_SUCCESS;
>  }
> +
> +#endif /* ElfXX */
> +
> +#undef ElfXX
>
  
Jan Beulich July 27, 2026, 11:24 a.m. UTC | #2
On 27.07.2026 13:20, H.J. Lu wrote:
> On Mon, Jul 27, 2026 at 5:20 PM Jan Beulich <jbeulich@suse.com> wrote:
>>
>> 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.
>>
>> --- a/binutils/readelf.c
>> +++ b/binutils/readelf.c
>> @@ -40,6 +40,8 @@
>>    ELF file than is provided by objdump.  In particular it can display DWARF
>>    debugging information which (at the moment) objdump cannot.  */
>>
>> +#ifndef ElfXX
>> +
>>  #include "sysdep.h"
>>  #include <assert.h>
>>  #include <time.h>
>> @@ -7366,14 +7368,21 @@ process_file_header (Filedata * filedata
>>    return true;
>>  }
>>
>> +#define ElfXX(n) Elf32 ## n
>> +#include "readelf.c"
>> +#define ElfXX(n) Elf64 ## n
>> +#include "readelf.c"
> 
> Can we extract this piece code into readelf.h and include
> readelf.h instead?

I'm sure we (technically) could, but I'm unconvinced we should. Personally
I don't consider such a valid use of "header files". I did consider adding
a new .c file, but I couldn't think of a name which I would be at least
reasonably okay with.

Jan
  
Andreas Schwab July 27, 2026, 11:56 a.m. UTC | #3
On Jul 27 2026, Jan Beulich wrote:

> I did consider adding
> a new .c file, but I couldn't think of a name which I would be at least
> reasonably okay with.

Perhaps following the pattern in bfd: readelf-nn.c
  
Jan Beulich July 27, 2026, 12:08 p.m. UTC | #4
On 27.07.2026 13:56, Andreas Schwab wrote:
> On Jul 27 2026, Jan Beulich wrote:
> 
>> I did consider adding
>> a new .c file, but I couldn't think of a name which I would be at least
>> reasonably okay with.
> 
> Perhaps following the pattern in bfd: readelf-nn.c

And then also generate readelf-32.c and readelf-64.c from it? I'd like to
avoid introducing new generated files, whenever possible.

Jan
  
H.J. Lu July 27, 2026, 12:12 p.m. UTC | #5
On Mon, Jul 27, 2026 at 8:08 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 27.07.2026 13:56, Andreas Schwab wrote:
> > On Jul 27 2026, Jan Beulich wrote:
> >
> >> I did consider adding
> >> a new .c file, but I couldn't think of a name which I would be at least
> >> reasonably okay with.
> >
> > Perhaps following the pattern in bfd: readelf-nn.c
>
> And then also generate readelf-32.c and readelf-64.c from it? I'd like to
> avoid introducing new generated files, whenever possible.
>

You don't need to generate readelf-32.c and readelf-64.c.
You can just include readelf-nn.c twice.
  
Jan Beulich July 27, 2026, 12:15 p.m. UTC | #6
On 27.07.2026 14:12, H.J. Lu wrote:
> On Mon, Jul 27, 2026 at 8:08 PM Jan Beulich <jbeulich@suse.com> wrote:
>>
>> On 27.07.2026 13:56, Andreas Schwab wrote:
>>> On Jul 27 2026, Jan Beulich wrote:
>>>
>>>> I did consider adding
>>>> a new .c file, but I couldn't think of a name which I would be at least
>>>> reasonably okay with.
>>>
>>> Perhaps following the pattern in bfd: readelf-nn.c
>>
>> And then also generate readelf-32.c and readelf-64.c from it? I'd like to
>> avoid introducing new generated files, whenever possible.
> 
> You don't need to generate readelf-32.c and readelf-64.c.
> You can just include readelf-nn.c twice.

Of course I can; the question was solely towards Andreas making an analogy
with bfd/. Similar naming decisions may better (but don't need to) be used
together with similar coding approaches.

Jan
  

Patch

--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -40,6 +40,8 @@ 
   ELF file than is provided by objdump.  In particular it can display DWARF
   debugging information which (at the moment) objdump cannot.  */
 
+#ifndef ElfXX
+
 #include "sysdep.h"
 #include <assert.h>
 #include <time.h>
@@ -7366,14 +7368,21 @@  process_file_header (Filedata * filedata
   return true;
 }
 
+#define ElfXX(n) Elf32 ## n
+#include "readelf.c"
+#define ElfXX(n) Elf64 ## n
+#include "readelf.c"
+
+#else /* ElfXX */
+
 /* Read in the program headers from FILEDATA and store them in PHEADERS.
-   Returns TRUE upon success, FALSE otherwise.  Loads 32-bit headers.  */
+   Returns TRUE upon success, FALSE otherwise.  */
 
 static bool
-get_32bit_program_headers (Filedata * filedata, Elf_Internal_Phdr * pheaders)
+ElfXX(_get_program_headers) (Filedata * filedata, Elf_Internal_Phdr * pheaders)
 {
-  Elf32_External_Phdr * phdrs;
-  Elf32_External_Phdr * external;
+  ElfXX(_External_Phdr) * phdrs;
+  const ElfXX(_External_Phdr) * external;
   Elf_Internal_Phdr *   internal;
   unsigned int i;
   unsigned int size = filedata->file_header.e_phentsize;
@@ -7390,8 +7399,8 @@  get_32bit_program_headers (Filedata * fi
   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"));
+  phdrs = get_data (NULL, filedata, filedata->file_header.e_phoff, size, num,
+		    _("program headers"));
   if (phdrs == NULL)
     return false;
 
@@ -7413,52 +7422,9 @@  get_32bit_program_headers (Filedata * fi
   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);
-    }
+#endif /* ElfXX */
 
-  free (phdrs);
-  return true;
-}
+#ifndef ElfXX
 
 /* Returns TRUE if the program headers were read into `program_headers'.  */
 
@@ -7492,8 +7458,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;
@@ -25618,3 +25584,7 @@  main (int argc, char ** argv)
 
   return err ? EXIT_FAILURE : EXIT_SUCCESS;
 }
+
+#endif /* ElfXX */
+
+#undef ElfXX