AArch64: Add gdbserver MTE support
[deliverable/binutils-gdb.git] / bfd / elfnn-riscv.c
index 8b9819becdde024b94e11384b217aff4cd289cc7..364d67b6749bf7d929668a740ae73f174f82426e 100644 (file)
@@ -32,6 +32,7 @@
 #include "elf/riscv.h"
 #include "opcode/riscv.h"
 #include "objalloc.h"
+#include "cpu-riscv.h"
 
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
@@ -69,16 +70,16 @@ struct riscv_elf_link_hash_entry
 {
   struct elf_link_hash_entry elf;
 
-#define GOT_UNKNOWN     0
-#define GOT_NORMAL      1
-#define GOT_TLS_GD      2
-#define GOT_TLS_IE      4
-#define GOT_TLS_LE      8
+#define GOT_UNKNOWN    0
+#define GOT_NORMAL     1
+#define GOT_TLS_GD     2
+#define GOT_TLS_IE     4
+#define GOT_TLS_LE     8
   char tls_type;
 };
 
 #define riscv_elf_hash_entry(ent) \
-  ((struct riscv_elf_link_hash_entry *)(ent))
+  ((struct riscv_elf_link_hash_entry *) (ent))
 
 struct _bfd_riscv_elf_obj_tdata
 {
@@ -130,6 +131,9 @@ struct riscv_elf_link_hash_table
 
   /* The index of the last unused .rel.iplt slot.  */
   bfd_vma last_iplt_index;
+
+  /* Re-run the relaxations from relax pass 0 if TRUE.  */
+  bfd_boolean restart_relax;
 };
 
 /* Instruction access functions. */
@@ -398,6 +402,7 @@ riscv_elf_link_hash_table_create (bfd *abfd)
     }
 
   ret->max_alignment = (bfd_vma) -1;
+  ret->restart_relax = FALSE;
 
   /* Create hash table for local ifunc.  */
   ret->loc_hash_table = htab_try_create (1024,
@@ -1645,27 +1650,27 @@ perform_relocation (const reloc_howto_type *howto,
       break;
 
     case R_RISCV_JAL:
-      if (!VALID_UJTYPE_IMM (value))
+      if (!VALID_JTYPE_IMM (value))
        return bfd_reloc_overflow;
-      value = ENCODE_UJTYPE_IMM (value);
+      value = ENCODE_JTYPE_IMM (value);
       break;
 
     case R_RISCV_BRANCH:
-      if (!VALID_SBTYPE_IMM (value))
+      if (!VALID_BTYPE_IMM (value))
        return bfd_reloc_overflow;
-      value = ENCODE_SBTYPE_IMM (value);
+      value = ENCODE_BTYPE_IMM (value);
       break;
 
     case R_RISCV_RVC_BRANCH:
-      if (!VALID_RVC_B_IMM (value))
+      if (!VALID_CBTYPE_IMM (value))
        return bfd_reloc_overflow;
-      value = ENCODE_RVC_B_IMM (value);
+      value = ENCODE_CBTYPE_IMM (value);
       break;
 
     case R_RISCV_RVC_JUMP:
-      if (!VALID_RVC_J_IMM (value))
+      if (!VALID_CJTYPE_IMM (value))
        return bfd_reloc_overflow;
-      value = ENCODE_RVC_J_IMM (value);
+      value = ENCODE_CJTYPE_IMM (value);
       break;
 
     case R_RISCV_RVC_LUI:
@@ -1678,12 +1683,12 @@ perform_relocation (const reloc_howto_type *howto,
                                         contents + rel->r_offset);
          insn = (insn & ~MATCH_C_LUI) | MATCH_C_LI;
          riscv_put_insn (howto->bitsize, insn, contents + rel->r_offset);
-         value = ENCODE_RVC_IMM (0);
+         value = ENCODE_CITYPE_IMM (0);
        }
-      else if (!VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value)))
+      else if (!VALID_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value)))
        return bfd_reloc_overflow;
       else
-       value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
+       value = ENCODE_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
     case R_RISCV_32:
@@ -1738,14 +1743,14 @@ typedef struct
 
 typedef struct riscv_pcrel_lo_reloc
 {
-  asection *                    input_section;
-  struct bfd_link_info *        info;
-  reloc_howto_type *            howto;
-  const Elf_Internal_Rela *     reloc;
-  bfd_vma                       addr;
-  const char *                  name;
-  bfd_byte *                    contents;
-  struct riscv_pcrel_lo_reloc *         next;
+  asection *input_section;
+  struct bfd_link_info *info;
+  reloc_howto_type *howto;
+  const Elf_Internal_Rela *reloc;
+  bfd_vma addr;
+  const char *name;
+  bfd_byte *contents;
+  struct riscv_pcrel_lo_reloc *next;
 } riscv_pcrel_lo_reloc;
 
 typedef struct
@@ -1771,7 +1776,6 @@ riscv_pcrel_reloc_eq (const void *entry1, const void *entry2)
 static bfd_boolean
 riscv_init_pcrel_relocs (riscv_pcrel_relocs *p)
 {
-
   p->lo_relocs = NULL;
   p->hi_relocs = htab_create (1024, riscv_pcrel_reloc_hash,
                              riscv_pcrel_reloc_eq, free);
@@ -1824,11 +1828,11 @@ riscv_zero_pcrel_hi_reloc (Elf_Internal_Rela *rel,
   if (ARCH_SIZE > 32 && !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (addr)))
     return FALSE;
 
-  rel->r_info = ELFNN_R_INFO(addr, R_RISCV_HI20);
+  rel->r_info = ELFNN_R_INFO (addr, R_RISCV_HI20);
 
-  bfd_vma insn = riscv_get_insn(howto->bitsize, contents + rel->r_offset);
+  bfd_vma insn = riscv_get_insn (howto->bitsize, contents + rel->r_offset);
   insn = (insn & ~MASK_AUIPC) | MATCH_LUI;
-  riscv_put_insn(howto->bitsize, insn, contents + rel->r_offset);
+  riscv_put_insn (howto->bitsize, insn, contents + rel->r_offset);
   return TRUE;
 }
 
@@ -1882,7 +1886,7 @@ riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p)
       riscv_pcrel_hi_reloc *entry = htab_find (p->hi_relocs, &search);
       if (entry == NULL
          /* Check for overflow into bit 11 when adding reloc addend.  */
-         || (! (entry->value & 0x800)
+         || (!(entry->value & 0x800)
              && ((entry->value + r->reloc->r_addend) & 0x800)))
        {
          char *string = (entry == NULL
@@ -2236,7 +2240,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
                goto do_relocation;
 
            default:
- bad_ifunc_reloc:
          bad_ifunc_reloc:
              if (h->root.root.string)
                name = h->root.root.string;
              else
@@ -2254,7 +2258,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
            }
        }
 
- skip_ifunc:
   skip_ifunc:
       if (h != NULL)
        name = h->root.root.string;
       else
@@ -2538,7 +2542,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
                   || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                       && !resolved_to_zero)
                   || h->root.type != bfd_link_hash_undefweak)
-              && (! howto->pc_relative
+              && (!howto->pc_relative
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (!bfd_link_pic (info)
                  && h != NULL
@@ -2656,14 +2660,14 @@ riscv_elf_relocate_section (bfd *output_bfd,
                          BFD_ASSERT (! unresolved_reloc);
                          bfd_put_NN (output_bfd,
                                      dtpoff (info, relocation),
-                                     (htab->elf.sgot->contents + off +
-                                      RISCV_ELF_WORD_BYTES));
+                                     (htab->elf.sgot->contents
+                                      + off + RISCV_ELF_WORD_BYTES));
                        }
                      else
                        {
                          bfd_put_NN (output_bfd, 0,
-                                     (htab->elf.sgot->contents + off +
-                                      RISCV_ELF_WORD_BYTES));
+                                     (htab->elf.sgot->contents
+                                      + off + RISCV_ELF_WORD_BYTES));
                          outrel.r_info = ELFNN_R_INFO (indx, R_RISCV_TLS_DTPRELNN);
                          outrel.r_offset += RISCV_ELF_WORD_BYTES;
                          riscv_elf_append_rela (output_bfd, htab->elf.srelgot, &outrel);
@@ -2680,8 +2684,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
                                  htab->elf.sgot->contents + off);
                      bfd_put_NN (output_bfd,
                                  dtpoff (info, relocation),
-                                 (htab->elf.sgot->contents + off +
-                                  RISCV_ELF_WORD_BYTES));
+                                 (htab->elf.sgot->contents
+                                  + off + RISCV_ELF_WORD_BYTES));
                   }
                }
 
@@ -2692,7 +2696,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
                      bfd_put_NN (output_bfd, 0,
                                  htab->elf.sgot->contents + off + ie_off);
                      outrel.r_offset = sec_addr (htab->elf.sgot)
-                                      + off + ie_off;
+                                       + off + ie_off;
                      outrel.r_addend = 0;
                      if (indx == 0)
                        outrel.r_addend = tpoff (info, relocation);
@@ -2999,7 +3003,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
              else
                {
                  /* Generate R_RISCV_NN.  */
-                 BFD_ASSERT((h->got.offset & 1) == 0);
+                 BFD_ASSERT ((h->got.offset & 1) == 0);
                  BFD_ASSERT (h->dynindx != -1);
                  rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
                  rela.r_addend = 0;
@@ -3008,7 +3012,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
          else if (bfd_link_pic (info))
            {
              /* Generate R_RISCV_NN.  */
-             BFD_ASSERT((h->got.offset & 1) == 0);
+             BFD_ASSERT ((h->got.offset & 1) == 0);
              BFD_ASSERT (h->dynindx != -1);
              rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
              rela.r_addend = 0;
@@ -3040,7 +3044,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
             or a pie link, or the symbol was forced to be local because
             of a version file.  The entry in the global offset table will
             already have been initialized in the relocate_section function.  */
-         BFD_ASSERT((h->got.offset & 1) != 0);
+         BFD_ASSERT ((h->got.offset & 1) != 0);
          asection *sec = h->root.u.def.section;
          rela.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE);
          rela.r_addend = (h->root.u.def.value
@@ -3049,7 +3053,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
        }
       else
        {
-         BFD_ASSERT((h->got.offset & 1) == 0);
+         BFD_ASSERT ((h->got.offset & 1) == 0);
          BFD_ASSERT (h->dynindx != -1);
          rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
          rela.r_addend = 0;
@@ -3499,18 +3503,18 @@ riscv_merge_multi_letter_ext (bfd *ibfd,
        }
     }
 
-  if (in || out) {
-    /* If we're here, either `in' or `out' is running longer than
-       the other. So, we need to append the corresponding tail.  */
-    tail = in ? in : out;
-
-    while (tail)
-      {
-       riscv_add_subset (&merged_subsets, tail->name, tail->major_version,
-                         tail->minor_version);
-       tail = tail->next;
-      }
-  }
+  if (in || out)
+    {
+      /* If we're here, either `in' or `out' is running longer than
+        the other. So, we need to append the corresponding tail.  */
+      tail = in ? in : out;
+      while (tail)
+       {
+         riscv_add_subset (&merged_subsets, tail->name, tail->major_version,
+                           tail->minor_version);
+         tail = tail->next;
+       }
+    }
 
   return TRUE;
 }
@@ -3680,8 +3684,8 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info)
            unsigned int Tag_a = Tag_RISCV_priv_spec;
            unsigned int Tag_b = Tag_RISCV_priv_spec_minor;
            unsigned int Tag_c = Tag_RISCV_priv_spec_revision;
-           enum riscv_priv_spec_class in_priv_spec;
-           enum riscv_priv_spec_class out_priv_spec;
+           enum riscv_spec_class in_priv_spec = PRIV_SPEC_CLASS_NONE;
+           enum riscv_spec_class out_priv_spec = PRIV_SPEC_CLASS_NONE;
 
            /* Get the privileged spec class from elf attributes.  */
            riscv_get_priv_spec_class_from_numbers (in_attr[Tag_a].i,
@@ -3802,16 +3806,6 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
   if (!riscv_merge_attributes (ibfd, info))
     return FALSE;
 
-  new_flags = elf_elfheader (ibfd)->e_flags;
-  old_flags = elf_elfheader (obfd)->e_flags;
-
-  if (! elf_flags_init (obfd))
-    {
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = new_flags;
-      return TRUE;
-    }
-
   /* Check to see if the input BFD actually contains any sections.  If not,
      its flags may not have been initialized either, but it cannot actually
      cause any incompatibility.  Do not short-circuit dynamic objects; their
@@ -3827,19 +3821,31 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 
       for (sec = ibfd->sections; sec != NULL; sec = sec->next)
        {
+         null_input_bfd = FALSE;
+
          if ((bfd_section_flags (sec)
               & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
              == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
-           only_data_sections = FALSE;
-
-         null_input_bfd = FALSE;
-         break;
+           {
+             only_data_sections = FALSE;
+             break;
+           }
        }
 
       if (null_input_bfd || only_data_sections)
        return TRUE;
     }
 
+  new_flags = elf_elfheader (ibfd)->e_flags;
+  old_flags = elf_elfheader (obfd)->e_flags;
+
+  if (!elf_flags_init (obfd))
+    {
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = new_flags;
+      return TRUE;
+    }
+
   /* Disallow linking different float ABIs.  */
   if ((old_flags ^ new_flags) & EF_RISCV_FLOAT_ABI)
     {
@@ -3935,7 +3941,7 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count,
         different symbols in 'sym_hashes', we don't want to adjust
         the global symbol __wrap_SYMBOL twice.
 
-         The same problem occurs with symbols that are versioned_hidden, as
+        The same problem occurs with symbols that are versioned_hidden, as
         foo becomes an alias for foo@BAR, and hence they need the same
         treatment.  */
       if (link_info->wrap_hash != NULL
@@ -4025,14 +4031,14 @@ riscv_free_pcgp_relocs (riscv_pcgp_relocs *p,
   riscv_pcgp_hi_reloc *c;
   riscv_pcgp_lo_reloc *l;
 
-  for (c = p->hi; c != NULL;)
+  for (c = p->hi; c != NULL; )
     {
       riscv_pcgp_hi_reloc *next = c->next;
       free (c);
       c = next;
     }
 
-  for (l = p->lo; l != NULL;)
+  for (l = p->lo; l != NULL; )
     {
       riscv_pcgp_lo_reloc *next = l->next;
       free (l);
@@ -4050,7 +4056,7 @@ riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off,
                            unsigned hi_sym, asection *sym_sec,
                            bfd_boolean undefined_weak)
 {
-  riscv_pcgp_hi_reloc *new = bfd_malloc (sizeof(*new));
+  riscv_pcgp_hi_reloc *new = bfd_malloc (sizeof (*new));
   if (!new)
     return FALSE;
   new->hi_sec_off = hi_sec_off;
@@ -4068,7 +4074,7 @@ riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off,
    This is used by a lo part reloc to find the corresponding hi part reloc.  */
 
 static riscv_pcgp_hi_reloc *
-riscv_find_pcgp_hi_reloc(riscv_pcgp_relocs *p, bfd_vma hi_sec_off)
+riscv_find_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off)
 {
   riscv_pcgp_hi_reloc *c;
 
@@ -4084,7 +4090,7 @@ riscv_find_pcgp_hi_reloc(riscv_pcgp_relocs *p, bfd_vma hi_sec_off)
 static bfd_boolean
 riscv_record_pcgp_lo_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off)
 {
-  riscv_pcgp_lo_reloc *new = bfd_malloc (sizeof(*new));
+  riscv_pcgp_lo_reloc *new = bfd_malloc (sizeof (*new));
   if (!new)
     return FALSE;
   new->hi_sec_off = hi_sec_off;
@@ -4129,7 +4135,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
 {
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   bfd_vma foff = symval - (sec_addr (sec) + rel->r_offset);
-  bfd_boolean near_zero = (symval + RISCV_IMM_REACH/2) < RISCV_IMM_REACH;
+  bfd_boolean near_zero = (symval + RISCV_IMM_REACH / 2) < RISCV_IMM_REACH;
   bfd_vma auipc, jalr;
   int rd, r_type, len = 4, rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC;
 
@@ -4137,7 +4143,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
      cause the PC-relative offset to later increase, so we need to add in the
      max alignment of any section inclusive from the call to the target.
      Otherwise, we only need to use the alignment of the current section.  */
-  if (VALID_UJTYPE_IMM (foff))
+  if (VALID_JTYPE_IMM (foff))
     {
       if (sym_sec->output_section == sec->output_section
          && sym_sec->output_section != bfd_abs_section_ptr)
@@ -4146,7 +4152,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
     }
 
   /* See if this function call can be shortened.  */
-  if (!VALID_UJTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && near_zero))
+  if (!VALID_JTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && near_zero))
     return TRUE;
 
   /* Shorten the function call.  */
@@ -4155,7 +4161,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
   auipc = bfd_getl32 (contents + rel->r_offset);
   jalr = bfd_getl32 (contents + rel->r_offset + 4);
   rd = (jalr >> OP_SH_RD) & OP_MASK_RD;
-  rvc = rvc && VALID_RVC_J_IMM (foff);
+  rvc = rvc && VALID_CJTYPE_IMM (foff);
 
   /* C.J exists on RV32 and RV64, but C.JAL is RV32-only.  */
   rvc = rvc && (rd == 0 || (rd == X_RA && ARCH_SIZE == 32));
@@ -4167,7 +4173,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
       auipc = rd == 0 ? MATCH_C_J : MATCH_C_JAL;
       len = 2;
     }
-  else if (VALID_UJTYPE_IMM (foff))
+  else if (VALID_JTYPE_IMM (foff))
     {
       /* Relax to JAL rd, addr.  */
       r_type = R_RISCV_JAL;
@@ -4296,8 +4302,8 @@ _bfd_riscv_relax_lui (bfd *abfd,
 
   if (use_rvc
       && ELFNN_R_TYPE (rel->r_info) == R_RISCV_HI20
-      && VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval))
-      && VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval)
+      && VALID_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (symval))
+      && VALID_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (symval)
                            + (link_info->relro ? 2 * ELF_MAXPAGESIZE
                               : ELF_MAXPAGESIZE)))
     {
@@ -4363,7 +4369,8 @@ _bfd_riscv_relax_tls_le (bfd *abfd,
     }
 }
 
-/* Implement R_RISCV_ALIGN by deleting excess alignment NOPs.  */
+/* Implement R_RISCV_ALIGN by deleting excess alignment NOPs.
+   Once we've handled an R_RISCV_ALIGN, we can't relax anything else.  */
 
 static bfd_boolean
 _bfd_riscv_relax_align (bfd *abfd, asection *sec,
@@ -4386,9 +4393,6 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
   bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
   bfd_vma nop_bytes = aligned_addr - symval;
 
-  /* Once we've handled an R_RISCV_ALIGN, we can't relax anything else.  */
-  sec->sec_flg0 = TRUE;
-
   /* Make sure there are enough NOPs to actually achieve the alignment.  */
   if (rel->r_addend < nop_bytes)
     {
@@ -4424,17 +4428,17 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
 /* Relax PC-relative references to GP-relative references.  */
 
 static bfd_boolean
-_bfd_riscv_relax_pc  (bfd *abfd ATTRIBUTE_UNUSED,
-                     asection *sec,
-                     asection *sym_sec,
-                     struct bfd_link_info *link_info,
-                     Elf_Internal_Rela *rel,
-                     bfd_vma symval,
-                     bfd_vma max_alignment,
-                     bfd_vma reserve_size,
-                     bfd_boolean *again ATTRIBUTE_UNUSED,
-                     riscv_pcgp_relocs *pcgp_relocs,
-                     bfd_boolean undefined_weak)
+_bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
+                    asection *sec,
+                    asection *sym_sec,
+                    struct bfd_link_info *link_info,
+                    Elf_Internal_Rela *rel,
+                    bfd_vma symval,
+                    bfd_vma max_alignment,
+                    bfd_vma reserve_size,
+                    bfd_boolean *again ATTRIBUTE_UNUSED,
+                    riscv_pcgp_relocs *pcgp_relocs,
+                    bfd_boolean undefined_weak)
 {
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   bfd_vma gp = riscv_global_pointer_value (link_info);
@@ -4584,23 +4588,47 @@ _bfd_riscv_relax_delete (bfd *abfd,
                         bfd_vma symval ATTRIBUTE_UNUSED,
                         bfd_vma max_alignment ATTRIBUTE_UNUSED,
                         bfd_vma reserve_size ATTRIBUTE_UNUSED,
-                        bfd_boolean *again ATTRIBUTE_UNUSED,
+                        bfd_boolean *again,
                         riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
                         bfd_boolean undefined_weak ATTRIBUTE_UNUSED)
 {
-  if (!riscv_relax_delete_bytes(abfd, sec, rel->r_offset, rel->r_addend,
-                               link_info))
+  if (!riscv_relax_delete_bytes (abfd, sec, rel->r_offset, rel->r_addend,
+                                link_info))
     return FALSE;
-  rel->r_info = ELFNN_R_INFO(0, R_RISCV_NONE);
+  rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
+  *again = TRUE;
   return TRUE;
 }
 
+/* Called by after_allocation to check if we need to run the whole
+   relaxations again.  */
+
+bfd_boolean
+bfd_elfNN_riscv_restart_relax_sections (struct bfd_link_info *info)
+{
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+  bfd_boolean restart = htab->restart_relax;
+  /* Reset the flag.  */
+  htab->restart_relax = FALSE;
+  return restart;
+}
+
 /* Relax a section.
 
    Pass 0: Shortens code sequences for LUI/CALL/TPREL relocs.
    Pass 1: Shortens code sequences for PCREL relocs.
-   Pass 2: Deletes the bytes that pass 1 made obselete.
-   Pass 3: Which cannot be disabled, handles code alignment directives.  */
+   Pass 2: Deletes the bytes that pass 1 made obsolete.
+   Pass 3: Which cannot be disabled, handles code alignment directives.
+
+   The `again` is used to determine whether the relax pass itself needs to
+   run again.  And the `restart_relax` is used to determine if we need to
+   run the whole relax passes again from 0 to 2.  Once we have deleted the
+   code between relax pass 0 to 2, the restart_relax will be set to TRUE,
+   and we should run the whole relaxations again to give them more chances
+   to shorten the code.
+
+   Since we can't relax anything else once we start to handle the alignments,
+   we will only enter into the relax pass 3 when the restart_relax is FALSE.  */
 
 static bfd_boolean
 _bfd_riscv_relax_section (bfd *abfd, asection *sec,
@@ -4619,11 +4647,12 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
   *again = FALSE;
 
   if (bfd_link_relocatable (info)
-      || sec->sec_flg0
       || (sec->flags & SEC_RELOC) == 0
       || sec->reloc_count == 0
       || (info->disable_target_specific_optimizations
-         && info->relax_pass < 2))
+         && info->relax_pass < 2)
+      || (htab->restart_relax
+         && info->relax_pass == 3))
     return TRUE;
 
   riscv_init_pcgp_relocs (&pcgp_relocs);
@@ -4677,7 +4706,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
            continue;
        }
       else if (info->relax_pass == 1
-              && !bfd_link_pic(info)
+              && !bfd_link_pic (info)
               && (type == R_RISCV_PCREL_HI20
                   || type == R_RISCV_PCREL_LO12_I
                   || type == R_RISCV_PCREL_LO12_S))
@@ -4860,7 +4889,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
  fail:
   if (relocs != data->relocs)
     free (relocs);
-  riscv_free_pcgp_relocs(&pcgp_relocs, abfd, sec);
+  riscv_free_pcgp_relocs (&pcgp_relocs, abfd, sec);
+
+  if (*again)
+    htab->restart_relax = TRUE;
 
   return ret;
 }
@@ -4875,6 +4907,8 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 # define PRPSINFO_OFFSET_PR_PID                16
 # define PRPSINFO_OFFSET_PR_FNAME      32
 # define PRPSINFO_OFFSET_PR_PSARGS     48
+# define PRPSINFO_PR_FNAME_LENGTH      16
+# define PRPSINFO_PR_PSARGS_LENGTH     80
 #else
 # define PRSTATUS_SIZE                 376
 # define PRSTATUS_OFFSET_PR_CURSIG     12
@@ -4885,7 +4919,82 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 # define PRPSINFO_OFFSET_PR_PID                24
 # define PRPSINFO_OFFSET_PR_FNAME      40
 # define PRPSINFO_OFFSET_PR_PSARGS     56
+# define PRPSINFO_PR_FNAME_LENGTH      16
+# define PRPSINFO_PR_PSARGS_LENGTH     80
+#endif
+
+/* Write PRSTATUS and PRPSINFO note into core file.  This will be called
+   before the generic code in elf.c.  By checking the compiler defines we
+   only perform any action here if the generic code would otherwise not be
+   able to help us.  The intention is that bare metal core dumps (where the
+   prstatus_t and/or prpsinfo_t might not be available) will use this code,
+   while non bare metal tools will use the generic elf code.  */
+
+static char *
+riscv_write_core_note (bfd *abfd ATTRIBUTE_UNUSED,
+                       char *buf ATTRIBUTE_UNUSED,
+                       int *bufsiz ATTRIBUTE_UNUSED,
+                       int note_type ATTRIBUTE_UNUSED, ...)
+{
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+#if !defined (HAVE_PRPSINFO_T)
+    case NT_PRPSINFO:
+      {
+       char data[PRPSINFO_SIZE] ATTRIBUTE_NONSTRING;
+       va_list ap;
+
+       va_start (ap, note_type);
+       memset (data, 0, sizeof (data));
+       strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char *),
+                 PRPSINFO_PR_FNAME_LENGTH);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_PUSH;
+       /* GCC 8.0 and 8.1 warn about 80 equals destination size with
+          -Wstringop-truncation:
+          https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+        */
+       DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
+       strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char *),
+                 PRPSINFO_PR_PSARGS_LENGTH);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_POP;
 #endif
+       va_end (ap);
+       return elfcore_write_note (abfd, buf, bufsiz,
+                                  "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRPSINFO_T */
+
+#if !defined (HAVE_PRSTATUS_T)
+    case NT_PRSTATUS:
+      {
+        char data[PRSTATUS_SIZE];
+        va_list ap;
+        long pid;
+        int cursig;
+        const void *greg;
+
+        va_start (ap, note_type);
+        memset (data, 0, sizeof(data));
+        pid = va_arg (ap, long);
+        bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID);
+        cursig = va_arg (ap, int);
+        bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG);
+        greg = va_arg (ap, const void *);
+        memcpy (data + PRSTATUS_OFFSET_PR_REG, greg,
+                PRSTATUS_SIZE - PRSTATUS_OFFSET_PR_REG - ARCH_SIZE / 8);
+        va_end (ap);
+        return elfcore_write_note (abfd, buf, bufsiz,
+                                   "CORE", note_type, data, sizeof (data));
+      }
+#endif /* !HAVE_PRSTATUS_T */
+    }
+}
 
 /* Support for core dump NOTE sections.  */
 
@@ -4928,11 +5037,13 @@ riscv_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 
        /* pr_fname */
        elf_tdata (abfd)->core->program = _bfd_elfcore_strndup
-         (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME, 16);
+         (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME,
+           PRPSINFO_PR_FNAME_LENGTH);
 
        /* pr_psargs */
        elf_tdata (abfd)->core->command = _bfd_elfcore_strndup
-         (abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS, 80);
+         (abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS,
+           PRPSINFO_PR_PSARGS_LENGTH);
        break;
     }
 
@@ -4975,57 +5086,58 @@ riscv_elf_obj_attrs_arg_type (int tag)
   return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL;
 }
 
-#define TARGET_LITTLE_SYM              riscv_elfNN_vec
-#define TARGET_LITTLE_NAME             "elfNN-littleriscv"
-#define TARGET_BIG_SYM                 riscv_elfNN_be_vec
-#define TARGET_BIG_NAME                        "elfNN-bigriscv"
+#define TARGET_LITTLE_SYM                      riscv_elfNN_vec
+#define TARGET_LITTLE_NAME                     "elfNN-littleriscv"
+#define TARGET_BIG_SYM                         riscv_elfNN_be_vec
+#define TARGET_BIG_NAME                                "elfNN-bigriscv"
 
-#define elf_backend_reloc_type_class        riscv_reloc_type_class
+#define elf_backend_reloc_type_class           riscv_reloc_type_class
 
-#define bfd_elfNN_bfd_reloc_name_lookup             riscv_reloc_name_lookup
-#define bfd_elfNN_bfd_link_hash_table_create riscv_elf_link_hash_table_create
-#define bfd_elfNN_bfd_reloc_type_lookup             riscv_reloc_type_lookup
+#define bfd_elfNN_bfd_reloc_name_lookup                riscv_reloc_name_lookup
+#define bfd_elfNN_bfd_link_hash_table_create   riscv_elf_link_hash_table_create
+#define bfd_elfNN_bfd_reloc_type_lookup                riscv_reloc_type_lookup
 #define bfd_elfNN_bfd_merge_private_bfd_data \
   _bfd_riscv_elf_merge_private_bfd_data
 
-#define elf_backend_copy_indirect_symbol     riscv_elf_copy_indirect_symbol
-#define elf_backend_create_dynamic_sections  riscv_elf_create_dynamic_sections
-#define elf_backend_check_relocs            riscv_elf_check_relocs
-#define elf_backend_adjust_dynamic_symbol    riscv_elf_adjust_dynamic_symbol
-#define elf_backend_size_dynamic_sections    riscv_elf_size_dynamic_sections
-#define elf_backend_relocate_section        riscv_elf_relocate_section
-#define elf_backend_finish_dynamic_symbol    riscv_elf_finish_dynamic_symbol
-#define elf_backend_finish_dynamic_sections  riscv_elf_finish_dynamic_sections
-#define elf_backend_gc_mark_hook            riscv_elf_gc_mark_hook
-#define elf_backend_plt_sym_val                     riscv_elf_plt_sym_val
-#define elf_backend_grok_prstatus           riscv_elf_grok_prstatus
-#define elf_backend_grok_psinfo                     riscv_elf_grok_psinfo
-#define elf_backend_object_p                riscv_elf_object_p
-#define elf_info_to_howto_rel               NULL
-#define elf_info_to_howto                   riscv_info_to_howto_rela
-#define bfd_elfNN_bfd_relax_section         _bfd_riscv_relax_section
-#define bfd_elfNN_mkobject                  elfNN_riscv_mkobject
-
-#define elf_backend_init_index_section      _bfd_elf_init_1_index_section
-
-#define elf_backend_can_gc_sections    1
-#define elf_backend_can_refcount       1
-#define elf_backend_want_got_plt       1
-#define elf_backend_plt_readonly       1
-#define elf_backend_plt_alignment      4
-#define elf_backend_want_plt_sym       1
-#define elf_backend_got_header_size    (ARCH_SIZE / 8)
-#define elf_backend_want_dynrelro      1
-#define elf_backend_rela_normal                1
-#define elf_backend_default_execstack  0
+#define elf_backend_copy_indirect_symbol       riscv_elf_copy_indirect_symbol
+#define elf_backend_create_dynamic_sections    riscv_elf_create_dynamic_sections
+#define elf_backend_check_relocs               riscv_elf_check_relocs
+#define elf_backend_adjust_dynamic_symbol      riscv_elf_adjust_dynamic_symbol
+#define elf_backend_size_dynamic_sections      riscv_elf_size_dynamic_sections
+#define elf_backend_relocate_section           riscv_elf_relocate_section
+#define elf_backend_finish_dynamic_symbol      riscv_elf_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections    riscv_elf_finish_dynamic_sections
+#define elf_backend_gc_mark_hook               riscv_elf_gc_mark_hook
+#define elf_backend_plt_sym_val                        riscv_elf_plt_sym_val
+#define elf_backend_grok_prstatus              riscv_elf_grok_prstatus
+#define elf_backend_grok_psinfo                        riscv_elf_grok_psinfo
+#define elf_backend_object_p                   riscv_elf_object_p
+#define elf_backend_write_core_note            riscv_write_core_note
+#define elf_info_to_howto_rel                  NULL
+#define elf_info_to_howto                      riscv_info_to_howto_rela
+#define bfd_elfNN_bfd_relax_section            _bfd_riscv_relax_section
+#define bfd_elfNN_mkobject                     elfNN_riscv_mkobject
+
+#define elf_backend_init_index_section         _bfd_elf_init_1_index_section
+
+#define elf_backend_can_gc_sections            1
+#define elf_backend_can_refcount               1
+#define elf_backend_want_got_plt               1
+#define elf_backend_plt_readonly               1
+#define elf_backend_plt_alignment              4
+#define elf_backend_want_plt_sym               1
+#define elf_backend_got_header_size            (ARCH_SIZE / 8)
+#define elf_backend_want_dynrelro              1
+#define elf_backend_rela_normal                        1
+#define elf_backend_default_execstack          0
 
 #undef  elf_backend_obj_attrs_vendor
-#define elf_backend_obj_attrs_vendor            "riscv"
+#define elf_backend_obj_attrs_vendor           "riscv"
 #undef  elf_backend_obj_attrs_arg_type
-#define elf_backend_obj_attrs_arg_type          riscv_elf_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type         riscv_elf_obj_attrs_arg_type
 #undef  elf_backend_obj_attrs_section_type
-#define elf_backend_obj_attrs_section_type      SHT_RISCV_ATTRIBUTES
+#define elf_backend_obj_attrs_section_type     SHT_RISCV_ATTRIBUTES
 #undef  elf_backend_obj_attrs_section
-#define elf_backend_obj_attrs_section           ".riscv.attributes"
+#define elf_backend_obj_attrs_section          ".riscv.attributes"
 
 #include "elfNN-target.h"
This page took 0.034447 seconds and 4 git commands to generate.