gdb/dwarf: pass compilation directory to line header
[binutils-gdb.git] / bfd / elfnn-riscv.c
index 36cbf1ed15f5fd100f46396744926516265ec8cc..8f9f0d8a86a3a793b627b0de653b83a5df3338db 100644 (file)
@@ -1,5 +1,5 @@
 /* RISC-V-specific support for NN-bit ELF.
-   Copyright (C) 2011-2021 Free Software Foundation, Inc.
+   Copyright (C) 2011-2022 Free Software Foundation, Inc.
 
    Contributed by Andrew Waterman (andrew@sifive.com).
    Based on TILE-Gx and MIPS targets.
@@ -134,6 +134,9 @@ struct riscv_elf_link_hash_table
   /* The data segment phase, don't relax the section
      when it is exp_seg_relro_adjust.  */
   int *data_segment_phase;
+
+  /* Relocations for variant CC symbols may be present.  */
+  int variant_cc;
 };
 
 /* Instruction access functions. */
@@ -1172,6 +1175,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              h->root.u.def.section = s;
              h->root.u.def.value = h->plt.offset;
            }
+
+         /* If the symbol has STO_RISCV_VARIANT_CC flag, then raise the
+            variant_cc flag of riscv_elf_link_hash_table.  */
+         if (h->other & STO_RISCV_VARIANT_CC)
+           htab->variant_cc = 1;
        }
       else
        {
@@ -1555,7 +1563,18 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
        return false;
     }
 
-  return _bfd_elf_add_dynamic_tags (output_bfd, info, true);
+  /* Add dynamic entries.  */
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      if (!_bfd_elf_add_dynamic_tags (output_bfd, info, true))
+       return false;
+
+      if (htab->variant_cc
+         && !_bfd_elf_add_dynamic_entry (info, DT_RISCV_VARIANT_CC, 0))
+       return false;
+    }
+
+  return true;
 }
 
 #define TP_OFFSET 0
@@ -3352,52 +3371,27 @@ riscv_std_ext_p (const char *name)
   return (strlen (name) == 1) && (name[0] != 'x') && (name[0] != 's');
 }
 
-/* Check if the versions are compatible.  */
+/* Update the output subset's version to match the input when the input
+   subset's version is newer.  */
 
-static bool
-riscv_version_mismatch (bfd *ibfd,
-                       struct riscv_subset_t *in,
-                       struct riscv_subset_t *out)
+static void
+riscv_update_subset_version (struct riscv_subset_t *in,
+                            struct riscv_subset_t *out)
 {
   if (in == NULL || out == NULL)
-    return true;
-
-  /* Since there are no version conflicts for now, we just report
-     warning when the versions are mis-matched.  */
-  if (in->major_version != out->major_version
-      || in->minor_version != out->minor_version)
+    return;
+
+  /* Update the output ISA versions to the newest ones, but otherwise don't
+     provide any errors or warnings about mis-matched ISA versions as it's
+     generally too tricky to check for these at link time. */
+  if ((in->major_version > out->major_version)
+      || (in->major_version == out->major_version
+         && in->minor_version > out->minor_version)
+      || (out->major_version == RISCV_UNKNOWN_VERSION))
     {
-      if ((in->major_version == RISCV_UNKNOWN_VERSION
-          && in->minor_version == RISCV_UNKNOWN_VERSION)
-         || (out->major_version == RISCV_UNKNOWN_VERSION
-             && out->minor_version == RISCV_UNKNOWN_VERSION))
-       {
-         /* Do not report the warning when the version of input
-            or output is RISCV_UNKNOWN_VERSION, since the extension
-            is added implicitly.  */
-       }
-      else
-       _bfd_error_handler
-         (_("warning: %pB: mis-matched ISA version %d.%d for '%s' "
-            "extension, the output version is %d.%d"),
-          ibfd,
-          in->major_version,
-          in->minor_version,
-          in->name,
-          out->major_version,
-          out->minor_version);
-
-      /* Update the output ISA versions to the newest ones.  */
-      if ((in->major_version > out->major_version)
-         || (in->major_version == out->major_version
-             && in->minor_version > out->minor_version))
-       {
-         out->major_version = in->major_version;
-         out->minor_version = in->minor_version;
-       }
+      out->major_version = in->major_version;
+      out->minor_version = in->minor_version;
     }
-
-  return true;
 }
 
 /* Return true if subset is 'i' or 'e'.  */
@@ -3458,11 +3452,10 @@ riscv_merge_std_ext (bfd *ibfd,
         ibfd, in->name, out->name);
       return false;
     }
-  else if (!riscv_version_mismatch (ibfd, in, out))
-    return false;
-  else
-    riscv_add_subset (&merged_subsets,
-                     out->name, out->major_version, out->minor_version);
+
+  riscv_update_subset_version(in, out);
+  riscv_add_subset (&merged_subsets,
+                   out->name, out->major_version, out->minor_version);
 
   in = in->next;
   out = out->next;
@@ -3480,10 +3473,8 @@ riscv_merge_std_ext (bfd *ibfd,
       if (!find_in && !find_out)
        continue;
 
-      if (find_in
-         && find_out
-         && !riscv_version_mismatch (ibfd, ext_in, ext_out))
-       return false;
+      if (find_in && find_out)
+       riscv_update_subset_version(ext_in, ext_out);
 
       ext_merged = find_out ? ext_out : ext_in;
       riscv_add_subset (&merged_subsets, ext_merged->name,
@@ -3505,8 +3496,7 @@ riscv_merge_std_ext (bfd *ibfd,
    on success and FALSE when a conflict is found.  */
 
 static bool
-riscv_merge_multi_letter_ext (bfd *ibfd,
-                             riscv_subset_t **pin,
+riscv_merge_multi_letter_ext (riscv_subset_t **pin,
                              riscv_subset_t **pout)
 {
   riscv_subset_t *in = *pin;
@@ -3536,8 +3526,7 @@ riscv_merge_multi_letter_ext (bfd *ibfd,
       else
        {
          /* Both present, check version and increment both.  */
-         if (!riscv_version_mismatch (ibfd, in, out))
-           return false;
+         riscv_update_subset_version (in, out);
 
          riscv_add_subset (&merged_subsets, out->name, out->major_version,
                            out->minor_version);
@@ -3610,7 +3599,7 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)
     return NULL;
 
   /* Merge all non-single letter extensions with single call.  */
-  if (!riscv_merge_multi_letter_ext (ibfd, &in, &out))
+  if (!riscv_merge_multi_letter_ext (&in, &out))
     return NULL;
 
   if (xlen_in != xlen_out)
@@ -5227,6 +5216,28 @@ riscv_elf_modify_segment_map (bfd *abfd,
   return true;
 }
 
+/* Merge non-visibility st_other attributes.  */
+
+static void
+riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
+                                 unsigned int st_other,
+                                 bool definition ATTRIBUTE_UNUSED,
+                                 bool dynamic ATTRIBUTE_UNUSED)
+{
+  unsigned int isym_sto = st_other & ~ELF_ST_VISIBILITY (-1);
+  unsigned int h_sto = h->other & ~ELF_ST_VISIBILITY (-1);
+
+  if (isym_sto == h_sto)
+    return;
+
+  if (isym_sto & ~STO_RISCV_VARIANT_CC)
+    _bfd_error_handler (_("unknown attribute for symbol `%s': 0x%02x"),
+                       h->root.root.string, isym_sto);
+
+  if (isym_sto & STO_RISCV_VARIANT_CC)
+    h->other |= STO_RISCV_VARIANT_CC;
+}
+
 #define TARGET_LITTLE_SYM                      riscv_elfNN_vec
 #define TARGET_LITTLE_NAME                     "elfNN-littleriscv"
 #define TARGET_BIG_SYM                         riscv_elfNN_be_vec
@@ -5263,6 +5274,7 @@ riscv_elf_modify_segment_map (bfd *abfd,
 #define elf_backend_additional_program_headers \
   riscv_elf_additional_program_headers
 #define elf_backend_modify_segment_map         riscv_elf_modify_segment_map
+#define elf_backend_merge_symbol_attribute     riscv_elf_merge_symbol_attribute
 
 #define elf_backend_init_index_section         _bfd_elf_init_1_index_section