Add bigobj support to AArch64 COFF

Message ID CABd5JDBTkqXqDL39QnAxEk5=B-JjKtrmJGmX0XwqU8UK9P-k1g@mail.gmail.com
State New
Headers
Series Add bigobj support to AArch64 COFF |

Commit Message

Evgeny Karpov Sept. 24, 2025, 6:13 p.m. UTC
  During Boost library testing on aarch64-w64-mingw32, it appeared that 2^16
sections are not enough. It can be handled by using the bigobj format to extend
the total amount of sections to 2^32. This patch adds bigobj support to
AArch64 COFF in a similar way to how it is done for x86_64.

Co-authored-by: Martin Vejbora <mvejbora@microsoft.com>

---
 bfd/coff-aarch64.c             | 75 ++++++++++++++++++++++++++++++++++
 bfd/config.bfd                 |  2 +-
 bfd/configure                  |  1 +
 bfd/configure.ac               |  1 +
 bfd/cpu-aarch64.c              |  2 +-
 bfd/pe-aarch64.c               |  3 ++
 bfd/targets.c                  |  2 +
 gas/config/tc-aarch64.c        | 22 +++++++++-
 gas/testsuite/gas/pe/big-obj.d |  2 +-
 ld/pe-dll.c                    | 12 ++++++
 10 files changed, 118 insertions(+), 4 deletions(-)
  

Comments

Jan Beulich Sept. 26, 2025, 6:04 a.m. UTC | #1
On 24.09.2025 20:13, Evgeny Karpov wrote:
> --- a/bfd/config.bfd
> +++ b/bfd/config.bfd
> @@ -252,7 +252,7 @@ case "${targ}" in
>      ;;
>    aarch64-*-pe* | aarch64-*-mingw*)
>      targ_defvec=aarch64_pe_le_vec
> -    targ_selvecs="aarch64_pe_le_vec aarch64_pei_le_vec
> aarch64_elf64_le_vec aarch64_elf64_be_vec aarch64_elf32_le_vec
> aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec pdb_vec"
> +    targ_selvecs="aarch64_pe_le_vec aarch64_pei_le_vec
> aarch64_pe_big_vec aarch64_elf64_le_vec aarch64_elf64_be_vec
> aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec
> arm_elf32_be_vec pdb_vec"

There's no endianness indicator in the new name; in fact "big" in the name thus
ends up ambiguous.

Note also that your patch came through line-wrapped.

> --- a/bfd/pe-aarch64.c
> +++ b/bfd/pe-aarch64.c
> @@ -23,6 +23,8 @@
> 
>  #define TARGET_SYM             aarch64_pe_le_vec
>  #define TARGET_NAME            "pe-aarch64-little"
> +#define TARGET_SYM_BIG         aarch64_pe_big_vec
> +#define TARGET_NAME_BIG        "pe-aarch64-bigobj"

Same issue noticeable here.

> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -10210,6 +10210,11 @@ aarch64_after_parse_args (void)
>  #endif
>  }
> 
> +#ifdef OBJ_COFF
> +/* Use big object file format.  */
> +static int use_big_obj = 0;

bool (and then false here and true below) please.

> @@ -11287,6 +11302,11 @@ md_show_usage (FILE * fp)
>    fprintf (fp, _("\
>    -EL                     assemble code for a little-endian cpu\n"));
>  #endif
> +
> +#ifdef OBJ_COFF
> +  fprintf (fp, _("\
> +  -mbig-obj               generate big object files\n"));
> +#endif
>  }

This will want accompanying by a doc update.

> --- a/gas/testsuite/gas/pe/big-obj.d
> +++ b/gas/testsuite/gas/pe/big-obj.d
> @@ -2,7 +2,7 @@
>  #objdump: -h
>  #name: PE big obj
> 
> -.*: *file format pe-bigobj-.*
> +.*: *file format (pe-bigobj-.*|pe-aarch64-bigobj)

This also suggests a naming inconsistency.

Jan
  
Alice Carlotti Oct. 1, 2025, 4:05 p.m. UTC | #2
On Mon, Sep 29, 2025 at 05:37:20AM -0700, Evgeny Karpov wrote:
> Fri Sep 26 2025
> Jan Beulich <jbeulich@suse.com> wrote:
> >> +    targ_selvecs="aarch64_pe_le_vec aarch64_pei_le_vec
> >> aarch64_pe_big_vec aarch64_elf64_le_vec aarch64_elf64_be_vec
> >> aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec
> >> arm_elf32_be_vec pdb_vec"
> >
> > There's no endianness indicator in the new name; in fact "big" in the name thus
> > ends up ambiguous.
> 
> The aarch64_pe_big_vec naming follows the same pattern as it used in x86_64.
> i386_pe_big_vec and x86_64_pe_big_vec.

The difference you've overlooked is that i386/x86_64 is always little-endian,
so we don't need to explicitly specify endianness. On the other hand, aarch64
can be either endianness, so endianness is explicitly specified here.

Following the same pattern would mean adding "big" into "aarch64_pe_le_vec" to
get either "aarch64_pe_le_big_vec" or "aarch64_pe_big_le_vec".
(I'm not sure whether "big" should be attached to "pe" or placed at the end;
attaching it to the "pe" would be more consistent with the other names
discussed below).

> 
> > Note also that your patch came through line-wrapped.
> 
> It will be fixed in the next submission.
> 
> > bool (and then false here and true below) please.
> 
> It will be changed in the next version.
> 
> > This will want accompanying by a doc update.
> 
> gas/doc/c-aarch64.texi will be extended with documentation.
> 
> >> +.*: *file format (pe-bigobj-.*|pe-aarch64-bigobj)
> >
> > This also suggests a naming inconsistency.
> 
> pei-aarch64-little and pe-aarch64-little are the main pattern here.
> The pe-aarch64-bigobj naming follows them.

For x86_64, we have "pe-x86-64" -> "pe-bigobj-x86-64".
Following the same pattern for aarch64 would produce
"pe-aarch64-little" -> "pe-bigobj-aarch64-little".

> 
> Regards,
> Evgeny
  

Patch

diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index 48b8bfaf496..fe6c3d89ef7 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -1017,3 +1017,78 @@  const bfd_target

   COFF_SWAP_TABLE
 };
+
+#ifdef COFF_WITH_PE_BIGOBJ
+const bfd_target
+  TARGET_SYM_BIG =
+{
+  TARGET_NAME_BIG,
+  bfd_target_coff_flavour,
+  BFD_ENDIAN_LITTLE,		/* Data byte order is little.  */
+  BFD_ENDIAN_LITTLE,		/* Header byte order is little.  */
+
+  (HAS_RELOC | EXEC_P		/* Object flags.  */
+   | HAS_LINENO | HAS_DEBUG
+   | HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | BFD_COMPRESS |
BFD_DECOMPRESS),
+
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags.  */
+#ifdef COFF_WITH_PE
+   | SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY | SEC_DEBUGGING
+#endif
+   | SEC_CODE | SEC_DATA | SEC_EXCLUDE ),
+
+#ifdef TARGET_UNDERSCORE
+  TARGET_UNDERSCORE,		/* Leading underscore.  */
+#else
+  0,				/* Leading underscore.  */
+#endif
+  '/',				/* Ar_pad_char.  */
+  15,				/* Ar_max_namelen.  */
+  0,				/* match priority.  */
+  TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
+
+  /* Data conversion functions.  */
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data.  */
+  /* Header conversion functions.  */
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Hdrs.  */
+
+  /* Note that we allow an object file to be treated as a core file
as well.  */
+  {				/* bfd_check_format.  */
+    _bfd_dummy_target,
+    coff_object_p,
+    bfd_generic_archive_p,
+    coff_object_p
+  },
+  {				/* bfd_set_format.  */
+    _bfd_bool_bfd_false_error,
+    coff_mkobject,
+    _bfd_generic_mkarchive,
+    _bfd_bool_bfd_false_error
+  },
+  {				/* bfd_write_contents.  */
+    _bfd_bool_bfd_false_error,
+    coff_write_object_contents,
+    _bfd_write_archive_contents,
+    _bfd_bool_bfd_false_error
+  },
+
+  BFD_JUMP_TABLE_GENERIC (coff_aarch64),
+  BFD_JUMP_TABLE_COPY (coff),
+  BFD_JUMP_TABLE_CORE (_bfd_nocore),
+  BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+  BFD_JUMP_TABLE_SYMBOLS (coff),
+  BFD_JUMP_TABLE_RELOCS (coff),
+  BFD_JUMP_TABLE_WRITE (coff),
+  BFD_JUMP_TABLE_LINK (coff),
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+  NULL,
+
+  &bigobj_swap_table
+};
+#endif
+
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 9fa1c51a9a2..2e7accaee64 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -252,7 +252,7 @@  case "${targ}" in
     ;;
   aarch64-*-pe* | aarch64-*-mingw*)
     targ_defvec=aarch64_pe_le_vec
-    targ_selvecs="aarch64_pe_le_vec aarch64_pei_le_vec
aarch64_elf64_le_vec aarch64_elf64_be_vec aarch64_elf32_le_vec
aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec pdb_vec"
+    targ_selvecs="aarch64_pe_le_vec aarch64_pei_le_vec
aarch64_pe_big_vec aarch64_elf64_le_vec aarch64_elf64_be_vec
aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec
arm_elf32_be_vec pdb_vec"
     want64=true
     targ_underscore=no
     ;;
diff --git a/bfd/configure b/bfd/configure
index ee588238500..9a0879d791c 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -15478,6 +15478,7 @@  do
     aarch64_mach_o_vec)		 tb="$tb mach-o-aarch64.lo"; target_size=64 ;;
     aarch64_pei_le_vec)		 tb="$tb pei-aarch64.lo pe-aarch64igen.lo
$coff"; target_size=64 ;;
     aarch64_pe_le_vec)		 tb="$tb pe-aarch64.lo pe-aarch64igen.lo
$coff"; target_size=64 ;;
+    aarch64_pe_big_vec)		 tb="$tb pe-aarch64.lo pe-aarch64igen.lo
$coff"; target_size=64 ;;
     alpha_ecoff_le_vec)		 tb="$tb coff-alpha.lo ecoff.lo $ecoff";
target_size=64 ;;
     alpha_elf64_vec)		 tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
     alpha_elf64_fbsd_vec)	 tb="$tb elf64-alpha.lo elf64.lo $elf";
target_size=64 ;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 4fb3bf41f34..2aa5a3a35bd 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -403,6 +403,7 @@  do
     aarch64_mach_o_vec)		 tb="$tb mach-o-aarch64.lo"; target_size=64 ;;
     aarch64_pei_le_vec)		 tb="$tb pei-aarch64.lo pe-aarch64igen.lo
$coff"; target_size=64 ;;
     aarch64_pe_le_vec)		 tb="$tb pe-aarch64.lo pe-aarch64igen.lo
$coff"; target_size=64 ;;
+    aarch64_pe_big_vec)		 tb="$tb pe-aarch64.lo pe-aarch64igen.lo
$coff"; target_size=64 ;;
     alpha_ecoff_le_vec)		 tb="$tb coff-alpha.lo ecoff.lo $ecoff";
target_size=64 ;;
     alpha_elf64_vec)		 tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
     alpha_elf64_fbsd_vec)	 tb="$tb elf64-alpha.lo elf64.lo $elf";
target_size=64 ;;
diff --git a/bfd/cpu-aarch64.c b/bfd/cpu-aarch64.c
index 51bdfc9d152..ff042a5650f 100644
--- a/bfd/cpu-aarch64.c
+++ b/bfd/cpu-aarch64.c
@@ -115,7 +115,7 @@  scan (const struct bfd_arch_info *info, const char *string)
 }

 /* Figure out if llp64 is default */
-#if DEFAULT_VECTOR == aarch64_pe_le_vec
+#if DEFAULT_VECTOR == aarch64_pe_le_vec || DEFAULT_VECTOR == aarch64_pe_big_vec
 #define LLP64_DEFAULT true
 #define AARCH64_DEFAULT false
 #else
diff --git a/bfd/pe-aarch64.c b/bfd/pe-aarch64.c
index 2204a51c509..e257beb8673 100644
--- a/bfd/pe-aarch64.c
+++ b/bfd/pe-aarch64.c
@@ -23,6 +23,8 @@ 

 #define TARGET_SYM             aarch64_pe_le_vec
 #define TARGET_NAME            "pe-aarch64-little"
+#define TARGET_SYM_BIG         aarch64_pe_big_vec
+#define TARGET_NAME_BIG        "pe-aarch64-bigobj"
 #define TARGET_ARCHITECTURE    bfd_arch_aarch64
 #define TARGET_PAGESIZE        4096
 #define TARGET_BIG_ENDIAN      0
@@ -32,6 +34,7 @@ 
 /* Rename the above into.. */
 #define COFF_WITH_peAArch64
 #define COFF_WITH_PE
+#define COFF_WITH_PE_BIGOBJ
 #define PCRELOFFSET       true

 /* Long section names not allowed in executable images, only object files.  */
diff --git a/bfd/targets.c b/bfd/targets.c
index ee629bbe9df..2db6fff7eac 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -680,6 +680,7 @@  extern const bfd_target aarch64_elf64_le_vec;
 extern const bfd_target aarch64_mach_o_vec;
 extern const bfd_target aarch64_pei_le_vec;
 extern const bfd_target aarch64_pe_le_vec;
+extern const bfd_target aarch64_pe_big_vec;
 extern const bfd_target alpha_ecoff_le_vec;
 extern const bfd_target alpha_elf64_vec;
 extern const bfd_target alpha_elf64_fbsd_vec;
@@ -987,6 +988,7 @@  static const bfd_target * const _bfd_target_vector[] =
 	&aarch64_elf64_le_vec,
 	&aarch64_mach_o_vec,
 	&aarch64_pe_le_vec,
+	&aarch64_pe_big_vec,
 	&aarch64_pei_le_vec,
 #endif

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 8f8c2c49f90..c2d0c3cbc30 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -10210,6 +10210,11 @@  aarch64_after_parse_args (void)
 #endif
 }

+#ifdef OBJ_COFF
+/* Use big object file format.  */
+static int use_big_obj = 0;
+#endif
+
 #ifdef OBJ_ELF
 const char *
 elf64_aarch64_target_format (void)
@@ -10229,7 +10234,7 @@  aarch64elf_frob_symbol (symbolS * symp, int *puntp)
 const char *
 coff_aarch64_target_format (void)
 {
-  return "pe-aarch64-little";
+  return use_big_obj ? "pe-aarch64-bigobj" : "pe-aarch64-little";
 }
 #endif

@@ -10588,6 +10593,7 @@  const char md_shortopts[] = "m:";
 #define OPTION_EL (OPTION_MD_BASE + 1)
 #endif
 #endif
+#define OPTION_MBIG_OBJ (OPTION_MD_BASE + 2)

 const struct option md_longopts[] = {
 #ifdef OPTION_EB
@@ -10595,6 +10601,9 @@  const struct option md_longopts[] = {
 #endif
 #ifdef OPTION_EL
   {"EL", no_argument, NULL, OPTION_EL},
+#endif
+#ifdef OBJ_COFF
+  {"mbig-obj", no_argument, NULL, OPTION_MBIG_OBJ},
 #endif
   {NULL, no_argument, NULL, 0}
 };
@@ -11215,6 +11224,12 @@  md_parse_option (int c, const char *arg)
       break;
 #endif

+#ifdef OBJ_COFF
+    case OPTION_MBIG_OBJ:
+      use_big_obj = 1;
+      break;
+#endif
+
     case 'a':
       /* Listing option.  Just ignore these, we don't support additional
          ones.  */
@@ -11287,6 +11302,11 @@  md_show_usage (FILE * fp)
   fprintf (fp, _("\
   -EL                     assemble code for a little-endian cpu\n"));
 #endif
+
+#ifdef OBJ_COFF
+  fprintf (fp, _("\
+  -mbig-obj               generate big object files\n"));
+#endif
 }

 /* Parse a .cpu directive.  */
diff --git a/gas/testsuite/gas/pe/big-obj.d b/gas/testsuite/gas/pe/big-obj.d
index 27b351a7d60..bde4e41e627 100644
--- a/gas/testsuite/gas/pe/big-obj.d
+++ b/gas/testsuite/gas/pe/big-obj.d
@@ -2,7 +2,7 @@ 
 #objdump: -h
 #name: PE big obj

-.*: *file format pe-bigobj-.*
+.*: *file format (pe-bigobj-.*|pe-aarch64-bigobj)

 Sections:
 #...
diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index c730b547502..6f6931e4e15 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -359,6 +359,18 @@  static pe_details_type pe_detail_list[] =
     false,
     autofilter_symbollist_generic
   },
+  {
+    "pei-aarch64-little",
+    "pe-aarch64-bigobj",
+    2,  /* IMAGE_REL_ARM64_ADDR32NB */
+    8,  /* IMAGE_REL_ARM64_SECREL */
+    11, /* IMAGE_REL_ARM64_SECREL_LOW12L */
+    13, /* IMAGE_REL_ARM64_SECTION */
+    PE_ARCH_aarch64,
+    bfd_arch_aarch64,
+    false,
+    autofilter_symbollist_generic
+  },
   { NULL, NULL, 0, 0, 0, 0, 0, 0, false, NULL }
 };