aboutsummaryrefslogtreecommitdiff
path: root/bfd/elfxx-riscv.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elfxx-riscv.c')
-rw-r--r--bfd/elfxx-riscv.c320
1 files changed, 312 insertions, 8 deletions
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 9364442..43d3c0d 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1022,6 +1022,12 @@ static const struct elf_reloc_map riscv_reloc_map[] =
{ BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
};
+struct riscv_profiles
+{
+ const char *profile_name;
+ const char *profile_string;
+};
+
/* Given a BFD reloc type, return a howto structure. */
reloc_howto_type *
@@ -1206,6 +1212,9 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
{"xsfvqmaccdod", "+zve32x,+zvl128b", check_implicit_always},
{"xsfvfnrclipxfqf", "+zve32f", check_implicit_always},
+ {"xtheadvector", "+zicsr", check_implicit_always},
+ {"xtheadzvamo", "+zaamo", check_implicit_always},
+
{"v", "+zve64d,+zvl128b", check_implicit_always},
{"zvfh", "+zvfhmin,+zfhmin", check_implicit_always},
{"zvfhmin", "+zve32f", check_implicit_always},
@@ -1239,6 +1248,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
{"zicfilp", "+zicsr", check_implicit_always},
{"zicfiss", "+zimop,+zicsr", check_implicit_always},
+ {"zclsd", "+zca,+zilsd", check_implicit_always},
{"sha", "+h,+ssstateen,+shcounterenw,+shvstvala,+shtvala,+shvstvecd,+shvsatpa,+shgatpa", check_implicit_always},
@@ -1279,9 +1289,11 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
{"zvks", "+zvksed,+zvksh,+zvkb,+zvkt", check_implicit_always},
{"smaia", "+ssaia", check_implicit_always},
+ {"smcdeleg", "+ssccfg", check_implicit_always},
{"smcsrind", "+sscsrind", check_implicit_always},
{"smcntrpmf", "+zicsr", check_implicit_always},
{"smctr", "+zicsr", check_implicit_always},
+ {"smrnmi", "+zicsr", check_implicit_always},
{"smstateen", "+ssstateen", check_implicit_always},
{"smepmp", "+zicsr", check_implicit_always},
{"smdbltrp", "+zicsr", check_implicit_always},
@@ -1289,6 +1301,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
{"smmpm", "+zicsr", check_implicit_always},
{"ssaia", "+zicsr", check_implicit_always},
+ {"ssccfg", "+sscsrind", check_implicit_always},
{"sscsrind", "+zicsr", check_implicit_always},
{"sscofpmf", "+zicsr", check_implicit_always},
{"sscounterenw", "+zicsr", check_implicit_always},
@@ -1307,6 +1320,61 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
{NULL, NULL, NULL}
};
+/* This table records the mapping form RISC-V Profiles into march string. */
+static struct riscv_profiles riscv_profiles_table[] =
+{
+ /* RVI20U only contains the base extension 'i' as mandatory extension. */
+ {"rvi20u64", "rv64i"},
+ {"rvi20u32", "rv32i"},
+
+ /* RVA20U contains the 'i,m,a,f,d,c,zicsr,zicntr,ziccif,ziccrse,ziccamoa,
+ zicclsm,za128rs' as mandatory extensions. */
+ {"rva20u64", "rv64imafdc_zicsr_zicntr_ziccif_ziccrse_ziccamoa"
+ "_zicclsm_za128rs"},
+
+ /* RVA22U contains the 'i,m,a,f,d,c,zicsr,zihintpause,zba,zbb,zbs,zicntr,
+ zihpm,ziccif,ziccrse,ziccamoa, zicclsm,zic64b,za64rs,zicbom,zicbop,zicboz,
+ zfhmin,zkt' as mandatory extensions. */
+ {"rva22u64", "rv64imafdc_zicsr_zicntr_ziccif_ziccrse_ziccamoa"
+ "_zicclsm_zic64b_za64rs_zihintpause_zba_zbb_zbs_zicbom_zicbop"
+ "_zicboz_zfhmin_zkt"},
+
+ /* RVA23 contains all mandatory base ISA for RVA22U64 and the new extension
+ 'v,zihintntl,zvfhmin,zvbb,zvkt,zicond,zimop,zcmop,zfa,zawrs' as mandatory
+ extensions. */
+ {"rva23u64", "rv64imafdcbv_zicsr_zicntr_zihpm_ziccif_ziccrse_ziccamoa"
+ "_zicclsm_zic64b_za64rs_zihintpause_zba_zbb_zbs_zicbom_zicbop"
+ "_zicboz_zfhmin_zkt_zvfhmin_zvbb_zvkt_zihintntl_zicond_zimop_zcmop_zcb"
+ "_zfa_zawrs_supm"},
+
+ /* RVA23S contains all mandatory base ISA for RVA23U64 and the privileged
+ extensions as mandatory extensions. */
+ {"rva23s64", "rv64imafdcbv_zicsr_zicntr_zihpm_ziccif_ziccrse_ziccamoa"
+ "_zicclsm_zic64b_za64rs_zihintpause_zba_zbb_zbs_zicbom_zicbop"
+ "_zicboz_zfhmin_zkt_zvfhmin_zvbb_zvkt_zihintntl_zicond_zimop_zcmop_zcb"
+ "_zfa_zawrs_supm_svbare_svade_ssccptr_sstvecd_sstvala_sscounterenw_svpbmt"
+ "_svinval_svnapot_sstc_sscofpmf_ssnpm_ssu64xl_sha"},
+
+ /* RVB23 contains all mandatory base ISA for RVA22U64 and the new extension
+ 'zihintntl,zicond,zimop,zcmop,zfa,zawrs' as mandatory
+ extensions. */
+ {"rvb23u64", "rv64imafdcb_zicsr_zicntr_zihpm_ziccif_ziccrse_ziccamoa"
+ "_zicclsm_zic64b_za64rs_zihintpause_zba_zbb_zbs_zicbom_zicbop"
+ "_zicboz_zfhmin_zkt_zihintntl_zicond_zimop_zcmop_zcb"
+ "_zfa_zawrs_supm"},
+
+ /* RVB23S contains all mandatory base ISA for RVB23U64 and the privileged
+ extensions as mandatory extensions. */
+ {"rvb23s64", "rv64imafdcb_zicsr_zicntr_zihpm_ziccif_ziccrse_ziccamoa"
+ "_zicclsm_zic64b_za64rs_zihintpause_zba_zbb_zbs_zicbom_zicbop"
+ "_zicboz_zfhmin_zkt_zvfhmin_zvbb_zvkt_zihintntl_zicond_zimop_zcmop_zcb"
+ "_zfa_zawrs_supm_svbare_svade_ssccptr_sstvecd_sstvala_sscounterenw_svpbmt"
+ "_svinval_svnapot_sstc_sscofpmf_ssu64xl"},
+
+ /* Terminate the list. */
+ {NULL, NULL}
+};
+
/* For default_enable field, decide if the extension should
be enbaled by default. */
@@ -1382,6 +1450,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
{"zimop", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zicfiss", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zicfilp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zilsd", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zmmul", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"za64rs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"za128rs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
@@ -1462,6 +1531,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
{"zcmop", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zcmp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zcmt", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zclsd", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{NULL, 0, 0, 0, 0}
};
@@ -1475,6 +1545,7 @@ static struct riscv_supported_ext riscv_supported_std_s_ext[] =
{"shvstvala", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"shvstvecd", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"smaia", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"smcdeleg", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"smcsrind", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"smcntrpmf", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"smctr", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
@@ -1483,6 +1554,7 @@ static struct riscv_supported_ext riscv_supported_std_s_ext[] =
{"smstateen", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"smdbltrp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"ssaia", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"ssccfg", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"ssccptr", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"sscsrind", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"sscofpmf", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
@@ -1500,6 +1572,7 @@ static struct riscv_supported_ext riscv_supported_std_s_ext[] =
{"svinval", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"svnapot", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"svpbmt", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"svvptc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"ssqosid", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"ssnpm", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"smnpm", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
@@ -1965,10 +2038,11 @@ riscv_parsing_subset_version (const char *p,
static const char *
riscv_parse_extensions (riscv_parse_subset_t *rps,
const char *arch,
- const char *p)
+ const char *p,
+ bool profile)
{
- /* First letter must start with i, e or g. */
- if (*p != 'e' && *p != 'i' && *p != 'g')
+ /* First letter must start with i, e, g or a profile. */
+ if (*p != 'e' && *p != 'i' && *p != 'g' && !profile)
{
rps->error_handler
(_("%s: first ISA extension must be `e', `i' or `g'"),
@@ -2152,10 +2226,19 @@ riscv_parse_check_conflicts (riscv_parse_subset_t *rps)
no_conflict = false;
}
if (riscv_lookup_subset (rps->subset_list, "xtheadvector", &subset)
- && riscv_lookup_subset (rps->subset_list, "v", &subset))
+ && riscv_lookup_subset (rps->subset_list, "zve32x", &subset))
{
rps->error_handler
- (_("`xtheadvector' is conflict with the `v' extension"));
+ (_("`xtheadvector' is conflict with the `v/zve32x' extension"));
+ no_conflict = false;
+ }
+ if (riscv_lookup_subset (rps->subset_list, "zclsd", &subset)
+ && ((riscv_lookup_subset (rps->subset_list, "c", &subset)
+ && riscv_lookup_subset (rps->subset_list, "f", &subset))
+ || riscv_lookup_subset (rps->subset_list, "zcf", &subset)))
+ {
+ rps->error_handler
+ (_("`zclsd' is conflict with the `c+f'/ `zcf' extension"));
no_conflict = false;
}
if (riscv_lookup_subset (rps->subset_list, "ssnpm", &subset) && xlen != 64)
@@ -2237,6 +2320,42 @@ riscv_set_default_arch (riscv_parse_subset_t *rps)
}
}
+static bool
+riscv_find_profiles (riscv_parse_subset_t *rps, const char **pp)
+{
+ const char *p = *pp;
+
+ /* Checking if input string contains a Profiles.
+ There are two cases use Profiles in -march option:
+
+ 1. Only use Profiles in '-march' as input
+ 2. Mixed Profiles with other extensions
+
+ Use '_' to split Profiles and other extensions. */
+
+ for (int i = 0; riscv_profiles_table[i].profile_name != NULL; ++i)
+ {
+ /* Find profile at the begin. */
+ if (startswith (p, riscv_profiles_table[i].profile_name))
+ {
+ /* Handle the profile string. */
+ riscv_parse_subset (rps, riscv_profiles_table[i].profile_string);
+ p += strlen (riscv_profiles_table[i].profile_name);
+ /* Handle string after profiles if exists. If missing underline
+ bewteen profile and other extensions, warn the user but not deal
+ as an error. */
+ if (*p != '\0' && *p != '_')
+ _bfd_error_handler
+ (_("Warning: should use \"_\" to contact Profiles with other "
+ "extensions"));
+ *pp = p;
+ return true;
+ }
+ }
+ /* Not found profile, return directly. */
+ return false;
+}
+
/* Function for parsing ISA string.
Return Value:
@@ -2274,8 +2393,14 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
}
}
+ bool profile = false;
p = arch;
- if (startswith (p, "rv32"))
+ if (riscv_find_profiles (rps, &p))
+ {
+ /* Check if using Profiles. */
+ profile = true;
+ }
+ else if (startswith (p, "rv32"))
{
*rps->xlen = 32;
p += 4;
@@ -2296,13 +2421,13 @@ riscv_parse_subset (riscv_parse_subset_t *rps,
string is empty. */
if (strlen (arch))
rps->error_handler (
- _("%s: ISA string must begin with rv32 or rv64"),
+ _("%s: ISA string must begin with rv32, rv64 or Profiles"),
arch);
return false;
}
/* Parse single standard and prefixed extensions. */
- if (riscv_parse_extensions (rps, arch, p) == NULL)
+ if (riscv_parse_extensions (rps, arch, p, profile) == NULL)
return false;
/* Finally add implicit extensions according to the current
@@ -2826,6 +2951,10 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
case INSN_CLASS_SMCTR_OR_SSCTR:
return (riscv_subset_supports (rps, "smctr")
|| riscv_subset_supports (rps, "ssctr"));
+ case INSN_CLASS_ZILSD:
+ return riscv_subset_supports (rps, "zilsd");
+ case INSN_CLASS_ZCLSD:
+ return riscv_subset_supports (rps, "zclsd");
case INSN_CLASS_SMRNMI:
return riscv_subset_supports (rps, "smrnmi");
case INSN_CLASS_SVINVAL:
@@ -3143,6 +3272,10 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
return "zcmt";
case INSN_CLASS_SMCTR_OR_SSCTR:
return _("smctr' or `ssctr");
+ case INSN_CLASS_ZILSD:
+ return "zilsd";
+ case INSN_CLASS_ZCLSD:
+ return "zclsd";
case INSN_CLASS_SMRNMI:
return "smrnmi";
case INSN_CLASS_SVINVAL:
@@ -3247,3 +3380,174 @@ riscv_print_extensions (void)
}
printf ("\n");
}
+
+/* Find the first input bfd with GNU property and merge it with GPROP. If no
+ such input is found, add it to a new section at the last input. Update
+ GPROP accordingly. */
+
+bfd *
+_bfd_riscv_elf_link_setup_gnu_properties (struct bfd_link_info *info,
+ uint32_t *and_prop_p)
+{
+ asection *sec;
+ bfd *pbfd;
+ bfd *ebfd = NULL;
+ elf_property *prop;
+
+ uint32_t and_prop = *and_prop_p;
+
+ /* Find a normal input file with GNU property note. */
+ for (pbfd = info->input_bfds; pbfd != NULL; pbfd = pbfd->link.next)
+ if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour
+ && bfd_count_sections (pbfd) != 0)
+ {
+ ebfd = pbfd;
+
+ if (elf_properties (pbfd) != NULL)
+ break;
+ }
+
+ /* If ebfd != NULL it is either an input with property note or the last
+ input. Either way if we have and_prop, we should add it (by
+ creating a section if needed). */
+ if (ebfd != NULL && (and_prop))
+ {
+ prop = _bfd_elf_get_property (ebfd, GNU_PROPERTY_RISCV_FEATURE_1_AND, 4);
+
+ prop->u.number |= and_prop;
+ prop->pr_kind = property_number;
+
+ /* pbfd being NULL implies ebfd is the last input. Create the GNU
+ property note section. */
+ if (pbfd == NULL)
+ {
+ sec
+ = bfd_make_section_with_flags (ebfd, NOTE_GNU_PROPERTY_SECTION_NAME,
+ (SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
+ | SEC_READONLY | SEC_HAS_CONTENTS
+ | SEC_DATA));
+ if (sec == NULL)
+ info->callbacks->einfo (
+ _ ("%F%P: failed to create GNU property section\n"));
+
+ elf_section_type (sec) = SHT_NOTE;
+ }
+ }
+
+ pbfd = _bfd_elf_link_setup_gnu_properties (info);
+
+ if (bfd_link_relocatable (info))
+ return pbfd;
+
+ /* If pbfd has any GNU_PROPERTY_RISCV_FEATURE_1_AND properties, update
+ and_prop accordingly. */
+ if (pbfd != NULL)
+ {
+ elf_property_list *p;
+ elf_property_list *plist = elf_properties (pbfd);
+
+ if ((p = _bfd_elf_find_property (plist, GNU_PROPERTY_RISCV_FEATURE_1_AND,
+ NULL))
+ != NULL)
+ and_prop = p->property.u.number
+ & (GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+ | GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS);
+ }
+
+ *and_prop_p = and_prop;
+ return pbfd;
+}
+
+/* Define elf_backend_parse_gnu_properties for RISC-V. */
+
+enum elf_property_kind
+_bfd_riscv_elf_parse_gnu_properties (bfd *abfd, unsigned int type,
+ bfd_byte *ptr, unsigned int datasz)
+{
+ elf_property *prop;
+
+ switch (type)
+ {
+ case GNU_PROPERTY_RISCV_FEATURE_1_AND:
+ if (datasz != 4)
+ {
+ _bfd_error_handler (_ (
+ "error: %pB: <corrupt RISC-V used size: 0x%x>"),
+ abfd, datasz);
+ return property_corrupt;
+ }
+ prop = _bfd_elf_get_property (abfd, type, datasz);
+ /* Combine properties of the same type. */
+ prop->u.number |= bfd_h_get_32 (abfd, ptr);
+ prop->pr_kind = property_number;
+ break;
+
+ default:
+ return property_ignored;
+ }
+
+ return property_number;
+}
+
+/* Merge RISC-V GNU property BPROP with APROP also accounting for PROP.
+ If APROP isn't NULL, merge it with BPROP and/or PROP. Vice-versa if BROP
+ isn't NULL. Return TRUE if there is any update to APROP or if BPROP should
+ be merge with ABFD. */
+
+bool
+_bfd_riscv_elf_merge_gnu_properties
+ (struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd ATTRIBUTE_UNUSED,
+ elf_property *aprop, elf_property *bprop, uint32_t and_prop)
+{
+ unsigned int orig_number;
+ bool updated = false;
+ unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type;
+
+ switch (pr_type)
+ {
+ case GNU_PROPERTY_RISCV_FEATURE_1_AND: {
+ if (aprop != NULL && bprop != NULL)
+ {
+ orig_number = aprop->u.number;
+ aprop->u.number = (orig_number & bprop->u.number) | and_prop;
+ updated = orig_number != aprop->u.number;
+ /* Remove the property if all feature bits are cleared. */
+ if (aprop->u.number == 0)
+ aprop->pr_kind = property_remove;
+ break;
+ }
+ /* If either is NULL, the AND would be 0 so, if there is
+ any PROP, asign it to the input that is not NULL. */
+ if (and_prop)
+ {
+ if (aprop != NULL)
+ {
+ orig_number = aprop->u.number;
+ aprop->u.number = and_prop;
+ updated = orig_number != aprop->u.number;
+ }
+ else if (bprop != NULL)
+ {
+ bprop->u.number = and_prop;
+ updated = true;
+ }
+ /* Shouldn't happen because we checked one of APROP or BPROP !=
+ * NULL. */
+ else
+ abort ();
+ }
+ /* No PROP and BPROP is NULL, so remove APROP. */
+ else if (!and_prop && bprop == NULL && aprop != NULL)
+ {
+ aprop->pr_kind = property_remove;
+ updated = true;
+ }
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ return updated;
+}