* [PATCH RESEND] elfedit: add support for editing e_flags
@ 2023-03-02 8:14 WANG Xuerui
2023-03-02 8:58 ` Jan Beulich
0 siblings, 1 reply; 3+ messages in thread
From: WANG Xuerui @ 2023-03-02 8:14 UTC (permalink / raw)
To: binutils; +Cc: Chenghua Xu, Zhensong Liu, Qinggang Meng, Xi Ruoyao, WANG Xuerui
From: WANG Xuerui <git@xen0n.name>
Add a pair of elfedit options (--{input,output}-flags) for manipulating
files' e_flags field. This is useful in certain cases, e.g. if you know
what you are doing and have to make some object files look as if
compiled for a different architecture or ABI variant.
---
(Resending because I've overlooked sizeof(output_elf_flags). I wondered
how BYTE_PUT is so smart to figure out the sizes until I've discovered
its *local* definition *after* hitting send...)
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. 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 | 55 +++++++++++++++++++--
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, 86 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..8939198c415 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 int input_elf_flags = 0;
+static int write_elf_flags = 0;
+static unsigned int 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%x\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, _("\
@@ -983,6 +1008,7 @@ main (int argc, char ** argv)
{
int c, status;
char *end;
+ unsigned long tmp;
#ifdef HAVE_LC_MESSAGES
setlocale (LC_MESSAGES, "");
@@ -1062,6 +1088,28 @@ main (int argc, char ** argv)
}
break;
+ case OPTION_INPUT_FLAGS:
+ check_elf_flags = 1;
+ tmp = strtoul (optarg, &end, 0);
+ if (*end != '\0' || tmp > 0xffffffff)
+ {
+ error (_("Invalid e_flags: %s\n"), optarg);
+ return 1;
+ }
+ input_elf_flags = (unsigned int) tmp;
+ break;
+
+ case OPTION_OUTPUT_FLAGS:
+ write_elf_flags = 1;
+ tmp = strtoul (optarg, &end, 0);
+ if (*end != '\0' || tmp > 0xffffffff)
+ {
+ error (_("Invalid e_flags: %s\n"), optarg);
+ return 1;
+ }
+ output_elf_flags = (unsigned int) tmp;
+ break;
+
#ifdef HAVE_MMAP
case OPTION_ENABLE_X86_FEATURE:
if (elf_x86_feature (optarg, 1) < 0)
@@ -1094,7 +1142,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"
--
2.39.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH RESEND] elfedit: add support for editing e_flags
2023-03-02 8:14 [PATCH RESEND] elfedit: add support for editing e_flags WANG Xuerui
@ 2023-03-02 8:58 ` Jan Beulich
2023-03-02 9:02 ` Jan Beulich
0 siblings, 1 reply; 3+ messages in thread
From: Jan Beulich @ 2023-03-02 8:58 UTC (permalink / raw)
To: WANG Xuerui
Cc: Chenghua Xu, Zhensong Liu, Qinggang Meng, Xi Ruoyao, WANG Xuerui,
binutils
On 02.03.2023 09:14, WANG Xuerui wrote:
> @@ -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.
This doesn't really explain what the behavior is; I had to look at the code
to see what's intended. However, ...
> +@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.
... instead of this pair of options, for anything flags-ish wouldn't it be
more convenient to have a way to merely specify a flags-to-clear and a flags-
to-set value? That would imo also eliminate the need for checking that the
input object's flags match a certain value.
> @@ -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%x\n"),
May I suggest to use %#x (and alike) wherever suitable? It's a shorter
string literal and doesn't needlessly clutter the value of 0 with a 0x
prefix.
> @@ -1062,6 +1088,28 @@ main (int argc, char ** argv)
> }
> break;
>
> + case OPTION_INPUT_FLAGS:
> + check_elf_flags = 1;
Please use bool/true/false for boolean variables.
> + tmp = strtoul (optarg, &end, 0);
> + if (*end != '\0' || tmp > 0xffffffff)
I'm afraid this may trigger compiler warnings: For one because the constant
isn't flagged as unsigned. And then (for 32-bit targets) for being an
always-true comparison.
> --- /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*
Any reason *-*-elf* isn't included here? But I guess you really want to
use [is_elf_format] anyway.
Also neither of the two tests uses the other option. If that's to remain,
I think it wants testing (I realize that doing so may require further
limiting the targets on which such a test can be easily run).
Jan
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH RESEND] elfedit: add support for editing e_flags
2023-03-02 8:58 ` Jan Beulich
@ 2023-03-02 9:02 ` Jan Beulich
0 siblings, 0 replies; 3+ messages in thread
From: Jan Beulich @ 2023-03-02 9:02 UTC (permalink / raw)
To: WANG Xuerui
Cc: Chenghua Xu, Zhensong Liu, Qinggang Meng, Xi Ruoyao, WANG Xuerui,
binutils
On 02.03.2023 09:58, Jan Beulich via Binutils wrote:
> On 02.03.2023 09:14, WANG Xuerui wrote:
>> + tmp = strtoul (optarg, &end, 0);
>> + if (*end != '\0' || tmp > 0xffffffff)
>
> I'm afraid this may trigger compiler warnings: For one because the constant
> isn't flagged as unsigned. And then (for 32-bit targets) for being an
> always-true comparison.
Argh, always-false (but you get the point).
Jan
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-03-02 9:02 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-02 8:14 [PATCH RESEND] elfedit: add support for editing e_flags WANG Xuerui
2023-03-02 8:58 ` Jan Beulich
2023-03-02 9:02 ` Jan Beulich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).