diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index 236cbb79ffb..d6c48eba63b 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -39,59 +39,310 @@
 
 #include "libcoff.h"
 
+static bfd_reloc_status_type
+coff_aarch64_addr64_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			   arelent *reloc_entry,
+			   asymbol *symbol ATTRIBUTE_UNUSED,
+			   void *data,
+			   asection *input_section ATTRIBUTE_UNUSED,
+			   bfd *output_bfd ATTRIBUTE_UNUSED,
+			   char **error_message ATTRIBUTE_UNUSED)
+{
+  uint64_t val = reloc_entry->addend;
+
+  bfd_putl64 (val, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_addr32_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			   arelent *reloc_entry,
+			   asymbol *symbol ATTRIBUTE_UNUSED,
+			   void *data,
+			   asection *input_section ATTRIBUTE_UNUSED,
+			   bfd *output_bfd ATTRIBUTE_UNUSED,
+			   char **error_message ATTRIBUTE_UNUSED)
+{
+  uint64_t val;
+
+  if ((int64_t) reloc_entry->addend > 0x7fffffff
+      || (int64_t) reloc_entry->addend < -0x7fffffff)
+    return bfd_reloc_overflow;
+
+  val = reloc_entry->addend;
+
+  bfd_putl32 ((uint32_t) val, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_branch26_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			     arelent *reloc_entry,
+			     asymbol *symbol ATTRIBUTE_UNUSED,
+			     void *data,
+			     asection *input_section ATTRIBUTE_UNUSED,
+			     bfd *output_bfd ATTRIBUTE_UNUSED,
+			     char **error_message ATTRIBUTE_UNUSED)
+{
+  uint32_t op;
+  int32_t param;
+
+  op = bfd_getl32 (data + reloc_entry->address);
+  param = reloc_entry->addend;
+
+  if (param > 0x7ffffff || param < -0x8000000)
+    return bfd_reloc_overflow;
+
+  op &= 0xfc000000;
+  op |= (param >> 2) & 0x3ffffff;
+
+  bfd_putl32 (op, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_rel21_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			  arelent *reloc_entry,
+			  asymbol *symbol ATTRIBUTE_UNUSED,
+			  void *data,
+			  asection *input_section ATTRIBUTE_UNUSED,
+			  bfd *output_bfd ATTRIBUTE_UNUSED,
+			  char **error_message ATTRIBUTE_UNUSED)
+{
+  uint32_t op;
+  int32_t param;
+
+  op = bfd_getl32 (data + reloc_entry->address);
+  param = reloc_entry->addend;
+
+  if (param > 0xfffff || param < -0x100000)
+    return bfd_reloc_overflow;
+
+  op &= 0x9f00001f;
+  op |= (param & 0x1ffffc) << 3;
+  op |= (param & 0x3) << 29;
+
+  bfd_putl32 (op, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_po12l_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			  arelent *reloc_entry,
+			  asymbol *symbol ATTRIBUTE_UNUSED,
+			  void *data,
+			  asection *input_section ATTRIBUTE_UNUSED,
+			  bfd *output_bfd ATTRIBUTE_UNUSED,
+			  char **error_message ATTRIBUTE_UNUSED)
+{
+  uint32_t op;
+  int32_t param;
+  uint8_t shift;
+
+  op = bfd_getl32 (data + reloc_entry->address);
+  param = reloc_entry->addend & 0xfff;
+
+  if ((op & 0xff800000) == 0x3d800000)
+    {
+      /* LDR / STR with q register */
+      shift = 4;
+    }
+  else
+    {
+      /* top two bits represent how much addend should be shifted */
+      shift = op >> 30;
+    }
+
+  if (param & ((1 << shift) - 1))
+    return bfd_reloc_overflow;
+
+  param >>= shift;
+
+  op &= 0xffc003ff;
+  op |= param << 10;
+
+  bfd_putl32 (op, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_branch19_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			     arelent *reloc_entry,
+			     asymbol *symbol ATTRIBUTE_UNUSED,
+			     void *data,
+			     asection *input_section ATTRIBUTE_UNUSED,
+			     bfd *output_bfd ATTRIBUTE_UNUSED,
+			     char **error_message ATTRIBUTE_UNUSED)
+{
+  uint32_t op;
+  int32_t param;
+
+  op = bfd_getl32 (data + reloc_entry->address);
+  param = reloc_entry->addend;
+
+  if (param > 0xfffff || param < -0x100000)
+    return bfd_reloc_overflow;
+
+  op &= 0xff00001f;
+  op |= ((param >> 2) & 0x7ffff) << 5;
+
+  bfd_putl32 (op, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_branch14_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			     arelent *reloc_entry,
+			     asymbol *symbol ATTRIBUTE_UNUSED,
+			     void *data,
+			     asection *input_section ATTRIBUTE_UNUSED,
+			     bfd *output_bfd ATTRIBUTE_UNUSED,
+			     char **error_message ATTRIBUTE_UNUSED)
+{
+  uint32_t op;
+  int32_t param;
+
+  op = bfd_getl32 (data + reloc_entry->address);
+  param = reloc_entry->addend;
+
+  if (param > 0x7fff || param < -0x8000)
+    return bfd_reloc_overflow;
+
+  op &= 0xfff8001f;
+  op |= ((param >> 2) & 0x3fff) << 5;
+
+  bfd_putl32 (op, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_po12a_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			  arelent *reloc_entry,
+			  asymbol *symbol ATTRIBUTE_UNUSED,
+			  void *data,
+			  asection *input_section ATTRIBUTE_UNUSED,
+			  bfd *output_bfd ATTRIBUTE_UNUSED,
+			  char **error_message ATTRIBUTE_UNUSED)
+{
+  uint32_t op;
+  int32_t param;
+
+  op = bfd_getl32 (data + reloc_entry->address);
+  param = reloc_entry->addend;
+
+  op &= 0xffc003ff;
+  op |= (param & 0xfff) << 10;
+
+  bfd_putl32 (op, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+coff_aarch64_addr32nb_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+			     arelent *reloc_entry,
+			     asymbol *symbol ATTRIBUTE_UNUSED,
+			     void *data,
+			     asection *input_section ATTRIBUTE_UNUSED,
+			     bfd *output_bfd ATTRIBUTE_UNUSED,
+			     char **error_message ATTRIBUTE_UNUSED)
+{
+  uint64_t val;
+
+  if ((int64_t) reloc_entry->addend > 0x7fffffff
+      || (int64_t) reloc_entry->addend < -0x7fffffff)
+    return bfd_reloc_overflow;
+
+  val = reloc_entry->addend;
+
+  bfd_putl32 ((uint32_t) val, data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
 /* 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_abs = HOWTO(IMAGE_REL_ARM64_ABSOLUTE, 0, 1, 0, false, 0,
+	 complain_overflow_dont,
+	 NULL, "IMAGE_REL_ARM64_ABSOLUTE",
+	 false, 0, 0, false);
+
 static const reloc_howto_type arm64_reloc_howto_64 = HOWTO(IMAGE_REL_ARM64_ADDR64, 0, 8, 64, false, 0,
 	 complain_overflow_bitfield,
-	 NULL, "64",
+	 coff_aarch64_addr64_reloc, "IMAGE_REL_ARM64_ADDR64",
 	 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",
+	 coff_aarch64_addr32_reloc, "IMAGE_REL_ARM64_ADDR32",
 	 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",
+	 NULL, "IMAGE_REL_ARM64_REL32",
 	 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",
+	 coff_aarch64_branch26_reloc, "IMAGE_REL_ARM64_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",
+	 coff_aarch64_rel21_reloc, "IMAGE_REL_ARM64_PAGEBASE_REL21",
 	 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",
+	 coff_aarch64_rel21_reloc, "IMAGE_REL_ARM64_REL21",
 	 false, 0x1fffff, 0x1fffff, true);
 
-static const reloc_howto_type arm64_reloc_howto_pgoff12 = HOWTO (IMAGE_REL_ARM64_PAGEOFFSET_12L, 1, 4, 12, true, 0,
+static const reloc_howto_type arm64_reloc_howto_pgoff12l = HOWTO (IMAGE_REL_ARM64_PAGEOFFSET_12L, 1, 4, 12, true, 0,
 	 complain_overflow_signed,
-	 NULL, "PGOFF12",
+	 coff_aarch64_po12l_reloc, "IMAGE_REL_ARM64_PAGEOFFSET_12L",
 	 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",
+	 coff_aarch64_branch19_reloc, "IMAGE_REL_ARM64_BRANCH19",
 	 false, 0x7ffff, 0x7ffff, true);
 
+static const reloc_howto_type arm64_reloc_howto_branch14 = HOWTO (IMAGE_REL_ARM64_BRANCH14, 2, 4, 14, true, 0,
+	 complain_overflow_signed,
+	 coff_aarch64_branch14_reloc, "IMAGE_REL_ARM64_BRANCH14",
+	 false, 0x3fff, 0x3fff, true);
+
+static const reloc_howto_type arm64_reloc_howto_pgoff12a = HOWTO (IMAGE_REL_ARM64_PAGEOFFSET_12A, 2, 4, 12, true, 10,
+	 complain_overflow_dont,
+	 coff_aarch64_po12a_reloc, "IMAGE_REL_ARM64_PAGEOFFSET_12A",
+	 false, 0x3ffc00, 0x3ffc00, false);
+
+static const reloc_howto_type arm64_reloc_howto_32nb = HOWTO (IMAGE_REL_ARM64_ADDR32NB, 0, 4, 32, false, 0,
+	 complain_overflow_bitfield,
+	 coff_aarch64_addr32nb_reloc, "IMAGE_REL_ARM64_ADDR32NB",
+	 false, 0xffffffff, 0xffffffff, false);
 
 static const reloc_howto_type* const arm64_howto_table[] = {
+     &arm64_reloc_howto_abs,
      &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
+     &arm64_reloc_howto_pgoff12l,
+     &arm64_reloc_howto_branch19,
+     &arm64_reloc_howto_branch14,
+     &arm64_reloc_howto_pgoff12a,
+     &arm64_reloc_howto_32nb
 };
 
 #ifndef NUM_ELEM
@@ -118,13 +369,24 @@ coff_aarch64_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real
   case BFD_RELOC_AARCH64_JUMP26:
     return &arm64_reloc_howto_branch26;
   case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+  case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
     return &arm64_reloc_howto_page21;
+  case BFD_RELOC_AARCH64_TSTBR14:
+    return &arm64_reloc_howto_branch14;
   case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
     return &arm64_reloc_howto_lo21;
+  case BFD_RELOC_AARCH64_ADD_LO12:
+    return &arm64_reloc_howto_pgoff12a;
+  case BFD_RELOC_AARCH64_LDST8_LO12:
   case BFD_RELOC_AARCH64_LDST16_LO12:
-    return &arm64_reloc_howto_pgoff12;
+  case BFD_RELOC_AARCH64_LDST32_LO12:
+  case BFD_RELOC_AARCH64_LDST64_LO12:
+  case BFD_RELOC_AARCH64_LDST128_LO12:
+    return &arm64_reloc_howto_pgoff12l;
   case BFD_RELOC_AARCH64_BRANCH19:
     return &arm64_reloc_howto_branch19;
+  case BFD_RELOC_RVA:
+    return &arm64_reloc_howto_32nb;
   default:
     BFD_FAIL ();
     return NULL;
@@ -155,6 +417,8 @@ coff_aarch64_rtype_lookup (unsigned int code)
 {
   switch (code)
   {
+    case IMAGE_REL_ARM64_ABSOLUTE:
+      return &arm64_reloc_howto_abs;
     case IMAGE_REL_ARM64_ADDR64:
       return &arm64_reloc_howto_64;
     case IMAGE_REL_ARM64_ADDR32:
@@ -168,9 +432,15 @@ coff_aarch64_rtype_lookup (unsigned int code)
     case IMAGE_REL_ARM64_REL21:
       return &arm64_reloc_howto_lo21;
     case IMAGE_REL_ARM64_PAGEOFFSET_12L:
-      return &arm64_reloc_howto_pgoff12;
+      return &arm64_reloc_howto_pgoff12l;
     case IMAGE_REL_ARM64_BRANCH19:
       return &arm64_reloc_howto_branch19;
+    case IMAGE_REL_ARM64_BRANCH14:
+      return &arm64_reloc_howto_branch14;
+    case IMAGE_REL_ARM64_PAGEOFFSET_12A:
+      return &arm64_reloc_howto_pgoff12a;
+    case IMAGE_REL_ARM64_ADDR32NB:
+      return &arm64_reloc_howto_32nb;
     default:
       BFD_FAIL ();
       return NULL;
@@ -188,6 +458,7 @@ coff_aarch64_rtype_lookup (unsigned int code)
 #define bfd_pe_print_pdata      NULL
 #endif
 
+#ifdef COFF_WITH_PE
 /* Return TRUE if this relocation should
    appear in the output .reloc section.  */
 
@@ -197,9 +468,384 @@ in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED,
 {
   return !howto->pc_relative;
 }
+#endif
+
+static bool
+coff_pe_aarch64_relocate_section (bfd *output_bfd,
+				  struct bfd_link_info *info,
+				  bfd *input_bfd,
+				  asection *input_section,
+				  bfd_byte *contents,
+				  struct internal_reloc *relocs,
+				  struct internal_syment *syms,
+				  asection **sections)
+{
+  struct internal_reloc *rel;
+  struct internal_reloc *relend;
+
+  if (bfd_link_relocatable (info))
+    return true;
+
+  rel = relocs;
+  relend = rel + input_section->reloc_count;
+
+  /* The addend for a relocation is stored in the immediate bits of each
+     opcode.  So for each relocation, we need to extract the immediate value,
+     use this to calculate what it should be for the symbol, and rewrite the
+     opcode into the section stream.  */
+
+  for (; rel < relend; rel++)
+    {
+      long symndx;
+      struct coff_link_hash_entry *h;
+      bfd_vma sym_value;
+      asection *sec = NULL;
+      uint64_t dest_vma;
+
+      /* skip trivial relocations */
+      if (rel->r_type == IMAGE_REL_ARM64_ADDR32
+	  || rel->r_type == IMAGE_REL_ARM64_ADDR64
+	  || rel->r_type == IMAGE_REL_ARM64_ABSOLUTE)
+	continue;
+
+      symndx = rel->r_symndx;
+      sym_value = syms[symndx].n_value;
+
+      h = obj_coff_sym_hashes (input_bfd)[symndx];
+
+      if (h && h->root.type == bfd_link_hash_defined)
+	{
+	  sec = h->root.u.def.section;
+	  sym_value = h->root.u.def.value;
+	}
+      else
+	{
+	  sec = sections[symndx];
+	}
+
+      if (!sec)
+	continue;
+
+      if (bfd_is_und_section (sec))
+	continue;
+
+      if (discarded_section (sec))
+	continue;
+
+      dest_vma = sec->output_section->vma + sec->output_offset + sym_value;
+
+      if (symndx < 0
+	  || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
+	continue;
+
+      switch (rel->r_type)
+	{
+	case IMAGE_REL_ARM64_ADDR32NB:
+	  {
+	    uint64_t val;
+	    int32_t addend;
+
+	    addend = bfd_getl32 (contents + rel->r_vaddr);
+
+	    dest_vma += addend;
+
+	    val = dest_vma;
+	    val -= pe_data (output_bfd)->pe_opthdr.ImageBase;
+
+	    if (val > 0xffffffff)
+	      (*info->callbacks->reloc_overflow)
+		(info, h ? &h->root : NULL, syms[symndx]._n._n_name,
+		"IMAGE_REL_ARM64_ADDR32NB", addend, input_bfd,
+		input_section, rel->r_vaddr - input_section->vma);
+
+	    bfd_putl32 (val, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	case IMAGE_REL_ARM64_BRANCH26:
+	  {
+	    uint64_t cur_vma;
+	    uint32_t opcode;
+	    int64_t addend, val;
+
+	    opcode = bfd_getl32 (contents + rel->r_vaddr);
+
+	    addend = (opcode & 0x3ffffff) << 2;
+
+	    if (addend & 0x8000000)
+	      addend |= 0xfffffffff0000000;
+
+	    dest_vma += addend;
+	    cur_vma = input_section->output_section->vma
+		      + input_section->output_offset
+		      + rel->r_vaddr;
+
+	    val = (dest_vma >> 2) - (cur_vma >> 2);
+
+	    if (val > 0x1ffffff || val < -0x2000000)
+	      (*info->callbacks->reloc_overflow)
+		(info, h ? &h->root : NULL, syms[symndx]._n._n_name,
+		"IMAGE_REL_ARM64_BRANCH26", addend, input_bfd,
+		input_section, rel->r_vaddr - input_section->vma);
+
+	    opcode &= 0xfc000000;
+	    opcode |= val & 0x3ffffff;
+
+	    bfd_putl32 (opcode, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	case IMAGE_REL_ARM64_BRANCH19:
+	  {
+	    uint64_t cur_vma;
+	    uint32_t opcode;
+	    int64_t addend, val;
+
+	    opcode = bfd_getl32 (contents + rel->r_vaddr);
+
+	    addend = (opcode & 0xffffe0) >> 3;
+
+	    if (addend & 0x100000)
+	      addend |= 0xffffffffffe00000;
+
+	    dest_vma += addend;
+	    cur_vma = input_section->output_section->vma
+		      + input_section->output_offset
+		      + rel->r_vaddr;
+
+	    val = (dest_vma >> 2) - (cur_vma >> 2);
+
+	    if (val > 0x3ffff || val < -0x40000)
+	      (*info->callbacks->reloc_overflow)
+		(info, h ? &h->root : NULL, syms[symndx]._n._n_name,
+		"IMAGE_REL_ARM64_BRANCH19", addend, input_bfd,
+		input_section, rel->r_vaddr - input_section->vma);
+
+	    opcode &= 0xff00001f;
+	    opcode |= (val & 0x7ffff) << 5;
+
+	    bfd_putl32 (opcode, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	case IMAGE_REL_ARM64_BRANCH14:
+	  {
+	    uint64_t cur_vma;
+	    uint32_t opcode;
+	    int64_t addend, val;
+
+	    opcode = bfd_getl32 (contents + rel->r_vaddr);
+
+	    addend = (opcode & 0x7ffe0) >> 3;
+
+	    if (addend & 0x8000)
+	      addend |= 0xffffffffffff0000;
+
+	    dest_vma += addend;
+	    cur_vma = input_section->output_section->vma
+		      + input_section->output_offset
+		      + rel->r_vaddr;
+
+	    val = (dest_vma >> 2) - (cur_vma >> 2);
+
+	    if (val > 0x1fff || val < -0x2000)
+	      (*info->callbacks->reloc_overflow)
+		(info, h ? &h->root : NULL, syms[symndx]._n._n_name,
+		"IMAGE_REL_ARM64_BRANCH14", addend, input_bfd,
+		input_section, rel->r_vaddr - input_section->vma);
+
+	    opcode &= 0xfff8001f;
+	    opcode |= (val & 0x3fff) << 5;
+
+	    bfd_putl32 (opcode, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	case IMAGE_REL_ARM64_PAGEBASE_REL21:
+	  {
+	    uint64_t cur_vma;
+	    uint32_t opcode;
+	    int64_t addend, val;
+
+	    opcode = bfd_getl32 (contents + rel->r_vaddr);
+
+	    addend = ((opcode & 0xffffe0) >> 3)
+		     | ((opcode & 0x60000000) >> 29);
+
+	    if (addend & 0x100000)
+	      addend |= 0xffffffffffe00000;
+
+	    dest_vma += addend;
+	    cur_vma = input_section->output_section->vma
+		      + input_section->output_offset
+		      + rel->r_vaddr;
+
+	    val = (dest_vma >> 12) - (cur_vma >> 12);
+
+	    if (val > 0xfffff || val < -0x100000)
+	      (*info->callbacks->reloc_overflow)
+		(info, h ? &h->root : NULL, syms[symndx]._n._n_name,
+		"IMAGE_REL_ARM64_PAGEBASE_REL21", addend, input_bfd,
+		input_section, rel->r_vaddr - input_section->vma);
+
+	    opcode &= 0x9f00001f;
+	    opcode |= (val & 0x3) << 29;
+	    opcode |= (val & 0x1ffffc) << 3;
+
+	    bfd_putl32 (opcode, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	case IMAGE_REL_ARM64_REL21:
+	  {
+	    uint64_t cur_vma;
+	    uint32_t opcode;
+	    int64_t addend, val;
+
+	    opcode = bfd_getl32 (contents + rel->r_vaddr);
+
+	    addend = ((opcode & 0xffffe0) >> 3)
+		     | ((opcode & 0x60000000) >> 29);
+
+	    if (addend & 0x100000)
+	      addend |= 0xffffffffffe00000;
+
+	    dest_vma += addend;
+	    cur_vma = input_section->output_section->vma
+		      + input_section->output_offset
+		      + rel->r_vaddr;
+
+	    val = dest_vma - cur_vma;
+
+	    if (val > 0xfffff || val < -0x100000)
+	      (*info->callbacks->reloc_overflow)
+		(info, h ? &h->root : NULL, syms[symndx]._n._n_name,
+		"IMAGE_REL_ARM64_REL21", addend, input_bfd,
+		input_section, rel->r_vaddr - input_section->vma);
+
+	    opcode &= 0x9f00001f;
+	    opcode |= (val & 0x3) << 29;
+	    opcode |= (val & 0x1ffffc) << 3;
+
+	    bfd_putl32 (opcode, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	case IMAGE_REL_ARM64_PAGEOFFSET_12L:
+	  {
+	    uint32_t opcode, val;
+	    uint8_t shift;
+	    int32_t addend;
+
+	    opcode = bfd_getl32 (contents + rel->r_vaddr);
+
+	    addend = (opcode & 0x3ffc00) >> 10;
+
+	    if ((opcode & 0xff800000) == 0x3d800000)
+	      {
+		/* LDR / STR with q register */
+		shift = 4;
+	      }
+	    else
+	      {
+		/* top two bits represent how much addend should be shifted */
+		shift = opcode >> 30;
+	      }
+
+	    addend <<= shift;
+
+	    dest_vma += addend;
+
+	    /* only interested in bottom 12 bits */
+	    val = dest_vma & 0xfff;
+
+	    if (val & ((1 << shift) - 1))
+	      (*info->callbacks->reloc_overflow)
+		(info, h ? &h->root : NULL, syms[symndx]._n._n_name,
+		"IMAGE_REL_ARM64_PAGEOFFSET_12L", addend, input_bfd,
+		input_section, rel->r_vaddr - input_section->vma);
+
+	    val >>= shift;
+
+	    opcode &= 0xffc003ff;
+	    opcode |= val << 10;
+
+	    bfd_putl32 (opcode, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	case IMAGE_REL_ARM64_PAGEOFFSET_12A:
+	  {
+	    uint32_t opcode, val;
+	    int32_t addend;
+
+	    opcode = bfd_getl32 (contents + rel->r_vaddr);
+
+	    addend = (opcode & 0x3ffc00) >> 10;
+
+	    dest_vma += addend;
+
+	    /* only interested in bottom 12 bits */
+	    val = dest_vma & 0xfff;
+
+	    opcode &= 0xffc003ff;
+	    opcode |= val << 10;
+
+	    bfd_putl32 (opcode, contents + rel->r_vaddr);
+	    rel->r_type = IMAGE_REL_ARM64_ABSOLUTE;
+
+	    break;
+	  }
+
+	default:
+	  info->callbacks->einfo (_("%F%P: Unhandled relocation type %u\n"),
+				  rel->r_type);
+	  BFD_FAIL ();
+	  return false;
+	}
+    }
+
+  return _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,
+					     input_section, contents,
+					     relocs, syms, sections);
+}
+
+#define coff_relocate_section coff_pe_aarch64_relocate_section
 
 #include "coffcode.h"
 
+/* Prevent assertion in md_apply_fix by forcing use_rela_p on for new
+   sections.  */
+static bool
+coff_aarch64_new_section_hook (bfd *abfd, asection *section)
+{
+  if (!coff_new_section_hook (abfd, section))
+    return false;
+
+  section->use_rela_p = 1;
+
+  return true;
+}
+
+#define coff_aarch64_close_and_cleanup coff_close_and_cleanup
+#define coff_aarch64_bfd_free_cached_info coff_bfd_free_cached_info
+#define coff_aarch64_get_section_contents coff_get_section_contents
+#define coff_aarch64_get_section_contents_in_window coff_get_section_contents_in_window
+
 /* Target vectors.  */
 const bfd_target
 #ifdef TARGET_SYM
@@ -266,7 +912,7 @@ const bfd_target
     _bfd_bool_bfd_false_error
   },
 
-  BFD_JUMP_TABLE_GENERIC (coff),
+  BFD_JUMP_TABLE_GENERIC (coff_aarch64),
   BFD_JUMP_TABLE_COPY (coff),
   BFD_JUMP_TABLE_CORE (_bfd_nocore),
   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 3672b6a3602..800afa8105f 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -1493,12 +1493,6 @@ 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/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 132f8db7c50..25e79431046 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -1889,10 +1889,9 @@ s_ltorg (int ignored ATTRIBUTE_UNUSED)
     }
 }
 
-#ifdef OBJ_ELF
+#if defined(OBJ_ELF) || defined(OBJ_COFF)
 /* Forward declarations for functions below, in the MD interface
    section.  */
-static fixS *fix_new_aarch64 (fragS *, int, short, expressionS *, int, int);
 static struct reloc_table_entry * find_reloc_table_entry (char **);
 
 /* Directives: Data.  */
@@ -1900,7 +1899,7 @@ static struct reloc_table_entry * find_reloc_table_entry (char **);
    implemented properly.  */
 
 static void
-s_aarch64_elf_cons (int nbytes)
+s_aarch64_cons (int nbytes)
 {
   expressionS exp;
 
@@ -1950,6 +1949,12 @@ s_aarch64_elf_cons (int nbytes)
   input_line_pointer--;
   demand_empty_rest_of_line ();
 }
+#endif
+
+#ifdef OBJ_ELF
+/* Forward declarations for functions below, in the MD interface
+   section.  */
+ static fixS *fix_new_aarch64 (fragS *, int, short, expressionS *, int, int);
 
 /* Mark symbol that it follows a variant PCS convention.  */
 
@@ -2119,11 +2124,13 @@ const pseudo_typeS md_pseudo_table[] = {
   {"tlsdescadd", s_tlsdescadd, 0},
   {"tlsdesccall", s_tlsdesccall, 0},
   {"tlsdescldr", s_tlsdescldr, 0},
-  {"word", s_aarch64_elf_cons, 4},
-  {"long", s_aarch64_elf_cons, 4},
-  {"xword", s_aarch64_elf_cons, 8},
-  {"dword", s_aarch64_elf_cons, 8},
   {"variant_pcs", s_variant_pcs, 0},
+#endif
+#if defined(OBJ_ELF) || defined(OBJ_COFF)
+  {"word", s_aarch64_cons, 4},
+  {"long", s_aarch64_cons, 4},
+  {"xword", s_aarch64_cons, 8},
+  {"dword", s_aarch64_cons, 8},
 #endif
   {"float16", float_cons, 'h'},
   {"bfloat16", float_cons, 'b'},
@@ -9260,6 +9267,9 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
       /* An error will already have been reported.  */
       break;
 
+    case BFD_RELOC_RVA:
+      break;
+
     default:
       as_bad_where (fixP->fx_file, fixP->fx_line,
 		    _("unexpected %s fixup"),
diff --git a/gas/testsuite/gas/pe/pe-aarch64.d b/gas/testsuite/gas/pe/pe-aarch64.d
index 0b8009da5c4..eb611031183 100644
--- a/gas/testsuite/gas/pe/pe-aarch64.d
+++ b/gas/testsuite/gas/pe/pe-aarch64.d
@@ -1,14 +1,232 @@
 #as:
-#objdump: -d
+#objdump: -dr
 
 .*:     file format pe-aarch64-little
 
 
 Disassembly of section .text:
 
-0000000000000000 <_start>:
-   0:	d2800281 	mov	x1, #0x14                  	// #20
-   4:	14000001 	b	8 <foo>
+0000000000000000 <.text>:
+	...
 
-0000000000000008 <foo>:
-   8:	d65f03c0 	ret
+0000000000000010 <foo>:
+  10:	12345678 	and	w24, w19, #0xfffff003
+  14:	12345678 	and	w24, w19, #0xfffff003
+  18:	00000010 	udf	#16
+			18: IMAGE_REL_ARM64_ADDR32	.text
+  1c:	00000010 	udf	#16
+			1c: IMAGE_REL_ARM64_ADDR32	.text
+	...
+			20: IMAGE_REL_ARM64_ADDR32	bar
+			24: IMAGE_REL_ARM64_ADDR32	bar
+  28:	00000011 	udf	#17
+			28: IMAGE_REL_ARM64_ADDR32	.text
+  2c:	00000011 	udf	#17
+			2c: IMAGE_REL_ARM64_ADDR32	.text
+  30:	00000001 	udf	#1
+			30: IMAGE_REL_ARM64_ADDR32	bar
+  34:	00000001 	udf	#1
+			34: IMAGE_REL_ARM64_ADDR32	bar
+  38:	0000000f 	udf	#15
+			38: IMAGE_REL_ARM64_ADDR32	.text
+  3c:	0000000f 	udf	#15
+			3c: IMAGE_REL_ARM64_ADDR32	.text
+  40:	ffffffff 	.inst	0xffffffff ; undefined
+			40: IMAGE_REL_ARM64_ADDR32	bar
+  44:	ffffffff 	.inst	0xffffffff ; undefined
+			44: IMAGE_REL_ARM64_ADDR32	bar
+  48:	9abcdef0 	.inst	0x9abcdef0 ; undefined
+  4c:	12345678 	and	w24, w19, #0xfffff003
+  50:	9abcdef0 	.inst	0x9abcdef0 ; undefined
+  54:	12345678 	and	w24, w19, #0xfffff003
+  58:	00000010 	udf	#16
+			58: IMAGE_REL_ARM64_ADDR64	.text
+  5c:	00000000 	udf	#0
+  60:	00000010 	udf	#16
+			60: IMAGE_REL_ARM64_ADDR64	.text
+	...
+			68: IMAGE_REL_ARM64_ADDR64	bar
+			70: IMAGE_REL_ARM64_ADDR64	bar
+  78:	00000011 	udf	#17
+			78: IMAGE_REL_ARM64_ADDR64	.text
+  7c:	00000000 	udf	#0
+  80:	00000011 	udf	#17
+			80: IMAGE_REL_ARM64_ADDR64	.text
+  84:	00000000 	udf	#0
+  88:	00000001 	udf	#1
+			88: IMAGE_REL_ARM64_ADDR64	bar
+  8c:	00000000 	udf	#0
+  90:	00000001 	udf	#1
+			90: IMAGE_REL_ARM64_ADDR64	bar
+  94:	00000000 	udf	#0
+  98:	0000000f 	udf	#15
+			98: IMAGE_REL_ARM64_ADDR64	.text
+  9c:	00000000 	udf	#0
+  a0:	0000000f 	udf	#15
+			a0: IMAGE_REL_ARM64_ADDR64	.text
+  a4:	00000000 	udf	#0
+  a8:	ffffffff 	.inst	0xffffffff ; undefined
+			a8: IMAGE_REL_ARM64_ADDR64	bar
+  ac:	ffffffff 	.inst	0xffffffff ; undefined
+  b0:	ffffffff 	.inst	0xffffffff ; undefined
+			b0: IMAGE_REL_ARM64_ADDR64	bar
+  b4:	ffffffff 	.inst	0xffffffff ; undefined
+  b8:	00000010 	udf	#16
+			b8: IMAGE_REL_ARM64_ADDR32NB	.text
+  bc:	00000000 	udf	#0
+			bc: IMAGE_REL_ARM64_ADDR32NB	bar
+  c0:	00000011 	udf	#17
+			c0: IMAGE_REL_ARM64_ADDR32NB	.text
+  c4:	00000001 	udf	#1
+			c4: IMAGE_REL_ARM64_ADDR32NB	bar
+  c8:	0000000f 	udf	#15
+			c8: IMAGE_REL_ARM64_ADDR32NB	.text
+  cc:	ffffffff 	.inst	0xffffffff ; undefined
+			cc: IMAGE_REL_ARM64_ADDR32NB	bar
+  d0:	17ffffd0 	b	10 <foo>
+  d4:	17ffffd0 	b	14 <foo\+0x4>
+  d8:	17ffffcd 	b	c <.text\+0xc>
+  dc:	14000000 	b	0 <bar>
+			dc: IMAGE_REL_ARM64_BRANCH26	bar
+  e0:	14000001 	b	4 <bar\+0x4>
+			e0: IMAGE_REL_ARM64_BRANCH26	bar
+  e4:	17ffffff 	b	fffffffffffffffc <bar\+0xfffffffffffffffc>
+			e4: IMAGE_REL_ARM64_BRANCH26	bar
+  e8:	97ffffca 	bl	10 <foo>
+  ec:	97ffffca 	bl	14 <foo\+0x4>
+  f0:	97ffffc7 	bl	c <.text\+0xc>
+  f4:	94000000 	bl	0 <bar>
+			f4: IMAGE_REL_ARM64_BRANCH26	bar
+  f8:	94000001 	bl	4 <bar\+0x4>
+			f8: IMAGE_REL_ARM64_BRANCH26	bar
+  fc:	97ffffff 	bl	fffffffffffffffc <bar\+0xfffffffffffffffc>
+			fc: IMAGE_REL_ARM64_BRANCH26	bar
+ 100:	97ffffbf 	bl	fffffffffffffffc <foo\+0xffffffffffffffec>
+ 104:	b4fff860 	cbz	x0, 10 <foo>
+ 108:	b4fff860 	cbz	x0, 14 <foo\+0x4>
+ 10c:	b4fff800 	cbz	x0, c <.text\+0xc>
+ 110:	b4000000 	cbz	x0, 0 <bar>
+			110: IMAGE_REL_ARM64_BRANCH19	bar
+ 114:	b4000020 	cbz	x0, 4 <bar\+0x4>
+			114: IMAGE_REL_ARM64_BRANCH19	bar
+ 118:	b4ffffe0 	cbz	x0, fffffffffffffffc <bar\+0xfffffffffffffffc>
+			118: IMAGE_REL_ARM64_BRANCH19	bar
+ 11c:	b4fff700 	cbz	x0, fffffffffffffffc <foo\+0xffffffffffffffec>
+ 120:	3607f780 	tbz	w0, #0, 10 <foo>
+ 124:	3607f780 	tbz	w0, #0, 14 <foo\+0x4>
+ 128:	3607f720 	tbz	w0, #0, c <.text\+0xc>
+ 12c:	36000000 	tbz	w0, #0, 0 <bar>
+			12c: IMAGE_REL_ARM64_BRANCH14	bar
+ 130:	36000020 	tbz	w0, #0, 4 <bar\+0x4>
+			130: IMAGE_REL_ARM64_BRANCH14	bar
+ 134:	3607ffe0 	tbz	w0, #0, fffffffffffffffc <bar\+0xfffffffffffffffc>
+			134: IMAGE_REL_ARM64_BRANCH14	bar
+ 138:	3607f620 	tbz	w0, #0, fffffffffffffffc <foo\+0xffffffffffffffec>
+ 13c:	90000080 	adrp	x0, 10000 <foo\+0xfff0>
+			13c: IMAGE_REL_ARM64_PAGEBASE_REL21	.text
+ 140:	b0000080 	adrp	x0, 11000 <foo\+0x10ff0>
+			140: IMAGE_REL_ARM64_PAGEBASE_REL21	.text
+ 144:	f0000060 	adrp	x0, f000 <foo\+0xeff0>
+			144: IMAGE_REL_ARM64_PAGEBASE_REL21	.text
+ 148:	90000000 	adrp	x0, 0 <bar>
+			148: IMAGE_REL_ARM64_PAGEBASE_REL21	bar
+ 14c:	b0000000 	adrp	x0, 1000 <bar\+0x1000>
+			14c: IMAGE_REL_ARM64_PAGEBASE_REL21	bar
+ 150:	f0ffffe0 	adrp	x0, fffffffffffff000 <bar\+0xfffffffffffff000>
+			150: IMAGE_REL_ARM64_PAGEBASE_REL21	bar
+ 154:	90ffffe0 	adrp	x0, ffffffffffffc000 <foo\+0xffffffffffffbff0>
+			154: IMAGE_REL_ARM64_PAGEBASE_REL21	.text
+ 158:	10fff5c0 	adr	x0, 10 <foo>
+ 15c:	30fff5a0 	adr	x0, 11 <foo\+0x1>
+ 160:	70fff560 	adr	x0, f <.text\+0xf>
+ 164:	10000000 	adr	x0, 0 <bar>
+			164: IMAGE_REL_ARM64_REL21	bar
+ 168:	30000000 	adr	x0, 1 <bar\+0x1>
+			168: IMAGE_REL_ARM64_REL21	bar
+ 16c:	70ffffe0 	adr	x0, ffffffffffffffff <bar\+0xffffffffffffffff>
+			16c: IMAGE_REL_ARM64_REL21	bar
+ 170:	70fff460 	adr	x0, ffffffffffffffff <foo\+0xffffffffffffffef>
+ 174:	39004000 	strb	w0, \[x0, #16\]
+			174: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 178:	39005000 	strb	w0, \[x0, #20\]
+			178: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 17c:	39003000 	strb	w0, \[x0, #12\]
+			17c: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 180:	39000000 	strb	w0, \[x0\]
+			180: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 184:	39001000 	strb	w0, \[x0, #4\]
+			184: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 188:	393ff000 	strb	w0, \[x0, #4092\]
+			188: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 18c:	393ff000 	strb	w0, \[x0, #4092\]
+			18c: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 190:	79002000 	strh	w0, \[x0, #16\]
+			190: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 194:	79002800 	strh	w0, \[x0, #20\]
+			194: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 198:	79001800 	strh	w0, \[x0, #12\]
+			198: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 19c:	79000000 	strh	w0, \[x0\]
+			19c: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1a0:	79000800 	strh	w0, \[x0, #4\]
+			1a0: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1a4:	791ff800 	strh	w0, \[x0, #4092\]
+			1a4: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1a8:	791ff800 	strh	w0, \[x0, #4092\]
+			1a8: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1ac:	b9001000 	str	w0, \[x0, #16\]
+			1ac: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1b0:	b9001400 	str	w0, \[x0, #20\]
+			1b0: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1b4:	b9000c00 	str	w0, \[x0, #12\]
+			1b4: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1b8:	b9000000 	str	w0, \[x0\]
+			1b8: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1bc:	b9000400 	str	w0, \[x0, #4\]
+			1bc: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1c0:	b90ffc00 	str	w0, \[x0, #4092\]
+			1c0: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1c4:	b90ffc00 	str	w0, \[x0, #4092\]
+			1c4: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1c8:	f9000800 	str	x0, \[x0, #16\]
+			1c8: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1cc:	f9000c00 	str	x0, \[x0, #24\]
+			1cc: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1d0:	f9000400 	str	x0, \[x0, #8\]
+			1d0: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1d4:	f9000000 	str	x0, \[x0\]
+			1d4: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1d8:	f9000400 	str	x0, \[x0, #8\]
+			1d8: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1dc:	f907fc00 	str	x0, \[x0, #4088\]
+			1dc: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1e0:	f907fc00 	str	x0, \[x0, #4088\]
+			1e0: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1e4:	3d800400 	str	q0, \[x0, #16\]
+			1e4: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1e8:	3d800800 	str	q0, \[x0, #32\]
+			1e8: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1ec:	3d800000 	str	q0, \[x0\]
+			1ec: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 1f0:	3d800000 	str	q0, \[x0\]
+			1f0: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1f4:	3d800400 	str	q0, \[x0, #16\]
+			1f4: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1f8:	3d83fc00 	str	q0, \[x0, #4080\]
+			1f8: IMAGE_REL_ARM64_PAGEOFFSET_12L	bar
+ 1fc:	3d83fc00 	str	q0, \[x0, #4080\]
+			1fc: IMAGE_REL_ARM64_PAGEOFFSET_12L	.text
+ 200:	91004000 	add	x0, x0, #0x10
+			200: IMAGE_REL_ARM64_PAGEOFFSET_12A	.text
+ 204:	91004400 	add	x0, x0, #0x11
+			204: IMAGE_REL_ARM64_PAGEOFFSET_12A	.text
+ 208:	91003c00 	add	x0, x0, #0xf
+			208: IMAGE_REL_ARM64_PAGEOFFSET_12A	.text
+ 20c:	91000000 	add	x0, x0, #0x0
+			20c: IMAGE_REL_ARM64_PAGEOFFSET_12A	bar
+ 210:	91000400 	add	x0, x0, #0x1
+			210: IMAGE_REL_ARM64_PAGEOFFSET_12A	bar
+ 214:	913ffc00 	add	x0, x0, #0xfff
+			214: IMAGE_REL_ARM64_PAGEOFFSET_12A	bar
+ 218:	913ffc00 	add	x0, x0, #0xfff
+			218: IMAGE_REL_ARM64_PAGEOFFSET_12A	.text
diff --git a/gas/testsuite/gas/pe/pe-aarch64.s b/gas/testsuite/gas/pe/pe-aarch64.s
index 546d55fc361..2a02d2d1c0d 100644
--- a/gas/testsuite/gas/pe/pe-aarch64.s
+++ b/gas/testsuite/gas/pe/pe-aarch64.s
@@ -1,11 +1,157 @@
-# 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
+.text
 
-.section .text
+.dword 0
+.dword 0
 
-_start:
-    mov x1, 20
-    b foo
 foo:
-    ret
+
+# 4-byte literal
+.long 0x12345678
+.word 0x12345678
+
+# IMAGE_REL_ARM64_ADDR32 (BFD_RELOC_32)
+.long foo
+.word foo
+.long bar
+.word bar
+.long foo + 1
+.word foo + 1
+.long bar + 1
+.word bar + 1
+.long foo - 1
+.word foo - 1
+.long bar - 1
+.word bar - 1
+
+# 8-byte literal
+.dword 0x123456789abcdef0
+.xword 0x123456789abcdef0
+
+# IMAGE_REL_ARM64_ADDR64 (BFD_RELOC_64)
+.dword foo
+.xword foo
+.dword bar
+.xword bar
+.dword foo + 1
+.xword foo + 1
+.dword bar + 1
+.xword bar + 1
+.dword foo - 1
+.xword foo - 1
+.dword bar - 1
+.xword bar - 1
+
+# IMAGE_REL_ARM64_ADDR32NB (BFD_RELOC_RVA)
+.rva foo
+.rva bar
+.rva foo + 1
+.rva bar + 1
+.rva foo - 1
+.rva bar - 1
+
+# IMAGE_REL_ARM64_BRANCH26 (BFD_RELOC_AARCH64_JUMP26)
+b foo
+b foo + 4
+b foo - 4
+b bar
+b bar + 4
+b bar - 4
+
+# IMAGE_REL_ARM64_BRANCH26 (BFD_RELOC_AARCH64_CALL26)
+bl foo
+bl foo + 4
+bl foo - 4
+bl bar
+bl bar + 4
+bl bar - 4
+bl .text - 4
+
+# IMAGE_REL_ARM64_BRANCH19 (BFD_RELOC_AARCH64_BRANCH19)
+cbz x0, foo
+cbz x0, foo + 4
+cbz x0, foo - 4
+cbz x0, bar
+cbz x0, bar + 4
+cbz x0, bar - 4
+cbz x0, .text - 4
+
+# IMAGE_REL_ARM64_BRANCH14 (BFD_RELOC_AARCH64_TSTBR14)
+tbz x0, 0, foo
+tbz x0, 0, foo + 4
+tbz x0, 0, foo - 4
+tbz x0, 0, bar
+tbz x0, 0, bar + 4
+tbz x0, 0, bar - 4
+tbz x0, 0, .text - 4
+
+# IMAGE_REL_ARM64_PAGEBASE_REL21 (BFD_RELOC_AARCH64_ADR_HI21_PCREL)
+adrp x0, foo
+adrp x0, foo + 1
+adrp x0, foo - 1
+adrp x0, bar
+adrp x0, bar + 1
+adrp x0, bar - 1
+adrp x0, .text - 4
+
+# IMAGE_REL_ARM64_REL21 (BFD_RELOC_AARCH64_ADR_LO21_PCREL)
+adr x0, foo
+adr x0, foo + 1
+adr x0, foo - 1
+adr x0, bar
+adr x0, bar + 1
+adr x0, bar - 1
+adr x0, .text - 1
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST8_LO12)
+strb w0, [x0,:lo12:foo]
+strb w0, [x0,:lo12:foo + 4]
+strb w0, [x0,:lo12:foo - 4]
+strb w0, [x0,:lo12:bar]
+strb w0, [x0,:lo12:bar + 4]
+strb w0, [x0,:lo12:bar - 4]
+strb w0, [x0,:lo12:.text - 4]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST16_LO12)
+strh w0, [x0,:lo12:foo]
+strh w0, [x0,:lo12:foo + 4]
+strh w0, [x0,:lo12:foo - 4]
+strh w0, [x0,:lo12:bar]
+strh w0, [x0,:lo12:bar + 4]
+strh w0, [x0,:lo12:bar - 4]
+strh w0, [x0,:lo12:.text - 4]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST32_LO12)
+str w0, [x0,:lo12:foo]
+str w0, [x0,:lo12:foo + 4]
+str w0, [x0,:lo12:foo - 4]
+str w0, [x0,:lo12:bar]
+str w0, [x0,:lo12:bar + 4]
+str w0, [x0,:lo12:bar - 4]
+str w0, [x0,:lo12:.text - 4]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST64_LO12)
+str x0, [x0,:lo12:foo]
+str x0, [x0,:lo12:foo + 8]
+str x0, [x0,:lo12:foo - 8]
+str x0, [x0,:lo12:bar]
+str x0, [x0,:lo12:bar + 8]
+str x0, [x0,:lo12:bar - 8]
+str x0, [x0,:lo12:.text - 8]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST128_LO12)
+str q0, [x0,:lo12:foo]
+str q0, [x0,:lo12:foo + 16]
+str q0, [x0,:lo12:foo - 16]
+str q0, [x0,:lo12:bar]
+str q0, [x0,:lo12:bar + 16]
+str q0, [x0,:lo12:bar - 16]
+str q0, [x0,:lo12:.text - 16]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12A (BFD_RELOC_AARCH64_ADD_LO12)
+add x0, x0, #:lo12:foo
+add x0, x0, #:lo12:foo + 1
+add x0, x0, #:lo12:foo - 1
+add x0, x0, #:lo12:bar
+add x0, x0, #:lo12:bar + 1
+add x0, x0, #:lo12:bar - 1
+add x0, x0, #:lo12:.text - 1
diff --git a/ld/testsuite/ld-pe/aarch64.d b/ld/testsuite/ld-pe/aarch64.d
new file mode 100644
index 00000000000..cc3daf9e9cd
--- /dev/null
+++ b/ld/testsuite/ld-pe/aarch64.d
@@ -0,0 +1,158 @@
+
+tmpdir/aarch64.x:     file format pei-aarch64-little
+
+
+Disassembly of section .text:
+
+0000000000002000 <__rt_psrelocs_end>:
+	...
+
+0000000000002010 <foo>:
+    2010:	12345678 	and	w24, w19, #0xfffff003
+    2014:	12345678 	and	w24, w19, #0xfffff003
+    2018:	00002000 	udf	#8192
+    201c:	00002000 	udf	#8192
+    2020:	00002220 	udf	#8736
+    2024:	00002220 	udf	#8736
+    2028:	00002001 	udf	#8193
+    202c:	00002001 	udf	#8193
+    2030:	00002221 	udf	#8737
+    2034:	00002221 	udf	#8737
+    2038:	00001fff 	udf	#8191
+    203c:	00001fff 	udf	#8191
+    2040:	0000221f 	udf	#8735
+    2044:	0000221f 	udf	#8735
+    2048:	9abcdef0 	.inst	0x9abcdef0 ; undefined
+    204c:	12345678 	and	w24, w19, #0xfffff003
+    2050:	9abcdef0 	.inst	0x9abcdef0 ; undefined
+    2054:	12345678 	and	w24, w19, #0xfffff003
+    2058:	00002000 	udf	#8192
+    205c:	00000000 	udf	#0
+    2060:	00002000 	udf	#8192
+    2064:	00000000 	udf	#0
+    2068:	00002220 	udf	#8736
+    206c:	00000000 	udf	#0
+    2070:	00002220 	udf	#8736
+    2074:	00000000 	udf	#0
+    2078:	00002001 	udf	#8193
+    207c:	00000000 	udf	#0
+    2080:	00002001 	udf	#8193
+    2084:	00000000 	udf	#0
+    2088:	00002221 	udf	#8737
+    208c:	00000000 	udf	#0
+    2090:	00002221 	udf	#8737
+    2094:	00000000 	udf	#0
+    2098:	00001fff 	udf	#8191
+    209c:	00000000 	udf	#0
+    20a0:	00001fff 	udf	#8191
+    20a4:	00000000 	udf	#0
+    20a8:	0000221f 	udf	#8735
+    20ac:	00000000 	udf	#0
+    20b0:	0000221f 	udf	#8735
+    20b4:	00000000 	udf	#0
+    20b8:	00001010 	udf	#4112
+    20bc:	00001220 	udf	#4640
+    20c0:	00001011 	udf	#4113
+    20c4:	00001221 	udf	#4641
+    20c8:	0000100f 	udf	#4111
+    20cc:	0000121f 	udf	#4639
+    20d0:	17ffffd0 	b	2010 <foo>
+    20d4:	17ffffd0 	b	2014 <foo\+0x4>
+    20d8:	17ffffcd 	b	200c <__rt_psrelocs_end\+0xc>
+    20dc:	14000051 	b	2220 <bar>
+    20e0:	14000051 	b	2224 <bar\+0x4>
+    20e4:	1400004e 	b	221c <.text>
+    20e8:	97ffffca 	bl	2010 <foo>
+    20ec:	97ffffca 	bl	2014 <foo\+0x4>
+    20f0:	97ffffc7 	bl	200c <__rt_psrelocs_end\+0xc>
+    20f4:	9400004b 	bl	2220 <bar>
+    20f8:	9400004b 	bl	2224 <bar\+0x4>
+    20fc:	94000048 	bl	221c <.text>
+    2100:	97ffffbf 	bl	1ffc <__ImageBase\+0xffc>
+    2104:	b4fff860 	cbz	x0, 2010 <foo>
+    2108:	b4fff860 	cbz	x0, 2014 <foo\+0x4>
+    210c:	b4fff800 	cbz	x0, 200c <__rt_psrelocs_end\+0xc>
+    2110:	b4000880 	cbz	x0, 2220 <bar>
+    2114:	b4000880 	cbz	x0, 2224 <bar\+0x4>
+    2118:	b4000820 	cbz	x0, 221c <.text>
+    211c:	b4fff700 	cbz	x0, 1ffc <__ImageBase\+0xffc>
+    2120:	3607f780 	tbz	w0, #0, 2010 <foo>
+    2124:	3607f780 	tbz	w0, #0, 2014 <foo\+0x4>
+    2128:	3607f720 	tbz	w0, #0, 200c <__rt_psrelocs_end\+0xc>
+    212c:	360007a0 	tbz	w0, #0, 2220 <bar>
+    2130:	360007a0 	tbz	w0, #0, 2224 <bar\+0x4>
+    2134:	36000740 	tbz	w0, #0, 221c <.text>
+    2138:	3607f620 	tbz	w0, #0, 1ffc <__ImageBase\+0xffc>
+    213c:	90000000 	adrp	x0, 2000 <__rt_psrelocs_end>
+    2140:	90000000 	adrp	x0, 2000 <__rt_psrelocs_end>
+    2144:	90000000 	adrp	x0, 2000 <__rt_psrelocs_end>
+    2148:	90000000 	adrp	x0, 2000 <__rt_psrelocs_end>
+    214c:	90000000 	adrp	x0, 2000 <__rt_psrelocs_end>
+    2150:	90000000 	adrp	x0, 2000 <__rt_psrelocs_end>
+    2154:	f0ffffe0 	adrp	x0, 1000 <__ImageBase>
+    2158:	10fff5c0 	adr	x0, 2010 <foo>
+    215c:	30fff5a0 	adr	x0, 2011 <foo\+0x1>
+    2160:	70fff560 	adr	x0, 200f <__rt_psrelocs_end\+0xf>
+    2164:	100005e0 	adr	x0, 2220 <bar>
+    2168:	300005c0 	adr	x0, 2221 <bar\+0x1>
+    216c:	70000580 	adr	x0, 221f <.text\+0x3>
+    2170:	70fff460 	adr	x0, 1fff <__ImageBase\+0xfff>
+    2174:	39004000 	strb	w0, \[x0, #16\]
+    2178:	39005000 	strb	w0, \[x0, #20\]
+    217c:	39003000 	strb	w0, \[x0, #12\]
+    2180:	39088000 	strb	w0, \[x0, #544\]
+    2184:	39089000 	strb	w0, \[x0, #548\]
+    2188:	39087000 	strb	w0, \[x0, #540\]
+    218c:	393ff000 	strb	w0, \[x0, #4092\]
+    2190:	79002000 	strh	w0, \[x0, #16\]
+    2194:	79002800 	strh	w0, \[x0, #20\]
+    2198:	79001800 	strh	w0, \[x0, #12\]
+    219c:	79044000 	strh	w0, \[x0, #544\]
+    21a0:	79044800 	strh	w0, \[x0, #548\]
+    21a4:	79043800 	strh	w0, \[x0, #540\]
+    21a8:	791ff800 	strh	w0, \[x0, #4092\]
+    21ac:	b9001000 	str	w0, \[x0, #16\]
+    21b0:	b9001400 	str	w0, \[x0, #20\]
+    21b4:	b9000c00 	str	w0, \[x0, #12\]
+    21b8:	b9022000 	str	w0, \[x0, #544\]
+    21bc:	b9022400 	str	w0, \[x0, #548\]
+    21c0:	b9021c00 	str	w0, \[x0, #540\]
+    21c4:	b90ffc00 	str	w0, \[x0, #4092\]
+    21c8:	f9000800 	str	x0, \[x0, #16\]
+    21cc:	f9000c00 	str	x0, \[x0, #24\]
+    21d0:	f9000400 	str	x0, \[x0, #8\]
+    21d4:	f9011000 	str	x0, \[x0, #544\]
+    21d8:	f9011400 	str	x0, \[x0, #552\]
+    21dc:	f9010c00 	str	x0, \[x0, #536\]
+    21e0:	f907fc00 	str	x0, \[x0, #4088\]
+    21e4:	3d800400 	str	q0, \[x0, #16\]
+    21e8:	3d800800 	str	q0, \[x0, #32\]
+    21ec:	3d800000 	str	q0, \[x0\]
+    21f0:	3d808800 	str	q0, \[x0, #544\]
+    21f4:	3d808c00 	str	q0, \[x0, #560\]
+    21f8:	3d808400 	str	q0, \[x0, #528\]
+    21fc:	3d83fc00 	str	q0, \[x0, #4080\]
+    2200:	91004000 	add	x0, x0, #0x10
+    2204:	91004400 	add	x0, x0, #0x11
+    2208:	91003c00 	add	x0, x0, #0xf
+    220c:	91088000 	add	x0, x0, #0x220
+    2210:	91088400 	add	x0, x0, #0x221
+    2214:	91087c00 	add	x0, x0, #0x21f
+    2218:	913ffc00 	add	x0, x0, #0xfff
+
+000000000000221c <.text>:
+    221c:	00000000 	udf	#0
+
+0000000000002220 <bar>:
+    2220:	9abcdef0 	.inst	0x9abcdef0 ; undefined
+    2224:	12345678 	and	w24, w19, #0xfffff003
+
+0000000000002228 <__CTOR_LIST__>:
+    2228:	ffffffff 	.inst	0xffffffff ; undefined
+    222c:	ffffffff 	.inst	0xffffffff ; undefined
+	...
+
+0000000000002238 <__DTOR_LIST__>:
+    2238:	ffffffff 	.inst	0xffffffff ; undefined
+    223c:	ffffffff 	.inst	0xffffffff ; undefined
+	...
diff --git a/ld/testsuite/ld-pe/aarch64a.s b/ld/testsuite/ld-pe/aarch64a.s
new file mode 100644
index 00000000000..58b8f5a00c0
--- /dev/null
+++ b/ld/testsuite/ld-pe/aarch64a.s
@@ -0,0 +1,159 @@
+.text
+
+.dword 0
+.dword 0
+
+# 2010
+.global foo
+foo:
+
+# 4-byte literal
+.long 0x12345678
+.word 0x12345678
+
+# IMAGE_REL_ARM64_ADDR32 (BFD_RELOC_32)
+.long foo
+.word foo
+.long bar
+.word bar
+.long foo + 1
+.word foo + 1
+.long bar + 1
+.word bar + 1
+.long foo - 1
+.word foo - 1
+.long bar - 1
+.word bar - 1
+
+# 8-byte literal
+.dword 0x123456789abcdef0
+.xword 0x123456789abcdef0
+
+# IMAGE_REL_ARM64_ADDR64 (BFD_RELOC_64)
+.dword foo
+.xword foo
+.dword bar
+.xword bar
+.dword foo + 1
+.xword foo + 1
+.dword bar + 1
+.xword bar + 1
+.dword foo - 1
+.xword foo - 1
+.dword bar - 1
+.xword bar - 1
+
+# IMAGE_REL_ARM64_ADDR32NB (BFD_RELOC_RVA)
+.rva foo
+.rva bar
+.rva foo + 1
+.rva bar + 1
+.rva foo - 1
+.rva bar - 1
+
+# IMAGE_REL_ARM64_BRANCH26 (BFD_RELOC_AARCH64_JUMP26)
+b foo
+b foo + 4
+b foo - 4
+b bar
+b bar + 4
+b bar - 4
+
+# IMAGE_REL_ARM64_BRANCH26 (BFD_RELOC_AARCH64_CALL26)
+bl foo
+bl foo + 4
+bl foo - 4
+bl bar
+bl bar + 4
+bl bar - 4
+bl .text - 4
+
+# IMAGE_REL_ARM64_BRANCH19 (BFD_RELOC_AARCH64_BRANCH19)
+cbz x0, foo
+cbz x0, foo + 4
+cbz x0, foo - 4
+cbz x0, bar
+cbz x0, bar + 4
+cbz x0, bar - 4
+cbz x0, .text - 4
+
+# IMAGE_REL_ARM64_BRANCH14 (BFD_RELOC_AARCH64_TSTBR14)
+tbz x0, 0, foo
+tbz x0, 0, foo + 4
+tbz x0, 0, foo - 4
+tbz x0, 0, bar
+tbz x0, 0, bar + 4
+tbz x0, 0, bar - 4
+tbz x0, 0, .text - 4
+
+# IMAGE_REL_ARM64_PAGEBASE_REL21 (BFD_RELOC_AARCH64_ADR_HI21_PCREL)
+adrp x0, foo
+adrp x0, foo + 1
+adrp x0, foo - 1
+adrp x0, bar
+adrp x0, bar + 1
+adrp x0, bar - 1
+adrp x0, .text - 4
+
+# IMAGE_REL_ARM64_REL21 (BFD_RELOC_AARCH64_ADR_LO21_PCREL)
+adr x0, foo
+adr x0, foo + 1
+adr x0, foo - 1
+adr x0, bar
+adr x0, bar + 1
+adr x0, bar - 1
+adr x0, .text - 1
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST8_LO12)
+strb w0, [x0,:lo12:foo]
+strb w0, [x0,:lo12:foo + 4]
+strb w0, [x0,:lo12:foo - 4]
+strb w0, [x0,:lo12:bar]
+strb w0, [x0,:lo12:bar + 4]
+strb w0, [x0,:lo12:bar - 4]
+strb w0, [x0,:lo12:.text - 4]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST16_LO12)
+strh w0, [x0,:lo12:foo]
+strh w0, [x0,:lo12:foo + 4]
+strh w0, [x0,:lo12:foo - 4]
+strh w0, [x0,:lo12:bar]
+strh w0, [x0,:lo12:bar + 4]
+strh w0, [x0,:lo12:bar - 4]
+strh w0, [x0,:lo12:.text - 4]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST32_LO12)
+str w0, [x0,:lo12:foo]
+str w0, [x0,:lo12:foo + 4]
+str w0, [x0,:lo12:foo - 4]
+str w0, [x0,:lo12:bar]
+str w0, [x0,:lo12:bar + 4]
+str w0, [x0,:lo12:bar - 4]
+str w0, [x0,:lo12:.text - 4]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST64_LO12)
+str x0, [x0,:lo12:foo]
+str x0, [x0,:lo12:foo + 8]
+str x0, [x0,:lo12:foo - 8]
+str x0, [x0,:lo12:bar]
+str x0, [x0,:lo12:bar + 8]
+str x0, [x0,:lo12:bar - 8]
+str x0, [x0,:lo12:.text - 8]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12L (BFD_RELOC_AARCH64_LDST128_LO12)
+str q0, [x0,:lo12:foo]
+str q0, [x0,:lo12:foo + 16]
+str q0, [x0,:lo12:foo - 16]
+str q0, [x0,:lo12:bar]
+str q0, [x0,:lo12:bar + 16]
+str q0, [x0,:lo12:bar - 16]
+str q0, [x0,:lo12:.text - 16]
+
+# IMAGE_REL_ARM64_PAGEOFFSET_12A (BFD_RELOC_AARCH64_ADD_LO12)
+add x0, x0, #:lo12:foo
+add x0, x0, #:lo12:foo + 1
+add x0, x0, #:lo12:foo - 1
+add x0, x0, #:lo12:bar
+add x0, x0, #:lo12:bar + 1
+add x0, x0, #:lo12:bar - 1
+add x0, x0, #:lo12:.text - 1
diff --git a/ld/testsuite/ld-pe/aarch64b.s b/ld/testsuite/ld-pe/aarch64b.s
new file mode 100644
index 00000000000..3f4ec48f724
--- /dev/null
+++ b/ld/testsuite/ld-pe/aarch64b.s
@@ -0,0 +1,8 @@
+.text
+
+.long 0
+
+# 2220
+.global bar
+bar:
+.dword 0x123456789abcdef0
diff --git a/ld/testsuite/ld-pe/pe.exp b/ld/testsuite/ld-pe/pe.exp
index 613635fd609..c22c6d449f9 100644
--- a/ld/testsuite/ld-pe/pe.exp
+++ b/ld/testsuite/ld-pe/pe.exp
@@ -79,9 +79,15 @@ if {[istarget i*86-*-cygwin*]
 }
 
 if {[istarget "aarch64-*-pe*"]} {
-	run_dump_test "pe-aarch64"
-}
+    run_dump_test "pe-aarch64"
+
+    set pe_tests {
+      {"aarch64" "--image-base 0x1000" "" "" {aarch64a.s aarch64b.s}
+	{{objdump -dr aarch64.d}} "aarch64.x"}
+    }
 
+    run_ld_link_tests $pe_tests
+}
 
 run_dump_test "image_size"
 run_dump_test "export_dynamic_warning"
