Make bfd_byte an int8_t, flagword a uint32_t
[binutils-gdb.git] / bfd / elfnn-riscv.c
index 00f034a67513bd9df29b892516c392135d438d56..e90e36b58bbbd2da875a37678d609f5fa9d4d189 100644 (file)
@@ -200,6 +200,9 @@ struct riscv_elf_link_hash_table
   /* The max alignment of output sections.  */
   bfd_vma max_alignment;
 
+  /* The max alignment of output sections in [gp-2K, gp+2K) range.  */
+  bfd_vma max_alignment_for_gp;
+
   /* Used by local STT_GNU_IFUNC symbols.  */
   htab_t loc_hash_table;
   void * loc_hash_memory;
@@ -488,6 +491,7 @@ riscv_elf_link_hash_table_create (bfd *abfd)
     }
 
   ret->max_alignment = (bfd_vma) -1;
+  ret->max_alignment_for_gp = (bfd_vma) -1;
 
   /* Create hash table for local ifunc.  */
   ret->loc_hash_table = htab_try_create (1024,
@@ -862,6 +866,47 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                 ifunc symbol.  */
              h->plt.refcount += 1;
            }
+
+         /* The non-preemptible absolute symbol shouldn't be referneced with
+            pc-relative relocation when generating shared object.  However,
+            PCREL_HI20/LO12 relocs are always bind locally when generating
+            shared object, so all absolute symbol referenced need to be
+            disallowed, except they are defined in linker script.
+
+            Maybe we should add this check for all pc-relative relocations,
+            please see pr28789 and pr25749 for details.  */
+         if (bfd_link_pic (info)
+             /* (h == NULL || SYMBOL_REFERENCES_LOCAL (info, h))  */
+             && is_abs_symbol)
+           {
+             if (h != NULL && (h)->root.ldscript_def)
+               /* Disallow the absolute symbol defined in linker script here
+                  will cause the glibc-linux toolchain build failed, so regard
+                  them as pc-relative symbols, just like what x86 did.  */
+               ;
+             else
+               {
+                 const char *name;
+                 if (h->root.root.string)
+                   name = h->root.root.string;
+                 else
+                   {
+                     Elf_Internal_Sym *sym;
+                     sym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd,
+                                                  r_symndx);
+                     name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
+                   }
+
+                 reloc_howto_type *r_t =
+                       riscv_elf_rtype_to_howto (abfd, r_type);
+                 _bfd_error_handler
+                   (_("%pB: relocation %s against absolute symbol `%s' can "
+                      "not be used when making a shared object"),
+                    abfd, r_t ? r_t->name : _("<unknown>"), name);
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
+           }
          /* Fall through.  */
 
        case R_RISCV_JAL:
@@ -4419,17 +4464,27 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
                                   link_info, pcgp_relocs, rel + 1);
 }
 
-/* Traverse all output sections and return the max alignment.  */
+/* Traverse all output sections and return the max alignment.
+
+   If gp is zero, then all the output section alignments are
+   possible candidates;  Otherwise, only the output sections
+   which are in the [gp-2K, gp+2K) range need to be considered.  */
 
 static bfd_vma
-_bfd_riscv_get_max_alignment (asection *sec)
+_bfd_riscv_get_max_alignment (asection *sec, bfd_vma gp)
 {
   unsigned int max_alignment_power = 0;
   asection *o;
 
   for (o = sec->output_section->owner->sections; o != NULL; o = o->next)
     {
-      if (o->alignment_power > max_alignment_power)
+      bool valid = true;
+      if (gp
+         && !(VALID_ITYPE_IMM (sec_addr (o) - gp)
+              || VALID_ITYPE_IMM (sec_addr (o) + o->size - gp)))
+       valid = false;
+
+      if (valid && o->alignment_power > max_alignment_power)
        max_alignment_power = o->alignment_power;
     }
 
@@ -4451,15 +4506,16 @@ _bfd_riscv_relax_lui (bfd *abfd,
                      riscv_pcgp_relocs *pcgp_relocs,
                      bool undefined_weak)
 {
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (link_info);
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
-  bfd_vma gp = riscv_elf_hash_table (link_info)->params->relax_gp
-                  ? riscv_global_pointer_value (link_info)
-                  : 0;
+  bfd_vma gp = htab->params->relax_gp
+              ? riscv_global_pointer_value (link_info)
+              : 0;
   int use_rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC;
 
   BFD_ASSERT (rel->r_offset + 4 <= sec->size);
 
-  if (gp)
+  if (!undefined_weak && gp)
     {
       /* If gp and the symbol are in the same output section, which is not the
         abs section, then consider only that output section's alignment.  */
@@ -4469,16 +4525,28 @@ _bfd_riscv_relax_lui (bfd *abfd,
       if (h->u.def.section->output_section == sym_sec->output_section
          && sym_sec->output_section != bfd_abs_section_ptr)
        max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power;
+      else
+       {
+         /* Consider output section alignments which are in [gp-2K, gp+2K). */
+         max_alignment = htab->max_alignment_for_gp;
+         if (max_alignment == (bfd_vma) -1)
+           {
+             max_alignment = _bfd_riscv_get_max_alignment (sec, gp);
+             htab->max_alignment_for_gp = max_alignment;
+           }
+       }
     }
 
   /* Is the reference in range of x0 or gp?
-     Valid gp range conservatively because of alignment issue.  */
+     Valid gp range conservatively because of alignment issue.
+
+     Should we also consider the alignment issue for x0 base?  */
   if (undefined_weak
-      || (VALID_ITYPE_IMM (symval)
-         || (symval >= gp
-             && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
-         || (symval < gp
-             && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))))
+      || VALID_ITYPE_IMM (symval)
+      || (symval >= gp
+         && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
+      || (symval < gp
+         && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))
     {
       unsigned sym = ELFNN_R_SYM (rel->r_info);
       switch (ELFNN_R_TYPE (rel->r_info))
@@ -4668,6 +4736,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
                     riscv_pcgp_relocs *pcgp_relocs,
                     bool undefined_weak)
 {
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (link_info);
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   bfd_vma gp = riscv_global_pointer_value (link_info);
 
@@ -4724,7 +4793,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
       abort ();
     }
 
-  if (gp)
+  if (!undefined_weak && gp)
     {
       /* If gp and the symbol are in the same output section, which is not the
         abs section, then consider only that output section's alignment.  */
@@ -4734,16 +4803,28 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
       if (h->u.def.section->output_section == sym_sec->output_section
          && sym_sec->output_section != bfd_abs_section_ptr)
        max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power;
+      else
+       {
+         /* Consider output section alignments which are in [gp-2K, gp+2K). */
+         max_alignment = htab->max_alignment_for_gp;
+         if (max_alignment == (bfd_vma) -1)
+           {
+             max_alignment = _bfd_riscv_get_max_alignment (sec, gp);
+             htab->max_alignment_for_gp = max_alignment;
+           }
+       }
     }
 
   /* Is the reference in range of x0 or gp?
-     Valid gp range conservatively because of alignment issue.  */
+     Valid gp range conservatively because of alignment issue.
+
+     Should we also consider the alignment issue for x0 base?  */
   if (undefined_weak
-      || (VALID_ITYPE_IMM (symval)
-         || (symval >= gp
-             && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
-         || (symval < gp
-             && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))))
+      || VALID_ITYPE_IMM (symval)
+      || (symval >= gp
+         && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
+      || (symval < gp
+         && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))
     {
       unsigned sym = hi_reloc.hi_sym;
       switch (ELFNN_R_TYPE (rel->r_info))
@@ -4836,6 +4917,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
   unsigned int i;
   bfd_vma max_alignment, reserve_size = 0;
   riscv_pcgp_relocs pcgp_relocs;
+  static asection *first_section = NULL;
 
   *again = false;
 
@@ -4851,6 +4933,13 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
       || *(htab->data_segment_phase) == 4)
     return true;
 
+  /* Record the first relax section, so that we can reset the
+     max_alignment_for_gp for the repeated relax passes.  */
+  if (first_section == NULL)
+    first_section = sec;
+  else if (first_section == sec)
+    htab->max_alignment_for_gp = -1;
+
   riscv_init_pcgp_relocs (&pcgp_relocs);
 
   /* Read this BFD's relocs if we haven't done so already.  */
@@ -4860,17 +4949,14 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
                                                 info->keep_memory)))
     goto fail;
 
-  if (htab)
+  /* Estimate the maximum alignment for all output sections once time
+     should be enough.  */
+  max_alignment = htab->max_alignment;
+  if (max_alignment == (bfd_vma) -1)
     {
-      max_alignment = htab->max_alignment;
-      if (max_alignment == (bfd_vma) -1)
-       {
-         max_alignment = _bfd_riscv_get_max_alignment (sec);
-         htab->max_alignment = max_alignment;
-       }
+      max_alignment = _bfd_riscv_get_max_alignment (sec, 0/* gp */);
+      htab->max_alignment = max_alignment;
     }
-  else
-    max_alignment = _bfd_riscv_get_max_alignment (sec);
 
   /* Examine and consider relaxing each reloc.  */
   for (i = 0; i < sec->reloc_count; i++)