Remove make_cleanup_value_free_to_mark
[deliverable/binutils-gdb.git] / bfd / elfnn-riscv.c
index 6b2d80c379879a3fc55712c4f8531a81bf7f2d6e..934704a87e78604b526f1a7c8f138a471bb46c5b 100644 (file)
@@ -1001,7 +1001,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       else
        {
          s->size += RISCV_ELF_WORD_BYTES;
-         if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h))
+         if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+             && ! UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
            htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
        }
     }
@@ -1040,7 +1041,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       if (eh->dyn_relocs != NULL
          && h->root.type == bfd_link_hash_undefweak)
        {
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+             || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
            eh->dyn_relocs = NULL;
 
          /* Make sure undefined weak symbols are output as a dynamic
@@ -1731,6 +1733,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
       int r_type = ELFNN_R_TYPE (rel->r_info), tls_type;
       reloc_howto_type *howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
       const char *msg = NULL;
+      bfd_boolean resolved_to_zero;
 
       if (howto == NULL
          || r_type == R_RISCV_GNU_VTINHERIT || r_type == R_RISCV_GNU_VTENTRY)
@@ -1785,6 +1788,9 @@ riscv_elf_relocate_section (bfd *output_bfd,
            name = bfd_section_name (input_bfd, sec);
        }
 
+      resolved_to_zero = (h != NULL
+                         && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+
       switch (r_type)
        {
        case R_RISCV_NONE:
@@ -1925,8 +1931,24 @@ riscv_elf_relocate_section (bfd *output_bfd,
          }
          break;
 
-       case R_RISCV_CALL_PLT:
        case R_RISCV_CALL:
+         /* Handle a call to an undefined weak function.  This won't be
+            relaxed, so we have to handle it here.  */
+         if (h != NULL && h->root.type == bfd_link_hash_undefweak
+             && h->plt.offset == MINUS_ONE)
+           {
+             /* We can use x0 as the base register.  */
+             bfd_vma insn = bfd_get_32 (input_bfd,
+                                        contents + rel->r_offset + 4);
+             insn &= ~(OP_MASK_RS1 << OP_SH_RS1);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset + 4);
+             /* Set the relocation value so that we get 0 after the pc
+                relative adjustment.  */
+             relocation = sec_addr (input_section) + rel->r_offset;
+           }
+         /* Fall through.  */
+
+       case R_RISCV_CALL_PLT:
        case R_RISCV_JAL:
        case R_RISCV_RVC_JUMP:
          if (bfd_link_pic (info) && h != NULL && h->plt.offset != MINUS_ONE)
@@ -2032,7 +2054,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
 
          if ((bfd_link_pic (info)
               && (h == NULL
-                  || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                  || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                      && !resolved_to_zero)
                   || h->root.type != bfd_link_hash_undefweak)
               && (! howto->pc_relative
                   || !SYMBOL_CALLS_LOCAL (info, h)))
@@ -2356,7 +2379,8 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
     }
 
   if (h->got.offset != (bfd_vma) -1
-      && !(riscv_elf_hash_entry (h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE)))
+      && !(riscv_elf_hash_entry (h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE))
+      && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
     {
       asection *sgot;
       asection *srela;
@@ -2370,15 +2394,15 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
 
       rela.r_offset = sec_addr (sgot) + (h->got.offset &~ (bfd_vma) 1);
 
-      /* If this is a -Bsymbolic link, and the symbol is defined
-        locally, we just want to emit a RELATIVE reloc.  Likewise if
+      /* If this is a local symbol reference, we just want to emit a RELATIVE
+        reloc.  This can happen if it is a -Bsymbolic link, 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.  */
       if (bfd_link_pic (info)
-         && (info->symbolic || h->dynindx == -1)
-         && h->def_regular)
+         && SYMBOL_REFERENCES_LOCAL (info, h))
        {
+         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
@@ -2387,6 +2411,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
        }
       else
        {
+         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;
@@ -2617,6 +2642,14 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       goto fail;
     }
 
+  /* Disallow linking RVE and non-RVE.  */
+  if ((old_flags ^ new_flags) & EF_RISCV_RVE)
+    {
+      (*_bfd_error_handler)
+       (_("%pB: can't link RVE with other target"), ibfd);
+      goto fail;
+    }
+
   /* Allow linking RVC and non-RVC, and keep the RVC flag.  */
   elf_elfheader (obfd)->e_flags |= new_flags & EF_RISCV_RVC;
 
@@ -2665,10 +2698,16 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count,
 
          /* If the symbol *spans* the bytes we just deleted (i.e. its
             *end* is in the moved bytes but its *start* isn't), then we
-            must adjust its size.  */
-         if (sym->st_value <= addr
-             && sym->st_value + sym->st_size > addr
-             && sym->st_value + sym->st_size <= toaddr)
+            must adjust its size.
+
+            This test needs to use the original value of st_value, otherwise
+            we might accidentally decrease size when deleting bytes right
+            before the symbol.  But since deleted relocs can't span across
+            symbols, we can't have both a st_value and a st_size decrease,
+            so it is simpler to just use an else.  */
+         else if (sym->st_value <= addr
+                  && sym->st_value + sym->st_size > addr
+                  && sym->st_value + sym->st_size <= toaddr)
            sym->st_size -= count;
        }
     }
@@ -2686,9 +2725,12 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count,
         call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
         the same symbol (which is __wrap_SYMBOL), but still exist as two
         different symbols in 'sym_hashes', we don't want to adjust
-        the global symbol __wrap_SYMBOL twice.
-        This check is only relevant when symbols are being wrapped.  */
-      if (link_info->wrap_hash != NULL)
+        the global symbol __wrap_SYMBOL twice.  */
+      /* 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
+         || sym_hash->versioned == versioned_hidden)
        {
          struct elf_link_hash_entry **cur_sym_hashes;
 
@@ -2716,9 +2758,9 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count,
            sym_hash->root.u.def.value -= count;
 
          /* As above, adjust the size if needed.  */
-         if (sym_hash->root.u.def.value <= addr
-             && sym_hash->root.u.def.value + sym_hash->size > addr
-             && sym_hash->root.u.def.value + sym_hash->size <= toaddr)
+         else if (sym_hash->root.u.def.value <= addr
+                  && sym_hash->root.u.def.value + sym_hash->size > addr
+                  && sym_hash->root.u.def.value + sym_hash->size <= toaddr)
            sym_hash->size -= count;
        }
     }
This page took 0.025404 seconds and 4 git commands to generate.