/* 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.
/* 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. */
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
{
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
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'. */
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;
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,
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;
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);
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)
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
#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