[PATCH] elfedit: add support for editing e_flags

Xi Ruoyao xry111@xry111.site
Thu Mar 2 08:20:20 GMT 2023


On Thu, 2023-03-02 at 16:01 +0800, WANG Xuerui wrote:

> I have to pick up the work because I was trying to make AMDGPU DCN work
> on LoongArch, but that piece of code requires hard-float support while
> the LoongArch Linux kernel is compiled in the soft-float ABI, leading to
> link-time failures intermixing the two.

IMO we should keep soft-float ABI while enabling the FPU (i. e.
-mabi=lp64s -mfpu=64).  But ouch, this does not work properly with
current GCC...  -mfpu=64 silently enables using FPR to pass arg and
return value, w/o even a warning.  Not sure about Clang.

<rant>I remember I've been saying "floating ABI and floating instruction
set should be de-coupled" multiple times: "I" in "ABI" stands for
"interface" anyway and all the interfaces are just designed for hiding
implementation details.  But it seems nobody took it seriously.</rant>

> Since the hard-float code in
> question doesn't pass around FP arguments across the boundary between
> object files, but rather only internally, it is safe to just edit the
> e_flags of the hard-float objects to make their ABI look like LP64S.
> Which led to me discovering the previous similar work [1] has stalled...
> And that's why a bunch of LoongArch-related folks are on the CC list.
> 
> [1]: https://sourceware.org/pipermail/binutils/2022-April/120413.html
> 
>  binutils/doc/binutils.texi                  | 13 +++++-
>  binutils/elfedit.c                          | 52 +++++++++++++++++++-
> -
>  binutils/testsuite/binutils-all/elfedit-7.d | 10 ++++
>  binutils/testsuite/binutils-all/elfedit-8.d | 10 ++++
>  binutils/testsuite/binutils-all/elfedit.exp |  2 +
>  5 files changed, 83 insertions(+), 4 deletions(-)
>  create mode 100644 binutils/testsuite/binutils-all/elfedit-7.d
>  create mode 100644 binutils/testsuite/binutils-all/elfedit-8.d
> 
> diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
> index b1982a95704..a261af48254 100644
> --- a/binutils/doc/binutils.texi
> +++ b/binutils/doc/binutils.texi
> @@ -5297,10 +5297,12 @@ elfedit [@option{--input-mach=}@var{machine}]
>          [@option{--input-type=}@var{type}]
>          [@option{--input-osabi=}@var{osabi}]
>          [@option{--input-abiversion=}@var{version}]
> +        [@option{--input-flags=}@var{flags}]
>          @option{--output-mach=}@var{machine}
>          @option{--output-type=}@var{type}
>          @option{--output-osabi=}@var{osabi}
>          @option{--output-abiversion=}@var{version}
> +        @option{--output-flags=}@var{flags}
>          @option{--enable-x86-feature=}@var{feature}
>          @option{--disable-x86-feature=}@var{feature}
>          [@option{-v}|@option{--version}]
> @@ -5325,7 +5327,7 @@ should be updated.
>  The long and short forms of options, shown here as alternatives, are
>  equivalent. At least one of the @option{--output-mach},
>  @option{--output-type}, @option{--output-osabi},
> -@option{--output-abiversion},
> +@option{--output-abiversion}, @option{--output-flags},
>  @option{--enable-x86-feature} and @option{--disable-x86-feature}
>  options must be given.
>  
> @@ -5376,6 +5378,15 @@ isn't specified, it will match any ELF
> ABIVERSIONs.
>  Change the ELF ABIVERSION in the ELF header to @var{version}.
>  @var{version} must be between 0 and 255.
>  
> +@item --input-flags=@var{flags}
> +Set the matching input ELF file @var{e_flags} value to @var{flags}.
> +@var{flags} must be an unsigned 32-bit integer.  If @option{--input-
> flags}
> +isn't specified, it will match any e_flags value.
> +
> +@item --output-flags=@var{flags}
> +Change the @var{e_flags} field in the ELF header to @var{flags}.
> +@var{version} must be an unsigned 32-bit integer.
> +
>  @item --enable-x86-feature=@var{feature}
>  Set the @var{feature} bit in program property in @var{exec} or
> @var{dyn}
>  ELF files with machine types of @var{i386} or @var{x86-64}.  The
> diff --git a/binutils/elfedit.c b/binutils/elfedit.c
> index 117e67639a0..512e075f16a 100644
> --- a/binutils/elfedit.c
> +++ b/binutils/elfedit.c
> @@ -68,6 +68,10 @@ enum elfclass
>    };
>  static enum elfclass input_elf_class = ELF_CLASS_UNKNOWN;
>  static enum elfclass output_elf_class = ELF_CLASS_BOTH;
> +static int check_elf_flags = 0;
> +static unsigned long input_elf_flags = 0;
> +static int write_elf_flags = 0;
> +static unsigned long output_elf_flags = 0;
>  
>  #ifdef HAVE_MMAP
>  #include <sys/mman.h>
> @@ -394,7 +398,16 @@ update_elf_header (const char *file_name, FILE
> *file)
>        return 0;
>      }
>  
> -  /* Update e_machine, e_type and EI_OSABI.  */
> +  /* Skip if e_flags doesn't match. */
> +  if (check_elf_flags && elf_header.e_flags != input_elf_flags)
> +    {
> +      error
> +       (_("%s: Unmatched e_flags: 0x%lx is not 0x%lx\n"),
> +        file_name, elf_header.e_flags, input_elf_flags);
> +      return 0;
> +    }
> +
> +  /* Update e_machine, e_type, OSABI, ABIVERSION and e_flags.  */
>    switch (class)
>      {
>      default:
> @@ -410,6 +423,8 @@ update_elf_header (const char *file_name, FILE
> *file)
>         ehdr32.e_ident[EI_OSABI] = output_elf_osabi;
>        if (output_elf_abiversion != -1)
>         ehdr32.e_ident[EI_ABIVERSION] = output_elf_abiversion;
> +      if (write_elf_flags)
> +       BYTE_PUT (ehdr32.e_flags, output_elf_flags);
>        status = fwrite (&ehdr32, sizeof (ehdr32), 1, file) == 1;
>        break;
>      case ELFCLASS64:
> @@ -421,6 +436,8 @@ update_elf_header (const char *file_name, FILE
> *file)
>         ehdr64.e_ident[EI_OSABI] = output_elf_osabi;
>        if (output_elf_abiversion != -1)
>         ehdr64.e_ident[EI_ABIVERSION] = output_elf_abiversion;
> +      if (write_elf_flags)
> +       BYTE_PUT (ehdr64.e_flags, output_elf_flags);
>        status = fwrite (&ehdr64, sizeof (ehdr64), 1, file) == 1;
>        break;
>      }
> @@ -904,6 +921,8 @@ enum command_line_switch
>      OPTION_OUTPUT_OSABI,
>      OPTION_INPUT_ABIVERSION,
>      OPTION_OUTPUT_ABIVERSION,
> +    OPTION_INPUT_FLAGS,
> +    OPTION_OUTPUT_FLAGS,
>  #ifdef HAVE_MMAP
>      OPTION_ENABLE_X86_FEATURE,
>      OPTION_DISABLE_X86_FEATURE,
> @@ -920,6 +939,8 @@ static struct option options[] =
>    {"output-osabi",     required_argument, 0, OPTION_OUTPUT_OSABI},
>    {"input-abiversion", required_argument, 0,
> OPTION_INPUT_ABIVERSION},
>    {"output-abiversion",        required_argument, 0,
> OPTION_OUTPUT_ABIVERSION},
> +  {"input-flags",      required_argument, 0, OPTION_INPUT_FLAGS},
> +  {"output-flags",     required_argument, 0, OPTION_OUTPUT_FLAGS},
>  #ifdef HAVE_MMAP
>    {"enable-x86-feature",
>                         required_argument, 0,
> OPTION_ENABLE_X86_FEATURE},
> @@ -958,7 +979,11 @@ usage (FILE *stream, int exit_status)
>    --output-osabi [%s]\n\
>                                Set output OSABI\n\
>    --input-abiversion [0-255]  Set input ABIVERSION\n\
> -  --output-abiversion [0-255] Set output ABIVERSION\n"),
> +  --output-abiversion [0-255] Set output ABIVERSION\n\
> +  --input-flags [32-bit unsigned integer]\n\
> +                              Set input e_flags\n\
> +  --output-flags [32-bit unsigned integer]\n\
> +                              Set output e_flags\n"),
>            osabi, osabi);
>  #ifdef HAVE_MMAP
>    fprintf (stream, _("\
> @@ -1062,6 +1087,26 @@ main (int argc, char ** argv)
>             }
>           break;
>  
> +       case OPTION_INPUT_FLAGS:
> +         check_elf_flags = 1;
> +         input_elf_flags = strtoul (optarg, &end, 0);
> +         if (*end != '\0' || input_elf_flags > 0xffffffff)
> +           {
> +             error (_("Invalid e_flags: %s\n"), optarg);
> +             return 1;
> +           }
> +         break;
> +
> +       case OPTION_OUTPUT_FLAGS:
> +         write_elf_flags = 1;
> +         output_elf_flags = strtoul (optarg, &end, 0);
> +         if (*end != '\0' || output_elf_flags > 0xffffffff)
> +           {
> +             error (_("Invalid e_flags: %s\n"), optarg);
> +             return 1;
> +           }
> +         break;
> +
>  #ifdef HAVE_MMAP
>         case OPTION_ENABLE_X86_FEATURE:
>           if (elf_x86_feature (optarg, 1) < 0)
> @@ -1094,7 +1139,8 @@ main (int argc, char ** argv)
>  #endif
>           && output_elf_type == -1
>           && output_elf_osabi == -1
> -         && output_elf_abiversion == -1))
> +         && output_elf_abiversion == -1
> +         && ! write_elf_flags))
>      usage (stderr, 1);
>  
>    status = 0;
> diff --git a/binutils/testsuite/binutils-all/elfedit-7.d
> b/binutils/testsuite/binutils-all/elfedit-7.d
> new file mode 100644
> index 00000000000..8e5a8b7d019
> --- /dev/null
> +++ b/binutils/testsuite/binutils-all/elfedit-7.d
> @@ -0,0 +1,10 @@
> +#PROG: elfedit
> +#elfedit: --output-flags 0xfedcba98
> +#source: empty.s
> +#readelf: -h
> +#name: Update ELF header 7 (hexadecimal e_flags value)
> +#target: *-*-linux* *-*-gnu*
> +
> +#...
> +  Flags:[ \t]+0xfedcba98.*
> +#...
> diff --git a/binutils/testsuite/binutils-all/elfedit-8.d
> b/binutils/testsuite/binutils-all/elfedit-8.d
> new file mode 100644
> index 00000000000..9538f4486b8
> --- /dev/null
> +++ b/binutils/testsuite/binutils-all/elfedit-8.d
> @@ -0,0 +1,10 @@
> +#PROG: elfedit
> +#elfedit: --output-flags 12345678
> +#source: empty.s
> +#readelf: -h
> +#name: Update ELF header 8 (decimal e_flags value)
> +#target: *-*-linux* *-*-gnu*
> +
> +#...
> +  Flags:[ \t]+0xbc614e.*
> +#...
> diff --git a/binutils/testsuite/binutils-all/elfedit.exp
> b/binutils/testsuite/binutils-all/elfedit.exp
> index 33f4bb05529..47e94e5a775 100644
> --- a/binutils/testsuite/binutils-all/elfedit.exp
> +++ b/binutils/testsuite/binutils-all/elfedit.exp
> @@ -26,3 +26,5 @@ run_dump_test "elfedit-3"
>  run_dump_test "elfedit-4"
>  run_dump_test "elfedit-5"
>  run_dump_test "elfedit-6"
> +run_dump_test "elfedit-7"
> +run_dump_test "elfedit-8"

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University


More information about the Binutils mailing list