AArch64: Fix -Werror on build
[deliverable/binutils-gdb.git] / bfd / elfnn-aarch64.c
index cf321f32c209755c1e9e86386c2fbba066f41f90..9e28544e4bd4d84cb85a156991a399656d13b10a 100644 (file)
@@ -1,5 +1,5 @@
 /* AArch64-specific support for NN-bit ELF.
-   Copyright (C) 2009-2018 Free Software Foundation, Inc.
+   Copyright (C) 2009-2019 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of BFD, the Binary File Descriptor library.
 #include "bfd.h"
 #include "libiberty.h"
 #include "libbfd.h"
-#include "bfd_stdint.h"
 #include "elf-bfd.h"
 #include "bfdlink.h"
 #include "objalloc.h"
 #define PLT_ENTRY_SIZE                 (32)
 #define PLT_SMALL_ENTRY_SIZE           (16)
 #define PLT_TLSDESC_ENTRY_SIZE         (32)
+/* PLT sizes with BTI insn.  */
+#define PLT_BTI_SMALL_ENTRY_SIZE       (24)
+/* PLT sizes with PAC insn.  */
+#define PLT_PAC_SMALL_ENTRY_SIZE       (24)
+/* PLT sizes with BTI and PAC insn.  */
+#define PLT_BTI_PAC_SMALL_ENTRY_SIZE   (24)
 
 /* Encoding of the nop instruction.  */
 #define INSN_NOP 0xd503201f
@@ -298,9 +303,26 @@ static const bfd_byte elfNN_aarch64_small_plt0_entry[PLT_ENTRY_SIZE] =
   0x1f, 0x20, 0x03, 0xd5,      /* nop */
 };
 
+static const bfd_byte elfNN_aarch64_small_plt0_bti_entry[PLT_ENTRY_SIZE] =
+{
+  0x5f, 0x24, 0x03, 0xd5,      /* bti c.  */
+  0xf0, 0x7b, 0xbf, 0xa9,      /* stp x16, x30, [sp, #-16]!  */
+  0x10, 0x00, 0x00, 0x90,      /* adrp x16, (GOT+16)  */
+#if ARCH_SIZE == 64
+  0x11, 0x0A, 0x40, 0xf9,      /* ldr x17, [x16, #PLT_GOT+0x10]  */
+  0x10, 0x42, 0x00, 0x91,      /* add x16, x16,#PLT_GOT+0x10   */
+#else
+  0x11, 0x0A, 0x40, 0xb9,      /* ldr w17, [x16, #PLT_GOT+0x8]  */
+  0x10, 0x22, 0x00, 0x11,      /* add w16, w16,#PLT_GOT+0x8   */
+#endif
+  0x20, 0x02, 0x1f, 0xd6,      /* br x17  */
+  0x1f, 0x20, 0x03, 0xd5,      /* nop */
+  0x1f, 0x20, 0x03, 0xd5,      /* nop */
+};
+
 /* Per function entry in a procedure linkage table looks like this
    if the distance between the PLTGOT and the PLT is < 4GB use
-   these PLT entries.  */
+   these PLT entries.  Use BTI versions of the PLTs when enabled.  */
 static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] =
 {
   0x10, 0x00, 0x00, 0x90,      /* adrp x16, PLTGOT + n * 8  */
@@ -314,6 +336,54 @@ static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] =
   0x20, 0x02, 0x1f, 0xd6,      /* br x17.  */
 };
 
+static const bfd_byte
+elfNN_aarch64_small_plt_bti_entry[PLT_BTI_SMALL_ENTRY_SIZE] =
+{
+  0x5f, 0x24, 0x03, 0xd5,      /* bti c.  */
+  0x10, 0x00, 0x00, 0x90,      /* adrp x16, PLTGOT + n * 8  */
+#if ARCH_SIZE == 64
+  0x11, 0x02, 0x40, 0xf9,      /* ldr x17, [x16, PLTGOT + n * 8] */
+  0x10, 0x02, 0x00, 0x91,      /* add x16, x16, :lo12:PLTGOT + n * 8  */
+#else
+  0x11, 0x02, 0x40, 0xb9,      /* ldr w17, [x16, PLTGOT + n * 4] */
+  0x10, 0x02, 0x00, 0x11,      /* add w16, w16, :lo12:PLTGOT + n * 4  */
+#endif
+  0x20, 0x02, 0x1f, 0xd6,      /* br x17.  */
+  0x1f, 0x20, 0x03, 0xd5,      /* nop */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_pac_entry[PLT_PAC_SMALL_ENTRY_SIZE] =
+{
+  0x10, 0x00, 0x00, 0x90,      /* adrp x16, PLTGOT + n * 8  */
+#if ARCH_SIZE == 64
+  0x11, 0x02, 0x40, 0xf9,      /* ldr x17, [x16, PLTGOT + n * 8] */
+  0x10, 0x02, 0x00, 0x91,      /* add x16, x16, :lo12:PLTGOT + n * 8  */
+#else
+  0x11, 0x02, 0x40, 0xb9,      /* ldr w17, [x16, PLTGOT + n * 4] */
+  0x10, 0x02, 0x00, 0x11,      /* add w16, w16, :lo12:PLTGOT + n * 4  */
+#endif
+  0x9f, 0x21, 0x03, 0xd5,      /* autia1716 */
+  0x20, 0x02, 0x1f, 0xd6,      /* br x17.  */
+  0x1f, 0x20, 0x03, 0xd5,      /* nop */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_bti_pac_entry[PLT_BTI_PAC_SMALL_ENTRY_SIZE] =
+{
+  0x5f, 0x24, 0x03, 0xd5,      /* bti c.  */
+  0x10, 0x00, 0x00, 0x90,      /* adrp x16, PLTGOT + n * 8  */
+#if ARCH_SIZE == 64
+  0x11, 0x02, 0x40, 0xf9,      /* ldr x17, [x16, PLTGOT + n * 8] */
+  0x10, 0x02, 0x00, 0x91,      /* add x16, x16, :lo12:PLTGOT + n * 8  */
+#else
+  0x11, 0x02, 0x40, 0xb9,      /* ldr w17, [x16, PLTGOT + n * 4] */
+  0x10, 0x02, 0x00, 0x11,      /* add w16, w16, :lo12:PLTGOT + n * 4  */
+#endif
+  0x9f, 0x21, 0x03, 0xd5,      /* autia1716 */
+  0x20, 0x02, 0x1f, 0xd6,      /* br x17.  */
+};
+
 static const bfd_byte
 elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] =
 {
@@ -332,6 +402,24 @@ elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] =
   0x1f, 0x20, 0x03, 0xd5,      /* nop */
 };
 
+static const bfd_byte
+elfNN_aarch64_tlsdesc_small_plt_bti_entry[PLT_TLSDESC_ENTRY_SIZE] =
+{
+  0x5f, 0x24, 0x03, 0xd5,      /* bti c.  */
+  0xe2, 0x0f, 0xbf, 0xa9,      /* stp x2, x3, [sp, #-16]! */
+  0x02, 0x00, 0x00, 0x90,      /* adrp x2, 0 */
+  0x03, 0x00, 0x00, 0x90,      /* adrp x3, 0 */
+#if ARCH_SIZE == 64
+  0x42, 0x00, 0x40, 0xf9,      /* ldr x2, [x2, #0] */
+  0x63, 0x00, 0x00, 0x91,      /* add x3, x3, 0 */
+#else
+  0x42, 0x00, 0x40, 0xb9,      /* ldr w2, [x2, #0] */
+  0x63, 0x00, 0x00, 0x11,      /* add w3, w3, 0 */
+#endif
+  0x40, 0x00, 0x1f, 0xd6,      /* br x2 */
+  0x1f, 0x20, 0x03, 0xd5,      /* nop */
+};
+
 #define elf_info_to_howto              elfNN_aarch64_info_to_howto
 #define elf_info_to_howto_rel          elfNN_aarch64_info_to_howto
 
@@ -2436,6 +2524,16 @@ struct elf_aarch64_obj_tdata
 
   /* Zero to warn when linking objects with incompatible wchar_t sizes.  */
   int no_wchar_size_warning;
+
+  /* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties.  */
+  uint32_t gnu_and_prop;
+
+  /* Zero to warn when linking objects with incompatible
+     GNU_PROPERTY_AARCH64_FEATURE_1_BTI.  */
+  int no_bti_warn;
+
+  /* PLT type based on security.  */
+  aarch64_plt_type plt_type;
 };
 
 #define elf_aarch64_tdata(bfd)                         \
@@ -2530,10 +2628,7 @@ struct elf_aarch64_link_hash_table
   int fix_erratum_835769;
 
   /* Fix erratum 843419.  */
-  int fix_erratum_843419;
-
-  /* Enable ADRP->ADR rewrite for erratum 843419 workaround.  */
-  int fix_erratum_843419_adr;
+  erratum_84319_opts fix_erratum_843419;
 
   /* Don't apply link-time values for dynamic relocations.  */
   int no_apply_dynamic_relocs;
@@ -2541,9 +2636,15 @@ struct elf_aarch64_link_hash_table
   /* The number of bytes in the initial entry in the PLT.  */
   bfd_size_type plt_header_size;
 
-  /* The number of bytes in the subsequent PLT etries.  */
+  /* The bytes of the initial PLT entry.  */
+  const bfd_byte *plt0_entry;
+
+  /* The number of bytes in the subsequent PLT entries.  */
   bfd_size_type plt_entry_size;
 
+  /* The bytes of the subsequent PLT entry.  */
+  const bfd_byte *plt_entry;
+
   /* Small local sym cache.  */
   struct sym_cache sym_cache;
 
@@ -2586,6 +2687,9 @@ struct elf_aarch64_link_hash_table
      yet.  */
   bfd_vma tlsdesc_plt;
 
+  /* The number of bytes in the PLT enty for the TLS descriptor.  */
+  bfd_size_type tlsdesc_plt_entry_size;
+
   /* The GOT offset for the lazy trampoline.  Communicated to the
      loader via DT_TLSDESC_GOT.  The magic value (bfd_vma) -1
      indicates an offset is not allocated.  */
@@ -2829,7 +2933,10 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
     }
 
   ret->plt_header_size = PLT_ENTRY_SIZE;
+  ret->plt0_entry = elfNN_aarch64_small_plt0_entry;
   ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE;
+  ret->plt_entry = elfNN_aarch64_small_plt_entry;
+  ret->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
   ret->obfd = abfd;
   ret->dt_tlsdesc_got = (bfd_vma) - 1;
 
@@ -3119,7 +3226,10 @@ _bfd_aarch64_add_stub_entry_after (const char *stub_name,
   asection *stub_sec;
   struct elf_aarch64_stub_hash_entry *stub_entry;
 
-  stub_sec = _bfd_aarch64_get_stub_for_link_section (link_section, htab);
+  stub_sec = NULL;
+  /* Only create the actual stub if we will end up needing it.  */
+  if (htab->fix_erratum_843419 & ERRAT_ADRP)
+    stub_sec = _bfd_aarch64_get_stub_for_link_section (link_section, htab);
   stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
                                         TRUE, FALSE);
   if (stub_entry == NULL)
@@ -3264,14 +3374,15 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
    we know stub section sizes.  */
 
 static bfd_boolean
-aarch64_size_one_stub (struct bfd_hash_entry *gen_entry,
-                      void *in_arg ATTRIBUTE_UNUSED)
+aarch64_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 {
   struct elf_aarch64_stub_hash_entry *stub_entry;
+  struct elf_aarch64_link_hash_table *htab;
   int size;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+  htab = (struct elf_aarch64_link_hash_table *) in_arg;
 
   switch (stub_entry->stub_type)
     {
@@ -3285,7 +3396,11 @@ aarch64_size_one_stub (struct bfd_hash_entry *gen_entry,
       size = sizeof (aarch64_erratum_835769_stub);
       break;
     case aarch64_stub_erratum_843419_veneer:
-      size = sizeof (aarch64_erratum_843419_stub);
+      {
+       if (htab->fix_erratum_843419 == ERRAT_ADR)
+         return TRUE;
+       size = sizeof (aarch64_erratum_843419_stub);
+      }
       break;
     default:
       abort ();
@@ -3845,7 +3960,7 @@ _bfd_aarch64_erratum_835769_scan (bfd *input_bfd,
 static bfd_boolean
 _bfd_aarch64_adrp_p (uint32_t insn)
 {
-  return ((insn & 0x9f000000) == 0x90000000);
+  return ((insn & AARCH64_ADRP_OP_MASK) == AARCH64_ADRP_OP);
 }
 
 
@@ -3950,8 +4065,10 @@ _bfd_aarch64_resize_stubs (struct elf_aarch64_link_hash_table *htab)
       /* Ensure all stub sections have a size which is a multiple of
         4096.  This is important in order to ensure that the insertion
         of stub sections does not in itself move existing code around
-        in such a way that new errata sequences are created.  */
-      if (htab->fix_erratum_843419)
+        in such a way that new errata sequences are created.  We only do this
+        when the ADRP workaround is enabled.  If only the ADR workaround is
+        enabled then the stubs workaround won't ever be used.  */
+      if (htab->fix_erratum_843419 & ERRAT_ADRP)
        if (section->size)
          section->size = BFD_ALIGN (section->size, 0x1000);
     }
@@ -4174,7 +4291,7 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
       (*htab->layout_sections_again) ();
     }
 
-  if (htab->fix_erratum_843419)
+  if (htab->fix_erratum_843419 != ERRAT_NONE)
     {
       bfd *input_bfd;
 
@@ -4414,6 +4531,9 @@ elfNN_aarch64_size_stubs (bfd *output_bfd,
                    {
                      /* The proper stub has already been created.  */
                      free (stub_name);
+                     /* Always update this stub's target since it may have
+                        changed after layout.  */
+                     stub_entry->target_value = sym_value + irela->r_addend;
                      continue;
                    }
 
@@ -4594,6 +4714,47 @@ bfd_elfNN_aarch64_init_maps (bfd *abfd)
     }
 }
 
+static void
+setup_plt_values (struct bfd_link_info *link_info,
+                 aarch64_plt_type plt_type)
+{
+  struct elf_aarch64_link_hash_table *globals;
+  globals = elf_aarch64_hash_table (link_info);
+
+  if (plt_type == PLT_BTI_PAC)
+    {
+      globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry;
+
+      /* Only in ET_EXEC we need PLTn with BTI.  */
+      if (bfd_link_pde (link_info))
+       {
+         globals->plt_entry_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+         globals->plt_entry = elfNN_aarch64_small_plt_bti_pac_entry;
+       }
+      else
+       {
+         globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+         globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+       }
+    }
+  else if (plt_type == PLT_BTI)
+    {
+      globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry;
+
+      /* Only in ET_EXEC we need PLTn with BTI.  */
+      if (bfd_link_pde (link_info))
+       {
+         globals->plt_entry_size = PLT_BTI_SMALL_ENTRY_SIZE;
+         globals->plt_entry = elfNN_aarch64_small_plt_bti_entry;
+       }
+    }
+  else if (plt_type == PLT_PAC)
+    {
+      globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+      globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+    }
+}
+
 /* Set option values needed during linking.  */
 void
 bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
@@ -4601,21 +4762,38 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
                               int no_enum_warn,
                               int no_wchar_warn, int pic_veneer,
                               int fix_erratum_835769,
-                              int fix_erratum_843419,
-                              int no_apply_dynamic_relocs)
+                              erratum_84319_opts fix_erratum_843419,
+                              int no_apply_dynamic_relocs,
+                              aarch64_bti_pac_info bp_info)
 {
   struct elf_aarch64_link_hash_table *globals;
 
   globals = elf_aarch64_hash_table (link_info);
   globals->pic_veneer = pic_veneer;
   globals->fix_erratum_835769 = fix_erratum_835769;
+  /* If the default options are used, then ERRAT_ADR will be set by default
+     which will enable the ADRP->ADR workaround for the erratum 843419
+     workaround.  */
   globals->fix_erratum_843419 = fix_erratum_843419;
-  globals->fix_erratum_843419_adr = TRUE;
   globals->no_apply_dynamic_relocs = no_apply_dynamic_relocs;
 
   BFD_ASSERT (is_aarch64_elf (output_bfd));
   elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
   elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn;
+
+  switch (bp_info.bti_type)
+    {
+    case BTI_WARN:
+      elf_aarch64_tdata (output_bfd)->no_bti_warn = 0;
+      elf_aarch64_tdata (output_bfd)->gnu_and_prop
+       |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+      break;
+
+    default:
+      break;
+    }
+  elf_aarch64_tdata (output_bfd)->plt_type = bp_info.plt_type;
+  setup_plt_values (link_info, bp_info.plt_type);
 }
 
 static bfd_vma
@@ -5066,15 +5244,24 @@ _bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry,
       || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer)
     return TRUE;
 
-  insn = bfd_getl32 (contents + stub_entry->target_value);
-  bfd_putl32 (insn,
-             stub_entry->stub_sec->contents + stub_entry->stub_offset);
+  BFD_ASSERT (((htab->fix_erratum_843419 & ERRAT_ADRP) && stub_entry->stub_sec)
+             || (htab->fix_erratum_843419 & ERRAT_ADR));
+
+  /* Only update the stub section if we have one.  We should always have one if
+     we're allowed to use the ADRP errata workaround, otherwise it is not
+     required.  */
+  if (stub_entry->stub_sec)
+    {
+      insn = bfd_getl32 (contents + stub_entry->target_value);
+      bfd_putl32 (insn,
+                 stub_entry->stub_sec->contents + stub_entry->stub_offset);
+    }
 
   place = (section->output_section->vma + section->output_offset
           + stub_entry->adrp_offset);
   insn = bfd_getl32 (contents + stub_entry->adrp_offset);
 
-  if ((insn & AARCH64_ADRP_OP_MASK) !=  AARCH64_ADRP_OP)
+  if (!_bfd_aarch64_adrp_p (insn))
     abort ();
 
   bfd_signed_vma imm =
@@ -5082,14 +5269,16 @@ _bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry,
      ((bfd_vma) _bfd_aarch64_decode_adrp_imm (insn) << 12, 33)
      - (place & 0xfff));
 
-  if (htab->fix_erratum_843419_adr
+  if ((htab->fix_erratum_843419 & ERRAT_ADR)
       && (imm >= AARCH64_MIN_ADRP_IMM  && imm <= AARCH64_MAX_ADRP_IMM))
     {
       insn = (_bfd_aarch64_reencode_adr_imm (AARCH64_ADR_OP, imm)
              | AARCH64_RT (insn));
       bfd_putl32 (insn, contents + stub_entry->adrp_offset);
+      /* Stub is not needed, don't map it out.  */
+      stub_entry->stub_type = aarch64_stub_none;
     }
-  else
+  else if (htab->fix_erratum_843419 & ERRAT_ADRP)
     {
       bfd_vma veneered_insn_loc;
       bfd_vma veneer_entry_loc;
@@ -5116,6 +5305,21 @@ _bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry,
       branch_insn |= branch_offset;
       bfd_putl32 (branch_insn, contents + stub_entry->target_value);
     }
+  else
+    {
+      abfd = stub_entry->target_section->owner;
+      _bfd_error_handler
+       (_("%pB: error: erratum 843419 immediate 0x%" BFD_VMA_FMT "x "
+          "out of range for ADR (input file too large) and "
+          "--fix-cortex-a53-843419=adr used.  Run the linker with "
+          "--fix-cortex-a53-843419=full instead"), abfd, imm);
+      bfd_set_error (bfd_error_bad_value);
+      /* This function is called inside a hashtable traversal and the error
+        handlers called above turn into non-fatal errors.  Which means this
+        case ld returns an exit code 0 and also produces a broken object file.
+        To prevent this, issue a hard abort.  */
+      BFD_FAIL ();
+    }
   return TRUE;
 }
 
@@ -5224,8 +5428,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 
   weak_undef_p = (h ? h->root.type == bfd_link_hash_undefweak
                  : bfd_is_und_section (sym_sec));
-  abs_symbol_p = (h !=NULL && h->root.type == bfd_link_hash_defined
-                 && bfd_is_abs_section (h->root.u.def.section));
+  abs_symbol_p = h != NULL && bfd_is_abs_symbol (&h->root);
 
 
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
@@ -5939,6 +6142,64 @@ bad_ifunc_reloc:
 # define movz_hw_R0    (0x52c00000)
 #endif
 
+/* Structure to hold payload for _bfd_aarch64_erratum_843419_clear_stub,
+   it is used to identify the stub information to reset.  */
+
+struct erratum_843419_branch_to_stub_clear_data
+{
+  bfd_vma adrp_offset;
+  asection *output_section;
+};
+
+/* Clear the erratum information for GEN_ENTRY if the ADRP_OFFSET and
+   section inside IN_ARG matches.  The clearing is done by setting the
+   stub_type to none.  */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_clear_stub (struct bfd_hash_entry *gen_entry,
+                                       void *in_arg)
+{
+  struct elf_aarch64_stub_hash_entry *stub_entry
+    = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+  struct erratum_843419_branch_to_stub_clear_data *data
+    = (struct erratum_843419_branch_to_stub_clear_data *) in_arg;
+
+  if (stub_entry->target_section != data->output_section
+      || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer
+      || stub_entry->adrp_offset != data->adrp_offset)
+    return TRUE;
+
+  /* Change the stub type instead of removing the entry, removing from the hash
+     table would be slower and we have already reserved the memory for the entry
+     so there wouldn't be much gain.  Changing the stub also keeps around a
+     record of what was there before.  */
+  stub_entry->stub_type = aarch64_stub_none;
+
+  /* We're done and there could have been only one matching stub at that
+     particular offset, so abort further traversal.  */
+  return FALSE;
+}
+
+/* TLS Relaxations may relax an adrp sequence that matches the erratum 843419
+   sequence.  In this case the erratum no longer applies and we need to remove
+   the entry from the pending stub generation.  This clears matching adrp insn
+   at ADRP_OFFSET in INPUT_SECTION in the stub table defined in GLOBALS.  */
+
+static void
+clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *globals,
+                           bfd_vma adrp_offset, asection *input_section)
+{
+  if (globals->fix_erratum_843419 & ERRAT_ADRP)
+    {
+      struct erratum_843419_branch_to_stub_clear_data data;
+      data.adrp_offset = adrp_offset;
+      data.output_section = input_section;
+
+      bfd_hash_traverse (&globals->stub_hash_table,
+                        _bfd_aarch64_erratum_843419_clear_stub, &data);
+    }
+}
+
 /* Handle TLS relaxations.  Relaxing is possible for symbols that use
    R_AARCH64_TLSDESC_ADR_{PAGE, LD64_LO12_NC, ADD_LO12_NC} during a static
    link.
@@ -5949,8 +6210,9 @@ bad_ifunc_reloc:
 
 static bfd_reloc_status_type
 elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
-                        bfd *input_bfd, bfd_byte *contents,
-                        Elf_Internal_Rela *rel, struct elf_link_hash_entry *h)
+                        bfd *input_bfd, asection *input_section,
+                        bfd_byte *contents, Elf_Internal_Rela *rel,
+                        struct elf_link_hash_entry *h)
 {
   bfd_boolean is_local = h == NULL;
   unsigned int r_type = ELFNN_R_TYPE (rel->r_info);
@@ -5971,6 +6233,9 @@ elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
 
             Where R is x for LP64, and w for ILP32.  */
          bfd_putl32 (movz_R0, contents + rel->r_offset);
+         /* We have relaxed the adrp into a mov, we may have to clear any
+            pending erratum fixes.  */
+         clear_erratum_843419_entry (globals, rel->r_offset, input_section);
          return bfd_reloc_continue;
        }
       else
@@ -6261,6 +6526,9 @@ elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
        {
          insn = bfd_getl32 (contents + rel->r_offset);
          bfd_putl32 (movz_R0 | (insn & 0x1f), contents + rel->r_offset);
+         /* We have relaxed the adrp into a mov, we may have to clear any
+            pending erratum fixes.  */
+         clear_erratum_843419_entry (globals, rel->r_offset, input_section);
        }
       return bfd_reloc_continue;
 
@@ -6485,7 +6753,8 @@ elfNN_aarch64_relocate_section (bfd *output_bfd,
          howto = elfNN_aarch64_howto_from_bfd_reloc (bfd_r_type);
          BFD_ASSERT (howto != NULL);
          r_type = howto->type;
-         r = elfNN_aarch64_tls_relax (globals, input_bfd, contents, rel, h);
+         r = elfNN_aarch64_tls_relax (globals, input_bfd, input_section,
+                                      contents, rel, h);
          unresolved_reloc = 0;
        }
       else
@@ -7363,8 +7632,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
              if (h != NULL
                  /* This is an absolute symbol.  It represents a value instead
                     of an address.  */
-                 && ((h->root.type == bfd_link_hash_defined
-                      && bfd_is_abs_section (h->root.u.def.section))
+                 && (bfd_is_abs_symbol (&h->root)
                      /* This is an undefined symbol.  */
                      || h->root.type == bfd_link_hash_undefined))
                break;
@@ -7564,9 +7832,6 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
        case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
        case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
-       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
-       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
-       case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
          {
            unsigned got_type;
            unsigned old_got_type;
@@ -8076,6 +8341,8 @@ aarch64_map_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
        return FALSE;
       break;
+    case aarch64_stub_none:
+      break;
 
     default:
       abort ();
@@ -8281,7 +8548,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
          /* Make room for this entry. For now we only create the
             small model PLT entries. We later need to find a way
             of relaxing into these from the large model PLT entries.  */
-         s->size += PLT_SMALL_ENTRY_SIZE;
+         s->size += htab->plt_entry_size;
 
          /* We also need to make an entry in the .got.plt section, which
             will be placed in the .got section by the linker script.  */
@@ -8781,15 +9048,15 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   if (htab->tlsdesc_plt)
     {
       if (htab->root.splt->size == 0)
-       htab->root.splt->size += PLT_ENTRY_SIZE;
-
-      htab->tlsdesc_plt = htab->root.splt->size;
-      htab->root.splt->size += PLT_TLSDESC_ENTRY_SIZE;
+       htab->root.splt->size += htab->plt_header_size;
 
       /* If we're not using lazy TLS relocations, don't generate the
-        GOT entry required.  */
+        GOT and PLT entry required.  */
       if (!(info->flags & DF_BIND_NOW))
        {
+         htab->tlsdesc_plt = htab->root.splt->size;
+         htab->root.splt->size += htab->tlsdesc_plt_entry_size;
+
          htab->dt_tlsdesc_got = htab->root.sgot->size;
          htab->root.sgot->size += GOT_ENTRY_SIZE;
        }
@@ -8893,9 +9160,23 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
            return FALSE;
 
          if (htab->tlsdesc_plt
+             && !(info->flags & DF_BIND_NOW)
              && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
                  || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
            return FALSE;
+
+         if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI_PAC)
+             && (!add_dynamic_entry (DT_AARCH64_BTI_PLT, 0)
+                 || !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0)))
+           return FALSE;
+
+         else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI)
+                  && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0))
+           return FALSE;
+
+         else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_PAC)
+                  && !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))
+           return FALSE;
        }
 
       if (relocs)
@@ -8992,7 +9273,13 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
     gotplt->output_offset + got_offset;
 
   /* Copy in the boiler-plate for the PLTn entry.  */
-  memcpy (plt_entry, elfNN_aarch64_small_plt_entry, PLT_SMALL_ENTRY_SIZE);
+  memcpy (plt_entry, htab->plt_entry, htab->plt_entry_size);
+
+  /* First instruction in BTI enabled PLT stub is a BTI
+     instruction so skip it.  */
+  if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI
+      && elf_elfheader (output_bfd)->e_type == ET_EXEC)
+    plt_entry = plt_entry + 4;
 
   /* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
      ADRP:   ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
@@ -9297,10 +9584,10 @@ elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd_vma plt_base;
 
 
-  memcpy (htab->root.splt->contents, elfNN_aarch64_small_plt0_entry,
-         PLT_ENTRY_SIZE);
+  memcpy (htab->root.splt->contents, htab->plt0_entry,
+         htab->plt_header_size);
   elf_section_data (htab->root.splt->output_section)->this_hdr.sh_entsize =
-    PLT_ENTRY_SIZE;
+    htab->plt_header_size;
 
   plt_got_2nd_ent = (htab->root.sgotplt->output_section->vma
                  + htab->root.sgotplt->output_offset
@@ -9309,18 +9596,24 @@ elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED,
   plt_base = htab->root.splt->output_section->vma +
     htab->root.splt->output_offset;
 
+  /* First instruction in BTI enabled PLT stub is a BTI
+     instruction so skip it.  */
+  bfd_byte *plt0_entry = htab->root.splt->contents;
+  if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI)
+    plt0_entry = plt0_entry + 4;
+
   /* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
      ADRP:   ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
   elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADR_HI21_PCREL,
-                               htab->root.splt->contents + 4,
+                               plt0_entry + 4,
                                PG (plt_got_2nd_ent) - PG (plt_base + 4));
 
   elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_LDSTNN_LO12,
-                               htab->root.splt->contents + 8,
+                               plt0_entry + 8,
                                PG_OFFSET (plt_got_2nd_ent));
 
   elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADD_LO12,
-                               htab->root.splt->contents + 12,
+                               plt0_entry + 12,
                                PG_OFFSET (plt_got_2nd_ent));
 }
 
@@ -9380,6 +9673,7 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
 
            case DT_TLSDESC_GOT:
              s = htab->root.sgot;
+             BFD_ASSERT (htab->dt_tlsdesc_got != (bfd_vma)-1);
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
                + htab->dt_tlsdesc_got;
              break;
@@ -9399,14 +9693,23 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
        this_hdr.sh_entsize = htab->plt_entry_size;
 
 
-      if (htab->tlsdesc_plt)
+      if (htab->tlsdesc_plt && !(info->flags & DF_BIND_NOW))
        {
+         BFD_ASSERT (htab->dt_tlsdesc_got != (bfd_vma)-1);
          bfd_put_NN (output_bfd, (bfd_vma) 0,
                      htab->root.sgot->contents + htab->dt_tlsdesc_got);
 
+         const bfd_byte *entry = elfNN_aarch64_tlsdesc_small_plt_entry;
+         htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
+
+         aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type;
+         if (type == PLT_BTI || type == PLT_BTI_PAC)
+           {
+             entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry;
+           }
+
          memcpy (htab->root.splt->contents + htab->tlsdesc_plt,
-                 elfNN_aarch64_tlsdesc_small_plt_entry,
-                 sizeof (elfNN_aarch64_tlsdesc_small_plt_entry));
+                 entry, htab->tlsdesc_plt_entry_size);
 
          {
            bfd_vma adrp1_addr =
@@ -9428,6 +9731,15 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
            bfd_byte *plt_entry =
              htab->root.splt->contents + htab->tlsdesc_plt;
 
+          /* First instruction in BTI enabled PLT stub is a BTI
+             instruction so skip it.  */
+           if (type & PLT_BTI)
+             {
+               plt_entry = plt_entry + 4;
+               adrp1_addr = adrp1_addr + 4;
+               adrp2_addr = adrp2_addr + 4;
+             }
+
            /* adrp x2, DT_TLSDESC_GOT */
            elf_aarch64_update_plt_entry (output_bfd,
                                          BFD_RELOC_AARCH64_ADR_HI21_PCREL,
@@ -9506,6 +9818,57 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
   return TRUE;
 }
 
+/* Check if BTI enabled PLTs are needed.  Returns the type needed.  */
+static aarch64_plt_type
+get_plt_type (bfd *abfd)
+{
+  aarch64_plt_type ret = PLT_NORMAL;
+  bfd_byte *contents, *extdyn, *extdynend;
+  asection *sec = bfd_get_section_by_name (abfd, ".dynamic");
+  if (!sec || !bfd_malloc_and_get_section (abfd, sec, &contents))
+    return ret;
+  extdyn = contents;
+  extdynend = contents + sec->size;
+  for (; extdyn < extdynend; extdyn += sizeof (ElfNN_External_Dyn))
+    {
+      Elf_Internal_Dyn dyn;
+      bfd_elfNN_swap_dyn_in (abfd, extdyn, &dyn);
+
+      /* Let's check the processor specific dynamic array tags.  */
+      bfd_vma tag = dyn.d_tag;
+      if (tag < DT_LOPROC || tag > DT_HIPROC)
+       continue;
+
+      switch (tag)
+       {
+       case DT_AARCH64_BTI_PLT:
+         ret |= PLT_BTI;
+         break;
+
+       case DT_AARCH64_PAC_PLT:
+         ret |= PLT_PAC;
+         break;
+
+       default: break;
+       }
+    }
+  free (contents);
+  return ret;
+}
+
+static long
+elfNN_aarch64_get_synthetic_symtab (bfd *abfd,
+                                   long symcount,
+                                   asymbol **syms,
+                                   long dynsymcount,
+                                   asymbol **dynsyms,
+                                   asymbol **ret)
+{
+  elf_aarch64_tdata (abfd)->plt_type = get_plt_type (abfd);
+  return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
+                                       dynsymcount, dynsyms, ret);
+}
+
 /* Return address for Ith PLT stub in section PLT, for relocation REL
    or (bfd_vma) -1 if it should not be included.  */
 
@@ -9513,7 +9876,27 @@ static bfd_vma
 elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt,
                           const arelent *rel ATTRIBUTE_UNUSED)
 {
-  return plt->vma + PLT_ENTRY_SIZE + i * PLT_SMALL_ENTRY_SIZE;
+  size_t plt0_size = PLT_ENTRY_SIZE;
+  size_t pltn_size = PLT_SMALL_ENTRY_SIZE;
+
+  if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI_PAC)
+    {
+      if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+       pltn_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+      else
+       pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+    }
+  else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI)
+    {
+      if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+       pltn_size = PLT_BTI_SMALL_ENTRY_SIZE;
+    }
+  else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_PAC)
+    {
+      pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+    }
+
+  return plt->vma + plt0_size + i * pltn_size;
 }
 
 /* Returns TRUE if NAME is an AArch64 mapping symbol.
@@ -9550,6 +9933,61 @@ elfNN_aarch64_backend_symbol_processing (bfd *abfd, asymbol *sym)
     sym->flags |= BSF_KEEP;
 }
 
+/* Implement elf_backend_setup_gnu_properties for AArch64.  It serves as a
+   wrapper function for _bfd_aarch64_elf_link_setup_gnu_properties to account
+   for the effect of GNU properties of the output_bfd.  */
+static bfd *
+elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info)
+{
+  uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+  bfd *pbfd = _bfd_aarch64_elf_link_setup_gnu_properties (info, &prop);
+  elf_aarch64_tdata (info->output_bfd)->gnu_and_prop = prop;
+  elf_aarch64_tdata (info->output_bfd)->plt_type
+    |= (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ? PLT_BTI : 0;
+  setup_plt_values (info, elf_aarch64_tdata (info->output_bfd)->plt_type);
+  return pbfd;
+}
+
+/* Implement elf_backend_merge_gnu_properties for AArch64.  It serves as a
+   wrapper function for _bfd_aarch64_elf_merge_gnu_properties to account
+   for the effect of GNU properties of the output_bfd.  */
+static bfd_boolean
+elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info,
+                                      bfd *abfd, bfd *bbfd,
+                                      elf_property *aprop,
+                                      elf_property *bprop)
+{
+  uint32_t prop
+    = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+
+  /* If output has been marked with BTI using command line argument, give out
+     warning if necessary.  */
+  /* Properties are merged per type, hence only check for warnings when merging
+     GNU_PROPERTY_AARCH64_FEATURE_1_AND.  */
+  if (((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+       || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND))
+      && (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
+      && (!elf_aarch64_tdata (info->output_bfd)->no_bti_warn))
+    {
+      if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+          || !aprop)
+       {
+         _bfd_error_handler (_("%pB: warning: BTI turned on by --force-bti when "
+                               "all inputs do not have BTI in NOTE section."),
+                             abfd);
+       }
+      if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+          || !bprop)
+       {
+         _bfd_error_handler (_("%pB: warning: BTI turned on by --force-bti when "
+                               "all inputs do not have BTI in NOTE section."),
+                             bbfd);
+       }
+    }
+
+  return  _bfd_aarch64_elf_merge_gnu_properties (info, abfd, aprop,
+                                                bprop, prop);
+}
 
 /* We use this so we can override certain functions
    (though currently we don't).  */
@@ -9624,6 +10062,9 @@ const struct elf_size_info elfNN_aarch64_size_info =
 #define bfd_elfNN_find_nearest_line            \
   elfNN_aarch64_find_nearest_line
 
+#define bfd_elfNN_get_synthetic_symtab         \
+  elfNN_aarch64_get_synthetic_symtab
+
 #define bfd_elfNN_mkobject                     \
   elfNN_aarch64_mkobject
 
@@ -9689,6 +10130,12 @@ const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_symbol_processing          \
   elfNN_aarch64_backend_symbol_processing
 
+#define elf_backend_setup_gnu_properties       \
+  elfNN_aarch64_link_setup_gnu_properties
+
+#define elf_backend_merge_gnu_properties       \
+  elfNN_aarch64_merge_gnu_properties
+
 #define elf_backend_can_refcount       1
 #define elf_backend_can_gc_sections    1
 #define elf_backend_plt_readonly       1
This page took 0.034528 seconds and 4 git commands to generate.