From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mailbox.box.xen0n.name (mail.xen0n.name [115.28.160.31]) by sourceware.org (Postfix) with ESMTPS id C6A983858D33 for ; Thu, 2 Mar 2023 08:01:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C6A983858D33 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=xen0n.name Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=xen0n.name DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=xen0n.name; s=mail; t=1677744109; bh=PTLmIRR5l3FugMpYSuy+bqWiaO2vor+nLvk3oHSGn7o=; h=From:To:Cc:Subject:Date:From; b=vxn5A0umifq4GrqXcpWS+4idLWB3BBDE+oOH2fpsEzHShX9bGhlq79ooQ8dI2kjja MSKypCyrWYcukP1yWPIN/+3S6nib3LujwT4DdFOF0kCz+aE69EJ+0R8rQfVPJyUW44 uvsAXWVK3A4maO7DVXs9SnFV/TqJYN2QfiAAyaJs= Received: from ld50.lan (unknown [114.93.192.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mailbox.box.xen0n.name (Postfix) with ESMTPSA id 42CF0600BD; Thu, 2 Mar 2023 16:01:46 +0800 (CST) From: WANG Xuerui To: binutils@sourceware.org Cc: Chenghua Xu , Zhensong Liu , Qinggang Meng , Xi Ruoyao , WANG Xuerui Subject: [PATCH] elfedit: add support for editing e_flags Date: Thu, 2 Mar 2023 16:01:37 +0800 Message-Id: <20230302080137.3346439-1-i.swmail@xen0n.name> X-Mailer: git-send-email 2.39.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: From: WANG Xuerui 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. --- 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 | 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 @@ -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" -- 2.39.1