elf_backend_relocate_section int vs. bfd_boolean
[deliverable/binutils-gdb.git] / bfd / elfnn-riscv.c
index b2ec6a29fbf41628a2d0fb03b4ca10463692dc2c..ddccb40e243ecf803ded717827a2002c50fab7a5 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>
@@ -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:
@@ -1927,7 +1932,7 @@ riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p)
    section, which means that the addend must be adjusted
    accordingly.  */
 
-static bfd_boolean
+static int
 riscv_elf_relocate_section (bfd *output_bfd,
                            struct bfd_link_info *info,
                            bfd *input_bfd,
@@ -3679,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,
@@ -3801,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
@@ -3826,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)
     {
@@ -4136,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)
@@ -4145,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.  */
@@ -4154,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));
@@ -4166,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;
@@ -4295,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)))
     {
@@ -4362,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,
@@ -4385,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)
     {
@@ -4583,7 +4588,7 @@ _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)
 {
@@ -4591,15 +4596,39 @@ _bfd_riscv_relax_delete (bfd *abfd,
                                 link_info))
     return FALSE;
   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,
@@ -4618,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);
@@ -4861,6 +4891,9 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
     free (relocs);
   riscv_free_pcgp_relocs (&pcgp_relocs, abfd, sec);
 
+  if (*again)
+    htab->restart_relax = TRUE;
+
   return ret;
 }
 
@@ -4874,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
@@ -4884,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.  */
 
@@ -4927,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;
     }
 
@@ -5000,6 +5112,7 @@ riscv_elf_obj_attrs_arg_type (int tag)
 #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
This page took 0.028384 seconds and 4 git commands to generate.