X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-riscv.c;h=5dd36ab965a9e56fe778d3c408faa2ec289c1c2c;hb=ebe84f23d2f3c0cb145cc7b3acfb011a4c7df1c9;hp=66e343f4a5a87296d8e866582d3f9c0e170a9faf;hpb=07f1f3aa536add16b20f2792e1c325fb02b7da2d;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index 66e343f4a5..5dd36ab965 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -1025,9 +1025,8 @@ riscv_elf_add_sub_reloc (bfd *abfd, `minor_version`: Parsing result of minor version, set to 0 if version is not present in arch string, but set to `default_minor_version` if `major_version` using default_major_version. - `default_major_version`: Default major version. - `default_minor_version`: Default minor version. - `std_ext_p`: True if parsing std extension. */ + `std_ext_p`: True if parsing std extension. + `use_default_version`: Set it to True if we need the default version. */ static const char * riscv_parsing_subset_version (riscv_parse_subset_t *rps, @@ -1035,17 +1034,16 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps, const char *p, unsigned *major_version, unsigned *minor_version, - unsigned default_major_version, - unsigned default_minor_version, - bfd_boolean std_ext_p) + bfd_boolean std_ext_p, + bfd_boolean *use_default_version) { bfd_boolean major_p = TRUE; unsigned version = 0; - unsigned major = 0; - unsigned minor = 0; char np; - for (;*p; ++p) + *major_version = 0; + *minor_version = 0; + for (; *p; ++p) { if (*p == 'p') { @@ -1062,13 +1060,14 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps, } else { - rps->error_handler ("-march=%s: Expect number after `%dp'.", - march, version); + rps->error_handler + (_("-march=%s: Expect number after `%dp'."), + march, version); return NULL; } } - major = version; + *major_version = version; major_p = FALSE; version = 0; } @@ -1079,21 +1078,15 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps, } if (major_p) - major = version; + *major_version = version; else - minor = version; + *minor_version = version; - if (major == 0 && minor == 0) - { - /* We don't found any version string, use default version. */ - *major_version = default_major_version; - *minor_version = default_minor_version; - } - else - { - *major_version = major; - *minor_version = minor; - } + /* We can not find any version in string, need to parse default version. */ + if (use_default_version != NULL + && *major_version == 0 + && *minor_version == 0) + *use_default_version = TRUE; return p; } @@ -1118,82 +1111,118 @@ riscv_supported_std_ext (void) static const char * riscv_parse_std_ext (riscv_parse_subset_t *rps, - const char *march, const char *p) + const char *march, + const char *p) { const char *all_std_exts = riscv_supported_std_ext (); const char *std_exts = all_std_exts; - unsigned major_version = 0; unsigned minor_version = 0; char std_ext = '\0'; + bfd_boolean use_default_version = FALSE; /* First letter must start with i, e or g. */ switch (*p) { case 'i': - p++; - p = riscv_parsing_subset_version ( - rps, - march, - p, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */TRUE); - riscv_add_subset (rps->subset_list, "i", major_version, minor_version); + p = riscv_parsing_subset_version (rps, + march, + ++p, + &major_version, + &minor_version, + /* std_ext_p= */TRUE, + &use_default_version); + + /* Find the default version if needed. */ + if (use_default_version + && rps->get_default_version != NULL) + rps->get_default_version ("i", + &major_version, + &minor_version); + riscv_add_subset (rps->subset_list, "i", + major_version, minor_version); break; case 'e': - p++; - p = riscv_parsing_subset_version ( - rps, - march, - p, &major_version, &minor_version, - /* default_major_version= */ 1, - /* default_minor_version= */ 9, - /* std_ext_p= */TRUE); - - riscv_add_subset (rps->subset_list, "e", major_version, minor_version); - riscv_add_subset (rps->subset_list, "i", 2, 0); + p = riscv_parsing_subset_version (rps, + march, + ++p, + &major_version, + &minor_version, + /* std_ext_p= */TRUE, + &use_default_version); + + /* Find the default version if needed. */ + if (use_default_version + && rps->get_default_version != NULL) + rps->get_default_version ("e", + &major_version, + &minor_version); + riscv_add_subset (rps->subset_list, "e", + major_version, minor_version); + + /* i-ext must be enabled. */ + if (rps->get_default_version != NULL) + rps->get_default_version ("i", + &major_version, + &minor_version); + riscv_add_subset (rps->subset_list, "i", + major_version, minor_version); if (*rps->xlen > 32) { - rps->error_handler ("-march=%s: rv%de is not a valid base ISA", - march, *rps->xlen); + rps->error_handler + (_("-march=%s: rv%de is not a valid base ISA"), + march, *rps->xlen); return NULL; } - break; case 'g': - p++; - p = riscv_parsing_subset_version ( - rps, - march, - p, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */TRUE); - riscv_add_subset (rps->subset_list, "i", major_version, minor_version); + /* The g-ext shouldn't has the version, so we just + skip the setting if user set a version to it. */ + p = riscv_parsing_subset_version (rps, + march, + ++p, + &major_version, + &minor_version, + TRUE, + &use_default_version); + + /* i-ext must be enabled. */ + if (rps->get_default_version != NULL) + rps->get_default_version ("i", + &major_version, + &minor_version); + riscv_add_subset (rps->subset_list, "i", + major_version, minor_version); for ( ; *std_exts != 'q'; std_exts++) { const char subset[] = {*std_exts, '\0'}; - riscv_add_subset ( - rps->subset_list, subset, major_version, minor_version); + + if (rps->get_default_version != NULL) + rps->get_default_version (subset, + &major_version, + &minor_version); + riscv_add_subset (rps->subset_list, subset, + major_version, minor_version); } break; default: - rps->error_handler ( - "-march=%s: first ISA subset must be `e', `i' or `g'", march); + rps->error_handler + (_("-march=%s: first ISA subset must be `e', `i' or `g'"), march); return NULL; } - while (*p) + /* The riscv_parsing_subset_version may set `p` to NULL, so I think we should + skip parsing the string if `p` is NULL or value of `p` is `\0`. */ + while (p != NULL && *p != '\0') { char subset[2] = {0, 0}; - if (*p == 'x' || *p == 's') + if (*p == 'x' || *p == 's' || *p == 'z') break; if (*p == '_') @@ -1210,55 +1239,91 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps, if (std_ext != *std_exts) { if (strchr (all_std_exts, std_ext) == NULL) - rps->error_handler ( - "-march=%s: unsupported ISA subset `%c'", march, *p); + rps->error_handler + (_("-march=%s: unsupported ISA subset `%c'"), march, *p); else - rps->error_handler ( - "-march=%s: ISA string is not in canonical order. `%c'", - march, *p); + rps->error_handler + (_("-march=%s: ISA string is not in canonical order. `%c'"), + march, *p); return NULL; } std_exts++; - p++; - p = riscv_parsing_subset_version ( - rps, - march, - p, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */TRUE); - + use_default_version = FALSE; subset[0] = std_ext; - - riscv_add_subset (rps->subset_list, subset, major_version, minor_version); + p = riscv_parsing_subset_version (rps, + march, + ++p, + &major_version, + &minor_version, + TRUE, + &use_default_version); + + /* Find the default version if needed. */ + if (use_default_version + && rps->get_default_version != NULL) + rps->get_default_version (subset, + &major_version, + &minor_version); + riscv_add_subset (rps->subset_list, subset, + major_version, minor_version); } return p; } -/* Parsing function for non-standard and supervisor extensions. +/* Classify the argument 'arch' into one of riscv_isa_ext_class_t. */ - Return Value: - Points to the end of extensions. +riscv_isa_ext_class_t +riscv_get_prefix_class (const char *arch) +{ + switch (*arch) + { + case 's': return RV_ISA_CLASS_S; + case 'x': return RV_ISA_CLASS_X; + case 'z': return RV_ISA_CLASS_Z; + default: return RV_ISA_CLASS_UNKNOWN; + } +} - Arguments: - `rps`: Hooks and status for parsing subset. - `march`: Full arch string. - `p`: Curent parsing position. - `ext_type`: What kind of extensions, 'x', 's' or 'sx'. - `ext_type_str`: Full name for kind of extension. */ +/* Structure describing parameters to use when parsing a particular + riscv_isa_ext_class_t. One of these should be provided for each + possible class, except RV_ISA_CLASS_UNKNOWN. */ + +typedef struct riscv_parse_config +{ + /* Class of the extension. */ + riscv_isa_ext_class_t class; + + /* Lower-case prefix string for error printing + and internal parser usage, e.g. "z", "x". */ + const char *prefix; + + /* Predicate which is used for checking whether + this is a "known" extension. For 'x', + it always returns true (since they are by + definition non-standard and cannot be known. */ + bfd_boolean (*ext_valid_p) (const char *); +} riscv_parse_config_t; + +/* Parse a generic prefixed extension. + `rps`: Hooks and status for parsing subset. + `march`: The full architecture string as passed in by "-march=...". + `p`: Point from which to start parsing the -march string. + `config`: What class of extensions to parse, predicate funcs, + and strings to use in error reporting. */ static const char * -riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps, - const char *march, - const char *p, - const char *ext_type, - const char *ext_type_str) +riscv_parse_prefixed_ext (riscv_parse_subset_t *rps, + const char *march, + const char *p, + const riscv_parse_config_t *config) { unsigned major_version = 0; unsigned minor_version = 0; - size_t ext_type_len = strlen (ext_type); + const char *last_name; + riscv_isa_ext_class_t class; + bfd_boolean use_default_version; while (*p) { @@ -1268,12 +1333,10 @@ riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps, continue; } - if (strncmp (p, ext_type, ext_type_len) != 0) - break; - - /* It's non-standard supervisor extension if it prefix with sx. */ - if ((ext_type[0] == 's') && (ext_type_len == 1) - && (*(p + 1) == 'x')) + /* Assert that the current extension specifier matches our parsing + class. */ + class = riscv_get_prefix_class (p); + if (class != config->class) break; char *subset = xstrdup (p); @@ -1283,25 +1346,67 @@ riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps, while (*++q != '\0' && *q != '_' && !ISDIGIT (*q)) ; + use_default_version = FALSE; end_of_version = - riscv_parsing_subset_version ( - rps, - march, - q, &major_version, &minor_version, - /* default_major_version= */ 2, - /* default_minor_version= */ 0, - /* std_ext_p= */FALSE); - + riscv_parsing_subset_version (rps, march, q, &major_version, + &minor_version, FALSE, + &use_default_version); *q = '\0'; - riscv_add_subset (rps->subset_list, subset, major_version, minor_version); + /* Check that the name is valid. + For 'x', anything goes but it cannot simply be 'x'. + For 's', it must be known from a list and cannot simply be 's'. + For 'z', it must be known from a list and cannot simply be 'z'. */ + + /* Check that the extension name is well-formed. */ + if (!config->ext_valid_p (subset)) + { + rps->error_handler + (_("-march=%s: Invalid or unknown %s ISA extension: '%s'"), + march, config->prefix, subset); + free (subset); + return NULL; + } + + /* Check that the last item is not the same as this. */ + last_name = rps->subset_list->tail->name; + if (!strcasecmp (last_name, subset)) + { + rps->error_handler + (_("-march=%s: Duplicate %s ISA extension: \'%s\'"), + march, config->prefix, subset); + free (subset); + return NULL; + } + + /* Check that we are in alphabetical order within the subset. */ + if (!strncasecmp (last_name, config->prefix, 1) + && strcasecmp (last_name, subset) > 0) + { + rps->error_handler + (_("\ +-march=%s: %s ISA extension not in alphabetical order: \'%s\' must come before \'%s\'."), + march, config->prefix, subset, last_name); + free (subset); + return NULL; + } + + /* Find the default version if needed. */ + if (use_default_version + && rps->get_default_version != NULL) + rps->get_default_version (subset, + &major_version, + &minor_version); + riscv_add_subset (rps->subset_list, subset, + major_version, minor_version); + free (subset); p += end_of_version - subset; if (*p != '\0' && *p != '_') { - rps->error_handler ("-march=%s: %s must separate with _", - march, ext_type_str); + rps->error_handler (_("-march=%s: %s must separate with _"), + march, config->prefix); return NULL; } } @@ -1309,6 +1414,84 @@ riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps, return p; } +/* List of Z-class extensions that binutils should know about. + Whether or not a particular entry is in this list will + dictate if gas/ld will accept its presence in the -march + string. + + Example: To add an extension called "Zbb" (bitmanip base extension), + add "zbb" string to the list (all lowercase). + + Keep this list alphabetically ordered. */ + +static const char * const riscv_std_z_ext_strtab[] = + { + "zicsr", NULL + }; + +/* Same as `riscv_std_z_ext_strtab', but for S-class extensions. */ + +static const char * const riscv_std_s_ext_strtab[] = + { + NULL + }; + +/* For the extension EXT, search through the list of known extensions + KNOWN_EXTS for a match, and return TRUE if found. */ + +static bfd_boolean +riscv_multi_letter_ext_valid_p (const char *ext, + const char *const *known_exts) +{ + size_t i; + + for (i = 0; known_exts[i]; ++i) + if (!strcmp (ext, known_exts[i])) + return TRUE; + + return FALSE; +} + +/* Predicator function for x-prefixed extensions. + Anything goes, except the literal 'x'. */ + +static bfd_boolean +riscv_ext_x_valid_p (const char *arg) +{ + if (!strcasecmp (arg, "x")) + return FALSE; + + return TRUE; +} + +/* Predicator functions for z-prefixed extensions. + Only known z-extensions are permitted. */ + +static bfd_boolean +riscv_ext_z_valid_p (const char *arg) +{ + return riscv_multi_letter_ext_valid_p (arg, riscv_std_z_ext_strtab); +} + +/* Predicator function for 's' prefixed extensions. + Must be either literal 's', or a known s-prefixed extension. */ + +static bfd_boolean +riscv_ext_s_valid_p (const char *arg) +{ + return riscv_multi_letter_ext_valid_p (arg, riscv_std_s_ext_strtab); +} + +/* Parsing order that is specified by the ISA manual. */ + +static const riscv_parse_config_t parse_config[] = +{ + {RV_ISA_CLASS_S, "s", riscv_ext_s_valid_p}, + {RV_ISA_CLASS_Z, "z", riscv_ext_z_valid_p}, + {RV_ISA_CLASS_X, "x", riscv_ext_x_valid_p}, + {RV_ISA_CLASS_UNKNOWN, NULL, NULL} +}; + /* Function for parsing arch string. Return Value: @@ -1323,6 +1506,7 @@ riscv_parse_subset (riscv_parse_subset_t *rps, const char *arch) { const char *p = arch; + size_t i; if (strncmp (p, "rv32", 4) == 0) { @@ -1336,8 +1520,9 @@ riscv_parse_subset (riscv_parse_subset_t *rps, } else { - rps->error_handler ("-march=%s: ISA string must begin with rv32 or rv64", - arch); + rps->error_handler + (_("-march=%s: ISA string must begin with rv32 or rv64"), + arch); return FALSE; } @@ -1347,30 +1532,17 @@ riscv_parse_subset (riscv_parse_subset_t *rps, if (p == NULL) return FALSE; - /* Parsing non-standard extension. */ - p = riscv_parse_sv_or_non_std_ext ( - rps, arch, p, "x", "non-standard extension"); - - if (p == NULL) - return FALSE; - - /* Parsing supervisor extension. */ - p = riscv_parse_sv_or_non_std_ext ( - rps, arch, p, "s", "supervisor extension"); - - if (p == NULL) - return FALSE; - - /* Parsing non-standard supervisor extension. */ - p = riscv_parse_sv_or_non_std_ext ( - rps, arch, p, "sx", "non-standard supervisor extension"); + /* Parse the different classes of extensions in the specified order. */ + for (i = 0; i < ARRAY_SIZE (parse_config); ++i) { + p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i]); - if (p == NULL) - return FALSE; + if (p == NULL) + return FALSE; + } if (*p != '\0') { - rps->error_handler ("-march=%s: unexpected ISA string at end: %s", + rps->error_handler (_("-march=%s: unexpected ISA string at end: %s"), arch, p); return FALSE; } @@ -1378,31 +1550,35 @@ riscv_parse_subset (riscv_parse_subset_t *rps, if (riscv_lookup_subset (rps->subset_list, "e") && riscv_lookup_subset (rps->subset_list, "f")) { - rps->error_handler ("-march=%s: rv32e does not support the `f' extension", - arch); + rps->error_handler + (_("-march=%s: rv32e does not support the `f' extension"), + arch); return FALSE; } if (riscv_lookup_subset (rps->subset_list, "d") && !riscv_lookup_subset (rps->subset_list, "f")) { - rps->error_handler ("-march=%s: `d' extension requires `f' extension", - arch); + rps->error_handler + (_("-march=%s: `d' extension requires `f' extension"), + arch); return FALSE; } if (riscv_lookup_subset (rps->subset_list, "q") && !riscv_lookup_subset (rps->subset_list, "d")) { - rps->error_handler ("-march=%s: `q' extension requires `d' extension", - arch); + rps->error_handler + (_("-march=%s: `q' extension requires `d' extension"), + arch); return FALSE; } if (riscv_lookup_subset (rps->subset_list, "q") && *rps->xlen < 64) { - rps->error_handler ("-march=%s: rv32 does not support the `q' extension", - arch); + rps->error_handler + (_("-march=%s: rv32 does not support the `q' extension"), + arch); return FALSE; } return TRUE; @@ -1413,7 +1589,8 @@ riscv_parse_subset (riscv_parse_subset_t *rps, void riscv_add_subset (riscv_subset_list_t *subset_list, const char *subset, - int major, int minor) + int major, + int minor) { riscv_subset_t *s = xmalloc (sizeof *s); @@ -1437,10 +1614,10 @@ riscv_subset_t * riscv_lookup_subset (const riscv_subset_list_t *subset_list, const char *subset) { - return riscv_lookup_subset_version ( - subset_list, subset, - RISCV_DONT_CARE_VERSION, - RISCV_DONT_CARE_VERSION); + return riscv_lookup_subset_version + (subset_list, subset, + RISCV_DONT_CARE_VERSION, + RISCV_DONT_CARE_VERSION); } /* Find subset in list with version checking, return NULL if not found. */ @@ -1487,7 +1664,7 @@ riscv_release_subset_list (riscv_subset_list_t *subset_list) /* Return the number of digits for the input. */ -static size_t +size_t riscv_estimate_digit (unsigned num) { size_t digit = 0;