public inbox for gdb-cvs@sourceware.org
help / color / mirror / Atom feed
* [binutils-gdb] aarch64-pe support for LD, GAS and BFD
@ 2022-10-19  8:57 Zac Walker
  0 siblings, 0 replies; only message in thread
From: Zac Walker @ 2022-10-19  8:57 UTC (permalink / raw)
  To: bfd-cvs, gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=c60b3806799abf1d7f6cf5108a1b0e733a950b13

commit c60b3806799abf1d7f6cf5108a1b0e733a950b13
Author: Jedidiah Thompson <wej22007@outlook.com>
Date:   Wed Oct 19 10:57:12 2022 +0200

    aarch64-pe support for LD, GAS and BFD
    
    Allows aarch64-pe to be targeted natively, not having to use objcopy to convert it from ELF to PE.
    Based on initial work by Jedidiah Thompson
    
    Co-authored-by: Jedidiah Thompson <wej22007@outlook.com>
    Co-authored-by: Zac Walker <zac.walker@linaro.org>

Diff:
---
 bfd/Makefile.am                   |   2 +
 bfd/Makefile.in                   |   1 +
 bfd/archures.c                    |   1 +
 bfd/bfd-in2.h                     |   1 +
 bfd/bfd.c                         |   1 +
 bfd/coff-aarch64.c                | 168 ++++++++++++++++++++++++++++++++------
 bfd/config.bfd                    |  16 +++-
 bfd/configure                     |   3 +-
 bfd/configure.ac                  |   3 +-
 bfd/cpu-aarch64.c                 |  35 +++++---
 bfd/pe-aarch64.c                  |  74 +++++++++++++++++
 bfd/pei-aarch64.c                 |   2 +-
 bfd/peicode.h                     |   2 +
 bfd/po/SRC-POTFILES.in            |   1 +
 bfd/targets.c                     |   6 +-
 gas/config/obj-coff.h             |   4 +
 gas/config/tc-aarch64.c           |  49 ++++++++---
 gas/config/tc-aarch64.h           |  18 ++--
 gas/config/te-pepaarch64.h        |  29 +++++++
 gas/configure.tgt                 |   2 +-
 gas/testsuite/gas/pe/pe-aarch64.d |  14 ++++
 gas/testsuite/gas/pe/pe-aarch64.s |  11 +++
 gas/testsuite/gas/pe/pe.exp       |   6 ++
 gdb/coff-pe-read.c                |   8 +-
 include/coff/aarch64.h            |  22 +++++
 ld/Makefile.am                    |   1 +
 ld/Makefile.in                    |   1 +
 ld/configure.tgt                  |   6 +-
 ld/emulparams/aarch64pe.sh        |   9 ++
 ld/emultempl/pep.em               |  10 ++-
 ld/pe-dll.c                       |  44 ++++++++--
 ld/pep-dll-aarch64.c              |  23 ++++++
 ld/pep-dll-x86_64.c               |  22 +++++
 ld/pep-dll.c                      |   5 +-
 ld/testsuite/ld-pe/pe-aarch64.d   |  16 ++++
 ld/testsuite/ld-pe/pe-aarch64.s   |  11 +++
 ld/testsuite/ld-pe/pe.exp         |   5 ++
 37 files changed, 547 insertions(+), 85 deletions(-)

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 794d992310d..b70d8f3ccea 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -578,6 +578,7 @@ BFD64_BACKENDS = \
 	pe-loongarch64igen.lo \
 	pe-x86_64.lo \
 	pei-aarch64.lo \
+	pe-aarch64.lo \
 	pei-ia64.lo \
 	pei-loongarch64.lo \
 	pei-x86_64.lo \
@@ -619,6 +620,7 @@ BFD64_BACKENDS_CFILES = \
 	mach-o-aarch64.c \
 	mach-o-x86-64.c \
 	mmo.c \
+	pe-aarch64.c \
 	pe-x86_64.c \
 	pei-aarch64.c \
 	pei-ia64.c \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index bdf12c99cfd..3f520355829 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -1089,6 +1089,7 @@ BFD64_BACKENDS_CFILES = \
 	mach-o-aarch64.c \
 	mach-o-x86-64.c \
 	mmo.c \
+	pe-aarch64.c \
 	pe-x86_64.c \
 	pei-aarch64.c \
 	pei-ia64.c \
diff --git a/bfd/archures.c b/bfd/archures.c
index c67bacddfdc..e817bb0a44b 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -523,6 +523,7 @@ DESCRIPTION
 .#define bfd_mach_aarch64 0
 .#define bfd_mach_aarch64_8R	1
 .#define bfd_mach_aarch64_ilp32	32
+.#define bfd_mach_aarch64_llp64 64
 .  bfd_arch_nios2,     {* Nios II.  *}
 .#define bfd_mach_nios2		0
 .#define bfd_mach_nios2r1	1
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 534a46439fc..e09259b7eae 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1857,6 +1857,7 @@ enum bfd_architecture
 #define bfd_mach_aarch64 0
 #define bfd_mach_aarch64_8R    1
 #define bfd_mach_aarch64_ilp32 32
+#define bfd_mach_aarch64_llp64 64
   bfd_arch_nios2,     /* Nios II.  */
 #define bfd_mach_nios2         0
 #define bfd_mach_nios2r1       1
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 4fca8250082..b9d4aa44d9c 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -1743,6 +1743,7 @@ bfd_get_sign_extend_vma (bfd *abfd)
       || strcmp (name, "pei-i386") == 0
       || strcmp (name, "pe-x86-64") == 0
       || strcmp (name, "pei-x86-64") == 0
+      || strcmp (name, "pe-aarch64-little") == 0
       || strcmp (name, "pei-aarch64-little") == 0
       || strcmp (name, "pe-arm-wince-little") == 0
       || strcmp (name, "pei-arm-wince-little") == 0
diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index e6f2fc2a0a0..2c3e225a222 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -39,34 +39,150 @@
 
 #include "libcoff.h"
 
-/* The page size is a guess based on ELF.  */
+/* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
+#define MINUS_ONE (~ (bfd_vma) 0)
+
+static const reloc_howto_type arm64_reloc_howto_64 = HOWTO(IMAGE_REL_ARM64_ADDR64, 0, 8, 64, false, 0,
+	 complain_overflow_bitfield,
+	 NULL, "64",
+	 false, MINUS_ONE, MINUS_ONE, false);
+
+static const reloc_howto_type arm64_reloc_howto_32 = HOWTO (IMAGE_REL_ARM64_ADDR32, 0, 4, 32, false, 0,
+	 complain_overflow_bitfield,
+	 NULL, "32",
+	 false, 0xffffffff, 0xffffffff, false);
+
+static const reloc_howto_type arm64_reloc_howto_32_pcrel = HOWTO (IMAGE_REL_ARM64_REL32, 0, 4, 32, true, 0,
+	 complain_overflow_bitfield,
+	 NULL, "DISP32",
+	 false, 0xffffffff, 0xffffffff, true);
+
+static const reloc_howto_type arm64_reloc_howto_branch26 = HOWTO (IMAGE_REL_ARM64_BRANCH26, 0, 4, 26, true, 0,
+	 complain_overflow_bitfield,
+	 NULL, "BRANCH26",
+	 false, 0x03ffffff, 0x03ffffff, true);
+
+static const reloc_howto_type arm64_reloc_howto_page21 = HOWTO (IMAGE_REL_ARM64_PAGEBASE_REL21, 12, 4, 21, true, 0,
+	 complain_overflow_signed,
+	 NULL, "PAGE21",
+	 false, 0x1fffff, 0x1fffff, false);
+
+static const reloc_howto_type arm64_reloc_howto_lo21 = HOWTO (IMAGE_REL_ARM64_REL21, 0, 4, 21, true, 0,
+	 complain_overflow_signed,
+	 NULL, "LO21",
+	 false, 0x1fffff, 0x1fffff, true);
+
+static const reloc_howto_type arm64_reloc_howto_pgoff12 = HOWTO (IMAGE_REL_ARM64_PAGEOFFSET_12L, 1, 4, 12, true, 0,
+	 complain_overflow_signed,
+	 NULL, "PGOFF12",
+	 false, 0xffe, 0xffe, true);
+
+static const reloc_howto_type arm64_reloc_howto_branch19 = HOWTO (IMAGE_REL_ARM64_BRANCH19, 2, 4, 19, true, 0,
+	 complain_overflow_signed,
+	 NULL, "BRANCH19",
+	 false, 0x7ffff, 0x7ffff, true);
+
+
+static const reloc_howto_type* const arm64_howto_table[] = {
+     &arm64_reloc_howto_64,
+     &arm64_reloc_howto_32,
+     &arm64_reloc_howto_32_pcrel,
+     &arm64_reloc_howto_branch26,
+     &arm64_reloc_howto_page21,
+     &arm64_reloc_howto_lo21,
+     &arm64_reloc_howto_pgoff12,
+     &arm64_reloc_howto_branch19
+};
 
-#define COFF_PAGE_SIZE 0x1000
+#ifndef NUM_ELEM
+#define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0]))
+#endif
 
-/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */
-#define OCTETS_PER_BYTE(ABFD, SEC) 1
+#define NUM_RELOCS NUM_ELEM (arm64_howto_table)
 
-#ifndef PCRELOFFSET
-#define PCRELOFFSET true
-#endif
+#define coff_bfd_reloc_type_lookup		coff_aarch64_reloc_type_lookup
+#define coff_bfd_reloc_name_lookup		coff_aarch64_reloc_name_lookup
 
-/* Currently we don't handle any relocations.  */
-static reloc_howto_type pe_aarch64_std_reloc_howto[] =
+static reloc_howto_type *
+coff_aarch64_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
+{
+  switch (code)
   {
+  case BFD_RELOC_64:
+    return &arm64_reloc_howto_64;
+  case BFD_RELOC_32:
+    return &arm64_reloc_howto_32;
+  case BFD_RELOC_32_PCREL:
+    return &arm64_reloc_howto_32_pcrel;
+  case BFD_RELOC_AARCH64_CALL26:
+  case BFD_RELOC_AARCH64_JUMP26:
+    return &arm64_reloc_howto_branch26;
+  case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+    return &arm64_reloc_howto_page21;
+  case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
+    return &arm64_reloc_howto_lo21;
+  case BFD_RELOC_AARCH64_LDST16_LO12:
+    return &arm64_reloc_howto_pgoff12;
+  case BFD_RELOC_AARCH64_BRANCH19:
+    return &arm64_reloc_howto_branch19;
+  default:
+    BFD_FAIL ();
+    return NULL;
+  }
+
+  return NULL;
+}
+
+static reloc_howto_type *
+coff_aarch64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+			    const char *r_name)
+{
+	unsigned int i;
 
-  };
+	for (i = 0; i < NUM_RELOCS; i++)
+	  if (arm64_howto_table[i]->name != NULL
+	    && strcasecmp (arm64_howto_table[i]->name, r_name) == 0)
+	    return arm64_howto_table[i];
+
+  return NULL;
+}
 
 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER  2
 #define COFF_PAGE_SIZE			      0x1000
 
-#ifndef NUM_ELEM
-#define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0]))
-#endif
+static reloc_howto_type *
+coff_aarch64_rtype_lookup (unsigned int code)
+{
+  switch (code)
+  {
+    case IMAGE_REL_ARM64_ADDR64:
+      return &arm64_reloc_howto_64;
+    case IMAGE_REL_ARM64_ADDR32:
+      return &arm64_reloc_howto_32;
+    case IMAGE_REL_ARM64_REL32:
+      return &arm64_reloc_howto_32_pcrel;
+    case IMAGE_REL_ARM64_BRANCH26:
+      return &arm64_reloc_howto_branch26;
+    case IMAGE_REL_ARM64_PAGEBASE_REL21:
+      return &arm64_reloc_howto_page21;
+    case IMAGE_REL_ARM64_REL21:
+      return &arm64_reloc_howto_lo21;
+    case IMAGE_REL_ARM64_PAGEOFFSET_12L:
+      return &arm64_reloc_howto_pgoff12;
+    case IMAGE_REL_ARM64_BRANCH19:
+      return &arm64_reloc_howto_branch19;
+    default:
+      BFD_FAIL ();
+      return NULL;
+  }
+
+  return NULL;
+}
 
-#define NUM_RELOCS NUM_ELEM (pe_aarch64_std_reloc_howto)
+#define RTYPE2HOWTO(cache_ptr, dst)				\
+  ((cache_ptr)->howto =	coff_aarch64_rtype_lookup((dst)->r_type))
 
-#define RTYPE2HOWTO(cache_ptr, dst)             \
-  (cache_ptr)->howto = NULL
+#define SELECT_RELOC(x,howto) { (x).r_type = (howto)->type; }
 
 #ifndef bfd_pe_print_pdata
 #define bfd_pe_print_pdata      NULL
@@ -93,13 +209,13 @@ const bfd_target
 #ifdef TARGET_SYM
   TARGET_SYM =
 #else
-  aarch64_pei_vec =
+# error "target symbol name not specified"
 #endif
 {
 #ifdef TARGET_NAME
   TARGET_NAME,
 #else
- "pei-aarch64-little",			/* Name.  */
+# error "target name not specified"
 #endif
   bfd_target_coff_flavour,
   BFD_ENDIAN_LITTLE,		/* Data byte order is little.  */
@@ -125,14 +241,14 @@ const bfd_target
   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.  */
+  /* 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.  */
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 5eb82d7e613..0ae8eb39d29 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -245,9 +245,15 @@ case "${targ}" in
     ;;
   aarch64-*-elf | aarch64-*-rtems* | aarch64-*-genode*)
     targ_defvec=aarch64_elf64_le_vec
-    targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec aarch64_pei_vec"
+    targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec aarch64_pei_le_vec aarch64_pe_le_vec"
     want64=true
     ;;
+  aarch64-*-pe*)
+    targ_defvec=aarch64_pe_le_vec
+    targ_selvecs="aarch64_pe_le_vec aarch64_pei_le_vec"
+    want64=true
+    targ_underscore=no
+    ;;
   aarch64_be-*-elf)
     targ_defvec=aarch64_elf64_be_vec
     targ_selvecs="aarch64_elf64_le_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_be_vec arm_elf32_le_vec"
@@ -280,7 +286,7 @@ case "${targ}" in
     ;;
   aarch64-*-linux* | aarch64-*-netbsd*)
     targ_defvec=aarch64_elf64_le_vec
-    targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec aarch64_pei_vec"
+    targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec aarch64_pei_le_vec aarch64_pe_le_vec"
     want64=true
     ;;
   aarch64_be-*-linux* | aarch64_be-*-netbsd*)
@@ -1488,6 +1494,12 @@ case "${targ}" in
     ;;
 esac
 
+if test x"$targ_defvec" = x"aarch64-pe"; then
+  # Not currently complete (and probably not stable), warn user
+  echo "*** WARNING BFD aarch64-pe support not complete nor stable"
+  echo "*** Do not rely on this for production purposes"
+fi
+
 # All MIPS ELF targets need a 64-bit bfd_vma.
 case "${targ_defvec} ${targ_selvecs}" in
   *mips_elf*)
diff --git a/bfd/configure b/bfd/configure
index b72e885f711..bae9d17c515 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -13603,7 +13603,8 @@ do
     aarch64_elf64_le_vec)	   tb="$tb elf64-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
     aarch64_elf64_le_cloudabi_vec) tb="$tb elf64-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
     aarch64_mach_o_vec)		 tb="$tb mach-o-aarch64.lo"; target_size=64 ;;
-    aarch64_pei_vec)		 tb="$tb pei-aarch64.lo pe-aarch64igen.lo $coff"; 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 ;;
     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 7a0ad0ffe33..74c0f072225 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -404,7 +404,8 @@ do
     aarch64_elf64_le_vec)	   tb="$tb elf64-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
     aarch64_elf64_le_cloudabi_vec) tb="$tb elf64-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf64.lo $elf"; target_size=64 ;;
     aarch64_mach_o_vec)		 tb="$tb mach-o-aarch64.lo"; target_size=64 ;;
-    aarch64_pei_vec)		 tb="$tb pei-aarch64.lo pe-aarch64igen.lo $coff"; 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 ;;
     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 e1bd8fc4789..eb88d0ef861 100644
--- a/bfd/cpu-aarch64.c
+++ b/bfd/cpu-aarch64.c
@@ -39,8 +39,8 @@ compatible (const bfd_arch_info_type * a, const bfd_arch_info_type * b)
   if (a->mach == b->mach)
     return a;
 
-  /* Don't allow mixing ilp32 with lp64.  */
-  if ((a->mach & bfd_mach_aarch64_ilp32) != (b->mach & bfd_mach_aarch64_ilp32))
+  /* Don't allow mixing data models.  */
+  if ((a->mach ^ b->mach) & (bfd_mach_aarch64_ilp32 | bfd_mach_aarch64_llp64))
     return NULL;
 
   /* Otherwise if either a or b is the 'default' machine
@@ -102,20 +102,33 @@ scan (const struct bfd_arch_info *info, const char *string)
   return false;
 }
 
-#define N(NUMBER, PRINT, WORDSIZE, DEFAULT, NEXT)		\
-  { WORDSIZE, WORDSIZE, 8, bfd_arch_aarch64, NUMBER,		\
-    "aarch64", PRINT, 4, DEFAULT, compatible, scan,		\
-      bfd_arch_default_fill, NEXT, 0 }
+/* Figure out if llp64 is default */
+#if DEFAULT_VECTOR == aarch64_pe_le_vec
+#define LLP64_DEFAULT true
+#define AARCH64_DEFAULT false
+#else
+#define LLP64_DEFAULT false
+#define AARCH64_DEFAULT true
+#endif
 
-static const bfd_arch_info_type bfd_aarch64_arch_v8_r =
-  N (bfd_mach_aarch64_8R, "aarch64:armv8-r", 64, false, NULL);
+#define N(NUMBER, PRINT, WORDSIZE, ADDRSIZE, DEFAULT, NEXT)		\
+  { WORDSIZE, ADDRSIZE, 8, bfd_arch_aarch64, NUMBER,		\
+     "aarch64", PRINT, 4, DEFAULT, compatible, scan,		\
+       bfd_arch_default_fill, NEXT, 0 }
+
+ static const bfd_arch_info_type bfd_aarch64_arch_v8_r =
+  N (bfd_mach_aarch64_8R, "aarch64:armv8-r", 64, 64, false, NULL);
 
 static const bfd_arch_info_type bfd_aarch64_arch_ilp32 =
-  N (bfd_mach_aarch64_ilp32, "aarch64:ilp32", 32, false,
+  N (bfd_mach_aarch64_ilp32, "aarch64:ilp32", 32, 32, false,
      &bfd_aarch64_arch_v8_r);
 
-const bfd_arch_info_type bfd_aarch64_arch =
-  N (0, "aarch64", 64, true, &bfd_aarch64_arch_ilp32);
+static const bfd_arch_info_type bfd_aarch64_arch_llp64 =
+  N (bfd_mach_aarch64_llp64, "aarch64:llp64", 32, 64, LLP64_DEFAULT,
+     &bfd_aarch64_arch_ilp32);
+
+ const bfd_arch_info_type bfd_aarch64_arch =
+  N (0, "aarch64", 64, 64, AARCH64_DEFAULT, &bfd_aarch64_arch_llp64);
 
 bool
 bfd_is_aarch64_special_symbol_name (const char *name, int type)
diff --git a/bfd/pe-aarch64.c b/bfd/pe-aarch64.c
new file mode 100644
index 00000000000..0790ba39a17
--- /dev/null
+++ b/bfd/pe-aarch64.c
@@ -0,0 +1,74 @@
+/* BFD back-end for AArch64 PE IMAGE COFF files.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#define TARGET_SYM             aarch64_pe_le_vec
+#define TARGET_NAME            "pe-aarch64-little"
+#define TARGET_ARCHITECTURE    bfd_arch_aarch64
+#define TARGET_PAGESIZE        4096
+#define TARGET_BIG_ENDIAN      0
+#define TARGET_ARCHIVE         0
+#define TARGET_PRIORITY        0
+
+/* Rename the above into.. */
+#define COFF_WITH_peAArch64
+#define COFF_WITH_PE
+#define PCRELOFFSET       true
+
+/* Long section names not allowed in executable images, only object files.  */
+#define COFF_LONG_SECTION_NAMES 1
+
+#define COFF_SECTION_ALIGNMENT_ENTRIES \
+{ COFF_SECTION_NAME_EXACT_MATCH (".bss"), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
+{ COFF_SECTION_NAME_EXACT_MATCH (".data"), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
+{ COFF_SECTION_NAME_EXACT_MATCH (".rdata"), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
+{ COFF_SECTION_NAME_EXACT_MATCH (".text"), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
+{ COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
+{ COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
+{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
+{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \
+  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
+
+#define PEI_HEADERS
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "coff/aarch64.h"
+#include "coff/internal.h"
+#include "coff/pe.h"
+#include "libcoff.h"
+#include "libpei.h"
+#include "libiberty.h"
+
+/* Make sure we're setting a 64-bit format.  */
+#undef AOUTSZ
+#define AOUTSZ          PEPAOUTSZ
+#define PEAOUTHDR       PEPAOUTHDR
+
+#include "coff-aarch64.c"
diff --git a/bfd/pei-aarch64.c b/bfd/pei-aarch64.c
index c447690793d..7b6c681b4be 100644
--- a/bfd/pei-aarch64.c
+++ b/bfd/pei-aarch64.c
@@ -21,7 +21,7 @@
 #include "sysdep.h"
 #include "bfd.h"
 
-#define TARGET_SYM		aarch64_pei_vec
+#define TARGET_SYM		aarch64_pei_le_vec
 #define TARGET_NAME		"pei-aarch64-little"
 #define TARGET_ARCHITECTURE	bfd_arch_aarch64
 #define TARGET_PAGESIZE		4096
diff --git a/bfd/peicode.h b/bfd/peicode.h
index 3888dd47cc6..add8d82bfde 100644
--- a/bfd/peicode.h
+++ b/bfd/peicode.h
@@ -191,6 +191,8 @@ coff_swap_filehdr_in (bfd * abfd, void * src, void * dst)
 
 #ifdef COFF_IMAGE_WITH_PE
 # define coff_swap_filehdr_out _bfd_XXi_only_swap_filehdr_out
+#elif defined COFF_WITH_peAArch64
+# define coff_swap_filehdr_out _bfd_XX_only_swap_filehdr_out
 #elif defined COFF_WITH_pex64
 # define coff_swap_filehdr_out _bfd_pex64_only_swap_filehdr_out
 #elif defined COFF_WITH_pep
diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in
index 30fce580ab4..36e51fe063f 100644
--- a/bfd/po/SRC-POTFILES.in
+++ b/bfd/po/SRC-POTFILES.in
@@ -313,6 +313,7 @@ osf-core.c
 pc532-mach.c
 pdb.c
 pdp11.c
+pe-aarch64.c
 pe-arm-wince.c
 pe-arm.c
 pe-i386.c
diff --git a/bfd/targets.c b/bfd/targets.c
index 7dbc3a5dbf6..0bb85b64cc2 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -686,7 +686,8 @@ extern const bfd_target aarch64_elf64_be_cloudabi_vec;
 extern const bfd_target aarch64_elf64_le_vec;
 extern const bfd_target aarch64_elf64_le_cloudabi_vec;
 extern const bfd_target aarch64_mach_o_vec;
-extern const bfd_target aarch64_pei_vec;
+extern const bfd_target aarch64_pei_le_vec;
+extern const bfd_target aarch64_pe_le_vec;
 extern const bfd_target alpha_ecoff_le_vec;
 extern const bfd_target alpha_elf64_vec;
 extern const bfd_target alpha_elf64_fbsd_vec;
@@ -999,7 +1000,8 @@ static const bfd_target * const _bfd_target_vector[] =
 	&aarch64_elf64_le_vec,
 	&aarch64_elf64_le_cloudabi_vec,
 	&aarch64_mach_o_vec,
-	&aarch64_pei_vec,
+	&aarch64_pe_le_vec,
+	&aarch64_pei_le_vec,
 #endif
 
 #ifdef BFD64
diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h
index 1dbd38aea37..f79c73702f9 100644
--- a/gas/config/obj-coff.h
+++ b/gas/config/obj-coff.h
@@ -40,6 +40,10 @@
 #endif
 #endif
 
+#ifdef TC_AARCH64
+#include "coff/aarch64.h"
+#endif
+
 #ifdef TC_PPC
 #include "coff/rs6000.h"
 #endif
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 98a7ca5878f..f6fa1585832 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -30,9 +30,9 @@
 
 #ifdef OBJ_ELF
 #include "elf/aarch64.h"
-#include "dw2gencfi.h"
 #endif
 
+#include "dw2gencfi.h"
 #include "dwarf2dbg.h"
 
 /* Types of processor to assemble for.  */
@@ -61,21 +61,25 @@ static aarch64_instr_sequence *insn_sequence = NULL;
 #ifdef OBJ_ELF
 /* Pre-defined "_GLOBAL_OFFSET_TABLE_"	*/
 static symbolS *GOT_symbol;
+#endif
 
 /* Which ABI to use.  */
 enum aarch64_abi_type
 {
   AARCH64_ABI_NONE = 0,
   AARCH64_ABI_LP64 = 1,
-  AARCH64_ABI_ILP32 = 2
+  AARCH64_ABI_ILP32 = 2,
+  AARCH64_ABI_LLP64 = 3
 };
 
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "aarch64"
 #endif
 
+#ifdef OBJ_ELF
 /* DEFAULT_ARCH is initialized in gas/configure.tgt.  */
 static const char *default_arch = DEFAULT_ARCH;
+#endif
 
 /* AArch64 ABI for the output file.  */
 static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_NONE;
@@ -85,7 +89,10 @@ static enum aarch64_abi_type aarch64_abi = AARCH64_ABI_NONE;
    64-bit model, in which the C int type is 32-bits but the C long type
    and all pointer types are 64-bit objects (LP64).  */
 #define ilp32_p		(aarch64_abi == AARCH64_ABI_ILP32)
-#endif
+
+/* When non zero, C types int and long are 32 bit,
+   pointers, however are 64 bit */
+#define llp64_p (aarch64_abi == AARCH64_ABI_LLP64)
 
 enum vector_el_type
 {
@@ -1459,7 +1466,7 @@ s_unreq (int a ATTRIBUTE_UNUSED)
 
 /* Directives: Instruction set selection.  */
 
-#ifdef OBJ_ELF
+#if defined OBJ_ELF || defined OBJ_COFF
 /* This code is to handle mapping symbols as defined in the ARM AArch64 ELF
    spec.  (See "Mapping symbols", section 4.5.4, ARM AAELF64 version 0.05).
    Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
@@ -8336,7 +8343,7 @@ aarch64_handle_align (fragS * fragP)
   fix = bytes & (noop_size - 1);
   if (fix)
     {
-#ifdef OBJ_ELF
+#if defined OBJ_ELF || defined OBJ_COFF
       insert_data_mapping_symbol (MAP_INSN, fragP->fr_fix, fragP, fix);
 #endif
       memset (p, 0, fix);
@@ -8394,6 +8401,7 @@ aarch64_init_frag (fragS * fragP, int max_chars)
       break;
     }
 }
+#endif /* OBJ_ELF */
 \f
 /* Initialize the DWARF-2 unwind information for this procedure.  */
 
@@ -8402,7 +8410,6 @@ tc_aarch64_frame_initial_instructions (void)
 {
   cfi_add_CFA_def_cfa (REG_SP, 0);
 }
-#endif /* OBJ_ELF */
 
 /* Convert REGNAME to a DWARF-2 register number.  */
 
@@ -8439,10 +8446,10 @@ tc_aarch64_regname_to_dw2regnum (char *regname)
 int
 aarch64_dwarf2_addr_size (void)
 {
-#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)
   if (ilp32_p)
     return 4;
-#endif
+  else if (llp64_p)
+    return 8;
   return bfd_arch_bits_per_address (stdoutput) / 8;
 }
 
@@ -9307,8 +9314,6 @@ cons_fix_new_aarch64 (fragS * frag, int where, int size, expressionS * exp)
   fix_new_exp (frag, where, (int) size, exp, pcrel, type);
 }
 
-#ifdef OBJ_ELF
-
 /* Implement md_after_parse_args.  This is the earliest time we need to decide
    ABI.  If no -mabi specified, the ABI will be decided by target triplet.  */
 
@@ -9318,13 +9323,18 @@ aarch64_after_parse_args (void)
   if (aarch64_abi != AARCH64_ABI_NONE)
     return;
 
+#ifdef OBJ_ELF
   /* DEFAULT_ARCH will have ":32" extension if it's configured for ILP32.  */
   if (strlen (default_arch) > 7 && strcmp (default_arch + 7, ":32") == 0)
     aarch64_abi = AARCH64_ABI_ILP32;
   else
     aarch64_abi = AARCH64_ABI_LP64;
+#else
+  aarch64_abi = AARCH64_ABI_LLP64;
+#endif
 }
 
+#ifdef OBJ_ELF
 const char *
 elf64_aarch64_target_format (void)
 {
@@ -9347,6 +9357,12 @@ aarch64elf_frob_symbol (symbolS * symp, int *puntp)
 {
   elf_frob_symbol (symp, puntp);
 }
+#elif defined OBJ_COFF
+const char *
+coff_aarch64_target_format (void)
+{
+  return "pe-aarch64-little";
+}
 #endif
 
 /* MD interface: Finalization.	*/
@@ -9662,7 +9678,12 @@ md_begin (void)
   cpu_variant = *mcpu_cpu_opt;
 
   /* Record the CPU type.  */
-  mach = ilp32_p ? bfd_mach_aarch64_ilp32 : bfd_mach_aarch64;
+  if(ilp32_p)
+    mach = bfd_mach_aarch64_ilp32;
+  else if (llp64_p)
+    mach = bfd_mach_aarch64_llp64;
+  else
+    mach = bfd_mach_aarch64;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
 }
@@ -10230,8 +10251,12 @@ struct aarch64_option_abi_value_table
 };
 
 static const struct aarch64_option_abi_value_table aarch64_abis[] = {
+#ifdef OBJ_ELF
   {"ilp32",		AARCH64_ABI_ILP32},
   {"lp64",		AARCH64_ABI_LP64},
+#else
+  {"llp64",		AARCH64_ABI_LLP64},
+#endif
 };
 
 static int
@@ -10257,10 +10282,8 @@ aarch64_parse_abi (const char *str)
 }
 
 static struct aarch64_long_option_table aarch64_long_opts[] = {
-#ifdef OBJ_ELF
   {"mabi=", N_("<abi name>\t  specify for ABI <abi name>"),
    aarch64_parse_abi, NULL},
-#endif /* OBJ_ELF */
   {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
    aarch64_parse_cpu, NULL},
   {"march=", N_("<arch name>\t  assemble for architecture <arch name>"),
diff --git a/gas/config/tc-aarch64.h b/gas/config/tc-aarch64.h
index f5c17523796..2d514ff610a 100644
--- a/gas/config/tc-aarch64.h
+++ b/gas/config/tc-aarch64.h
@@ -59,9 +59,11 @@ struct aarch64_fix
   enum aarch64_opnd opnd;
 };
 
-#if defined OBJ_ELF
+#ifdef OBJ_ELF
 # define AARCH64_BI_ENDIAN
 # define TARGET_FORMAT	elf64_aarch64_target_format ()
+#elif defined (OBJ_COFF)
+# define TARGET_FORMAT coff_aarch64_target_format ()
 #endif
 
 #define TC_FORCE_RELOCATION(FIX) aarch64_force_relocation (FIX)
@@ -169,7 +171,7 @@ void aarch64_elf_copy_symbol_attributes (symbolS *, symbolS *);
 struct aarch64_frag_type
 {
   int recorded;
-#ifdef OBJ_ELF
+#if defined OBJ_ELF || defined OBJ_COFF
   /* If there is a mapping symbol at offset 0 in this frag,
      it will be saved in FIRST_MAP.  If there are any mapping
      symbols in this frag, the last one will be saved in
@@ -202,8 +204,10 @@ struct aarch64_frag_type
 extern int aarch64_dwarf2_addr_size (void);
 #define DWARF2_ADDR_SIZE(bfd) aarch64_dwarf2_addr_size ()
 
+#if defined OBJ_ELF || defined OBJ_COFF
 #ifdef OBJ_ELF
 # define obj_frob_symbol(sym, punt)	aarch64elf_frob_symbol ((sym), & (punt))
+#endif
 
 # define GLOBAL_OFFSET_TABLE_NAME	"_GLOBAL_OFFSET_TABLE_"
 # define TC_SEGMENT_INFO_TYPE 		struct aarch64_segment_info_type
@@ -259,6 +263,7 @@ extern void aarch64_after_parse_args (void);
 
 extern void aarch64_frag_align_code (int, int);
 extern const char * elf64_aarch64_target_format (void);
+extern const char * coff_aarch64_target_format (void);
 extern int aarch64_force_relocation (struct fix *);
 extern void aarch64_cleanup (void);
 extern void aarch64_start_line_hook (void);
@@ -274,13 +279,4 @@ extern void aarch64_handle_align (struct frag *);
 extern int tc_aarch64_regname_to_dw2regnum (char *regname);
 extern void tc_aarch64_frame_initial_instructions (void);
 
-#ifdef TE_PE
-
-#define O_secrel O_md1
-
-#define TC_DWARF2_EMIT_OFFSET  tc_pe_dwarf2_emit_offset
-void tc_pe_dwarf2_emit_offset (symbolS *, unsigned int);
-
-#endif /* TE_PE */
-
 #endif /* TC_AARCH64 */
diff --git a/gas/config/te-pepaarch64.h b/gas/config/te-pepaarch64.h
new file mode 100644
index 00000000000..4774e94a633
--- /dev/null
+++ b/gas/config/te-pepaarch64.h
@@ -0,0 +1,29 @@
+/* Copyright (C) 2006-2022 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 3,
+   or (at your option) any later version.
+
+   GAS is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#define TE_PEP
+#define COFF_WITH_peAArch64
+
+#define TE_PE
+#define LEX_AT (LEX_BEGIN_NAME | LEX_NAME) /* Can have @'s inside labels.  */
+
+/* The PE format supports long section names.  */
+#define COFF_LONG_SECTION_NAMES
+
+#include "obj-format.h"
diff --git a/gas/configure.tgt b/gas/configure.tgt
index 9f2b6720bd7..82f2d44f418 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -135,7 +135,7 @@ case ${generic_target} in
     esac ;;
   aarch64*-*-netbsd*)			fmt=elf em=nbsd;;
   aarch64*-*-openbsd*)			fmt=elf;;
-
+  aarch64*-*-pe*)			fmt=coff em=pepaarch64 ;;
   alpha-*-*vms*)			fmt=evax ;;
   alpha-*-osf*)				fmt=ecoff ;;
   alpha-*-linux*ecoff*)			fmt=ecoff ;;
diff --git a/gas/testsuite/gas/pe/pe-aarch64.d b/gas/testsuite/gas/pe/pe-aarch64.d
new file mode 100644
index 00000000000..0b8009da5c4
--- /dev/null
+++ b/gas/testsuite/gas/pe/pe-aarch64.d
@@ -0,0 +1,14 @@
+#as:
+#objdump: -d
+
+.*:     file format pe-aarch64-little
+
+
+Disassembly of section .text:
+
+0000000000000000 <_start>:
+   0:	d2800281 	mov	x1, #0x14                  	// #20
+   4:	14000001 	b	8 <foo>
+
+0000000000000008 <foo>:
+   8:	d65f03c0 	ret
diff --git a/gas/testsuite/gas/pe/pe-aarch64.s b/gas/testsuite/gas/pe/pe-aarch64.s
new file mode 100644
index 00000000000..546d55fc361
--- /dev/null
+++ b/gas/testsuite/gas/pe/pe-aarch64.s
@@ -0,0 +1,11 @@
+# A little test to ensure pe-aarch64 is working in GAS.
+# Currently, the poor pe-aarch64 implementation in binutils
+# couldn't do anything useful, hence, this test is rather short
+
+.section .text
+
+_start:
+    mov x1, 20
+    b foo
+foo:
+    ret
diff --git a/gas/testsuite/gas/pe/pe.exp b/gas/testsuite/gas/pe/pe.exp
index 3568ff7b02f..8df750f9dd0 100644
--- a/gas/testsuite/gas/pe/pe.exp
+++ b/gas/testsuite/gas/pe/pe.exp
@@ -52,6 +52,12 @@ if ([istarget "x86_64-*-mingw*"]) then {
 	run_dump_test "peseh-x64-6"
 }
 
+
+# This test is only for AArch64
+if ([istarget "aarch64-*-pe*"]) {
+	run_dump_test "pe-aarch64"
+}
+
 # Big obj
 
 
diff --git a/gdb/coff-pe-read.c b/gdb/coff-pe-read.c
index 2f3b80815b5..0f57deb391a 100644
--- a/gdb/coff-pe-read.c
+++ b/gdb/coff-pe-read.c
@@ -331,7 +331,9 @@ read_pe_exported_syms (minimal_symbol_reader &reader,
   section_data[PE_SECTION_INDEX_BSS].section_name = ".bss";
 
   is_pe64 = (strcmp (target, "pe-x86-64") == 0
-	     || strcmp (target, "pei-x86-64") == 0);
+	     || strcmp (target, "pei-x86-64") == 0
+	     || strcmp (target, "pe-aarch64") == 0
+	     || strcmp (target, "pei-aarch64") == 0);
   is_pe32 = (strcmp (target, "pe-i386") == 0
 	     || strcmp (target, "pei-i386") == 0
 	     || strcmp (target, "pe-arm-wince-little") == 0
@@ -610,7 +612,9 @@ pe_text_section_offset (struct bfd *abfd)
   target = bfd_get_target (abfd);
 
   is_pe64 = (strcmp (target, "pe-x86-64") == 0
-	     || strcmp (target, "pei-x86-64") == 0);
+	     || strcmp (target, "pei-x86-64") == 0
+	     || strcmp (target, "pe-aarch64") == 0
+	     || strcmp (target, "pei-aarch64") == 0);
   is_pe32 = (strcmp (target, "pe-i386") == 0
 	     || strcmp (target, "pei-i386") == 0
 	     || strcmp (target, "pe-arm-wince-little") == 0
diff --git a/include/coff/aarch64.h b/include/coff/aarch64.h
index 2bbeaa9fadf..100e08f18ef 100644
--- a/include/coff/aarch64.h
+++ b/include/coff/aarch64.h
@@ -60,4 +60,26 @@ struct external_reloc
 #define RELOC struct external_reloc
 #define RELSZ 14
 
+/* ARM64 relocations types. */
+
+
+#define IMAGE_REL_ARM64_ABSOLUTE        0x0000  /* No relocation required */
+#define IMAGE_REL_ARM64_ADDR32          0x0001  /* The 32-bit VA of the target. */
+#define IMAGE_REL_ARM64_ADDR32NB        0x0002  /* The 32-bit RVA of the target. */
+#define IMAGE_REL_ARM64_BRANCH26        0x0003  /* The 26-bit relative displacement to the target, for B and BL instructions. */
+#define IMAGE_REL_ARM64_PAGEBASE_REL21  0x0004  /* The page base of the target, for ADRP instruction. */
+#define IMAGE_REL_ARM64_REL21           0x0005  /* The 12-bit relative displacement to the target, for instruction ADR */
+#define IMAGE_REL_ARM64_PAGEOFFSET_12A  0x0006  /* The 12-bit page offset of the target, for instructions ADD/ADDS (immediate) with zero shift. */
+#define IMAGE_REL_ARM64_PAGEOFFSET_12L  0x0007  /* The 12-bit page offset of the target, for instruction LDR (indexed, unsigned immediate). */
+#define IMAGE_REL_ARM64_SECREL          0x0008  /* The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. */
+#define IMAGE_REL_ARM64_SECREL_LOW12A   0x0009  /* Bit 0:11 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift. */
+#define IMAGE_REL_ARM64_SECREL_HIGH12A  0x000A  /* Bit 12:23 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift. */
+#define IMAGE_REL_ARM64_SECREL_LOW12L   0x000B  /* Bit 0:11 of section offset of the target, for instruction LDR (indexed, unsigned immediate). */
+#define IMAGE_REL_ARM64_TOKEN           0x000C  /* CLR token */
+#define IMAGE_REL_ARM64_SECTION         0x000D  /* The 16-bit section index of the section that contains the target. This is used to support debugging information. */
+#define IMAGE_REL_ARM64_ADDR64          0x000E  /* The 64-bit VA of the relocation target. */
+#define IMAGE_REL_ARM64_BRANCH19        0x000F  /* 19 bit offset << 2 & sign ext. for conditional B */
+#define IMAGE_REL_ARM64_BRANCH14        0x0010  /* The 14-bit offset to the relocation target, for instructions TBZ and TBNZ. */
+#define IMAGE_REL_ARM64_REL32           0x0011  /* The 32-bit relative address from the byte following the relocation. */
+
 #define ARM_NOTE_SECTION ".note"
diff --git a/ld/Makefile.am b/ld/Makefile.am
index bbe25f3aca2..b4ec47ae1fd 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -377,6 +377,7 @@ ALL_EMULATIONS = $(ALL_EMULATION_SOURCES:.c=.@OBJEXT@)
 ALL_64_EMULATION_SOURCES = \
 	eaarch64cloudabi.c \
 	eaarch64cloudabib.c \
+	eaarch64pe.c \
 	eaarch64elf.c \
 	eaarch64elf32.c \
 	eaarch64elf32b.c \
diff --git a/ld/Makefile.in b/ld/Makefile.in
index 400eed2717e..21d7edb4106 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -887,6 +887,7 @@ ALL_64_EMULATION_SOURCES = \
 	eaarch64linux32.c \
 	eaarch64linux32b.c \
 	eaarch64linuxb.c \
+	eaarch64pe.c \
 	eelf32_x86_64.c \
 	eelf32b4300.c \
 	eelf32bmip.c \
diff --git a/ld/configure.tgt b/ld/configure.tgt
index 2bae9099b6a..97639880d7e 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -117,6 +117,10 @@ aarch64-*-linux*)	targ_emul=aarch64linux
 aarch64-*-haiku*)	targ_emul=aarch64haiku
 			targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb armelf_haiku $targ_extra_libpath"
 			;;
+aarch64-*-pe*)
+			targ_emul=aarch64pe
+			targ_extra_ofiles="deffilep.o pep-dll-aarch64.o"
+			;;
 alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu)
 			targ_emul=elf64alpha_fbsd
 			targ_extra_emuls="elf64alpha alpha"
@@ -1042,7 +1046,7 @@ x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu)
 			;;
 x86_64-*-pe | x86_64-*-pep) targ_emul=i386pep ;
 			targ_extra_emuls=i386pe ;
-			targ_extra_ofiles="deffilep.o pep-dll.o pe-dll.o"
+			targ_extra_ofiles="deffilep.o pep-dll-x86_64.o pe-dll.o"
 			;;
 x86_64-*-cygwin)	targ_emul=i386pep ;
 			targ_extra_emuls=i386pe
diff --git a/ld/emulparams/aarch64pe.sh b/ld/emulparams/aarch64pe.sh
new file mode 100644
index 00000000000..02bf02cd963
--- /dev/null
+++ b/ld/emulparams/aarch64pe.sh
@@ -0,0 +1,9 @@
+ARCH="aarch64"
+SCRIPT_NAME=pep
+OUTPUT_FORMAT="pei-aarch64-little"
+RELOCATEABLE_OUTPUT_FORMAT="pe-aarch64-little"
+TEMPLATE_NAME=pep
+SUBSYSTEM=PE_DEF_SUBSYSTEM
+INITIAL_SYMBOL_CHAR=\"_\"
+TARGET_PAGE_SIZE=0x1000
+GENERATE_AUTO_IMPORT_SCRIPT=1
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index d94f18b05c5..7a390e74b05 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -48,7 +48,11 @@ fragment <<EOF
 
 #define COFF_IMAGE_WITH_PE
 #define COFF_WITH_PE
+#ifdef TARGET_IS_aarch64pe
+#define COFF_WITH_peAArch64
+#elif defined (TARGET_IS_i386pep)
 #define COFF_WITH_pex64
+#endif
 
 #include "sysdep.h"
 #include "bfd.h"
@@ -72,7 +76,11 @@ fragment <<EOF
 
 /* FIXME: See bfd/peXXigen.c for why we include an architecture specific
    header in generic PE code.  */
-#include "coff/x86_64.h"
+#ifdef TARGET_IS_i386pep
+# include "coff/x86_64.h"
+#elif defined TARGET_IS_aarch64pe
+# include "coff/aarch64.h"
+#endif
 #include "coff/pe.h"
 
 /* FIXME: These are BFD internal header files, and we should not be
diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index 338e2def83c..df16e85bbe0 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -42,7 +42,7 @@
 #include "../bfd/libcoff.h"
 #include "deffile.h"
 
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
 
 #define PE_IDATA4_SIZE	8
 #define PE_IDATA5_SIZE	8
@@ -209,7 +209,7 @@ static const autofilter_entry_type autofilter_symbollist_i386[] =
   { STRING_COMMA_LEN ("_NULL_IMPORT_DESCRIPTOR") },
   /* Entry point symbols, and entry hooks.  */
   { STRING_COMMA_LEN ("cygwin_crt0") },
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
   { STRING_COMMA_LEN ("DllMain") },
   { STRING_COMMA_LEN ("DllEntryPoint") },
   { STRING_COMMA_LEN ("DllMainCRTStartup") },
@@ -246,13 +246,14 @@ static const autofilter_entry_type autofilter_symbollist_i386[] =
 #define PE_ARCH_mips	 3
 #define PE_ARCH_arm	 4
 #define PE_ARCH_arm_wince 5
+#define PE_ARCH_aarch64  6
 
 /* Don't make it constant as underscore mode gets possibly overriden
    by target or -(no-)leading-underscore option.  */
 static pe_details_type pe_detail_list[] =
 {
   {
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
     "pei-x86-64",
     "pe-x86-64",
     3 /* R_IMAGEBASE */,
@@ -263,14 +264,14 @@ static pe_details_type pe_detail_list[] =
 #endif
     PE_ARCH_i386,
     bfd_arch_i386,
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
     false,
 #else
     true,
 #endif
     autofilter_symbollist_i386
   },
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
   {
     "pei-x86-64",
     "pe-bigobj-x86-64",
@@ -327,6 +328,15 @@ static pe_details_type pe_detail_list[] =
     false,
     autofilter_symbollist_generic
   },
+  {
+    "pei-aarch64-little",
+    "pe-aarch64-little",
+    2,  /* ARM64_RVA32 */
+    PE_ARCH_aarch64,
+    bfd_arch_aarch64,
+    false,
+    autofilter_symbollist_generic
+  },
   { NULL, NULL, 0, 0, 0, false, NULL }
 };
 
@@ -1638,7 +1648,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
 		  switch BITS_AND_SHIFT (relocs[i]->howto->bitsize,
 					 relocs[i]->howto->rightshift)
 		    {
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
 		    case BITS_AND_SHIFT (64, 0):
 		      reloc_data[total_relocs].type = IMAGE_REL_BASED_DIR64;
 		      total_relocs++;
@@ -2247,6 +2257,15 @@ static const unsigned char jmp_ix86_bytes[] =
   0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90
 };
 
+/* _function:
+  b <__imp_function>
+  nop */
+static const unsigned char jmp_aarch64_bytes[] =
+{
+  0x00, 0x00, 0x00, 0x14,
+  0x1f, 0x20, 0x03, 0xD5
+};
+
 /* _function:
 	mov.l	ip+8,r0
 	mov.l	@r0,r0
@@ -2317,6 +2336,10 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
 	  jmp_bytes = jmp_arm_bytes;
 	  jmp_byte_count = sizeof (jmp_arm_bytes);
 	  break;
+	case PE_ARCH_aarch64:
+	  jmp_bytes = jmp_aarch64_bytes;
+	  jmp_byte_count = sizeof (jmp_aarch64_bytes);
+	  break;
 	default:
 	  abort ();
 	}
@@ -2386,7 +2409,7 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
       switch (pe_details->pe_arch)
 	{
 	case PE_ARCH_i386:
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
 	  quick_reloc (abfd, 2, BFD_RELOC_32_PCREL, 2);
 #else
 	  /* Mark this object as SAFESEH compatible.  */
@@ -2407,6 +2430,9 @@ make_one (def_file_export *exp, bfd *parent, bool include_jmp_stub)
 	case PE_ARCH_arm_wince:
 	  quick_reloc (abfd, 8, BFD_RELOC_32, 2);
 	  break;
+	case PE_ARCH_aarch64:
+	  quick_reloc (abfd, 0, BFD_RELOC_AARCH64_JUMP26, 2);
+	  break;
 	default:
 	  abort ();
 	}
@@ -3406,7 +3432,7 @@ pe_implied_import_dll (const char *filename)
   /* Get pe_header, optional header and numbers of directory entries.  */
   pe_header_offset = pe_get32 (dll, 0x3c);
   opthdr_ofs = pe_header_offset + 4 + 20;
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
   num_entries = pe_get32 (dll, opthdr_ofs + 92 + 4 * 4); /*  & NumberOfRvaAndSizes.  */
 #else
   num_entries = pe_get32 (dll, opthdr_ofs + 92);
@@ -3416,7 +3442,7 @@ pe_implied_import_dll (const char *filename)
   if (num_entries < 1)
     return false;
 
-#ifdef pe_use_x86_64
+#ifdef pe_use_plus
   export_rva  = pe_get32 (dll, opthdr_ofs + 96 + 4 * 4);
   export_size = pe_get32 (dll, opthdr_ofs + 100 + 4 * 4);
 #else
diff --git a/ld/pep-dll-aarch64.c b/ld/pep-dll-aarch64.c
new file mode 100644
index 00000000000..61c9a2a2c93
--- /dev/null
+++ b/ld/pep-dll-aarch64.c
@@ -0,0 +1,23 @@
+/* Tiny wrapper over pep-dll.c
+   Copyright (C) 2006-2022 Free Software Foundation, Inc.
+
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#define COFF_WITH_peAArch64
+
+#include "pep-dll.c"
diff --git a/ld/pep-dll-x86_64.c b/ld/pep-dll-x86_64.c
new file mode 100644
index 00000000000..0be189815cc
--- /dev/null
+++ b/ld/pep-dll-x86_64.c
@@ -0,0 +1,22 @@
+/* Tiny wrapper over pep-dll.c
+   Copyright (C) 2006-2022 Free Software Foundation, Inc.
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#define COFF_WITH_pex64
+
+#include "pep-dll.c"
diff --git a/ld/pep-dll.c b/ld/pep-dll.c
index 3049a024e17..1cfed490337 100644
--- a/ld/pep-dll.c
+++ b/ld/pep-dll.c
@@ -21,7 +21,6 @@
 
 #define COFF_IMAGE_WITH_PE
 #define COFF_WITH_PE
-#define COFF_WITH_pex64
 
 /* Local defined globals.  */
 #define pe_def_file	            pep_def_file
@@ -58,7 +57,7 @@
 #define pe_output_file_set_long_section_names \
 				    pep_output_file_set_long_section_names
 
-/* Uses x86_64 PE+.  */
-#define pe_use_x86_64
+/* Uses PE+.  */
+#define pe_use_plus
 
 #include "pe-dll.c"
diff --git a/ld/testsuite/ld-pe/pe-aarch64.d b/ld/testsuite/ld-pe/pe-aarch64.d
new file mode 100644
index 00000000000..fac02b5fd87
--- /dev/null
+++ b/ld/testsuite/ld-pe/pe-aarch64.d
@@ -0,0 +1,16 @@
+#ld:
+#objdump: -d
+
+.*:     file format pei-aarch64-little
+
+
+Disassembly of section .text:
+
+0000000140001000 <__rt_psrelocs_end>:
+   140001000:	d2800281 	mov	x1, #0x14                  	// #20
+   140001004:	14000001 	b	140001008 <foo>
+
+0000000140001008 <foo>:
+   140001008:	d65f03c0 	ret
+   14000100c:	00000000 	udf	#0
+#...
diff --git a/ld/testsuite/ld-pe/pe-aarch64.s b/ld/testsuite/ld-pe/pe-aarch64.s
new file mode 100644
index 00000000000..5d493508913
--- /dev/null
+++ b/ld/testsuite/ld-pe/pe-aarch64.s
@@ -0,0 +1,11 @@
+# A little test to ensure pe-aarch64 is working in LD.
+# Currently, the poor pe-aarch64 implementation in binutils
+# couldn't do anything useful, hence, this test is rather short
+
+.section .text
+
+_start:
+    mov x1, 20
+    b foo
+foo:
+    ret
diff --git a/ld/testsuite/ld-pe/pe.exp b/ld/testsuite/ld-pe/pe.exp
index 22819e0894f..d8595ee61e8 100644
--- a/ld/testsuite/ld-pe/pe.exp
+++ b/ld/testsuite/ld-pe/pe.exp
@@ -78,6 +78,11 @@ if {[istarget i*86-*-cygwin*]
     run_ld_link_tests $pe_tests
 }
 
+if {[istarget "aarch64-*-pe*"]} {
+	run_dump_test "pe-aarch64"
+}
+
+
 run_dump_test "image_size"
 run_dump_test "export_dynamic_warning"

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-19  8:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-19  8:57 [binutils-gdb] aarch64-pe support for LD, GAS and BFD Zac Walker

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).