diff options
Diffstat (limited to 'bfd/elfxx-riscv.c')
-rw-r--r-- | bfd/elfxx-riscv.c | 320 |
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; +} |