BFD: Exclude sections with no content from compress check.
[deliverable/binutils-gdb.git] / bfd / elfxx-riscv.c
index 658629c0c811bda9544071ba5d869345ba1cb779..b15fdee9c7139c95582bb78ebc044826d402c903 100644 (file)
@@ -1193,7 +1193,7 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
     {
       char subset[2] = {0, 0};
 
-      if (*p == 'x' || *p == 's')
+      if (*p == 'x' || *p == 's' || *p == 'z')
        break;
 
       if (*p == '_')
@@ -1237,28 +1237,56 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,
   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.
+   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;
 
   while (*p)
     {
@@ -1268,12 +1296,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);
@@ -1294,14 +1320,51 @@ riscv_parse_sv_or_non_std_ext (riscv_parse_subset_t *rps,
 
       *q = '\0';
 
+      /* 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;
+       }
+
       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 seperate with _",
-                             march, ext_type_str);
+         rps->error_handler ("-march=%s: %s must separate with _",
+                             march, config->prefix);
          return NULL;
        }
     }
@@ -1309,6 +1372,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[] =
+  {
+    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 +1464,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)
     {
@@ -1347,26 +1489,14 @@ 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");
+  /* Parse the different classes of extensions in the specified order.  */
 
-  if (p == NULL)
-    return FALSE;
+  for (i = 0; i < ARRAY_SIZE (parse_config); ++i) {
+    p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i]);
 
-  /* 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");
-
-  if (p == NULL)
-    return FALSE;
+    if (p == NULL)
+      return FALSE;
+  }
 
   if (*p != '\0')
     {
This page took 0.026891 seconds and 4 git commands to generate.