+/* Parse the .insn directive. */
+
+static void
+s_riscv_insn (int x ATTRIBUTE_UNUSED)
+{
+ char *str = input_line_pointer;
+ struct riscv_cl_insn insn;
+ expressionS imm_expr;
+ bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
+ char save_c;
+
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+
+ save_c = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ const char *error = riscv_ip (str, &insn, &imm_expr,
+ &imm_reloc, insn_type_hash);
+
+ if (error)
+ {
+ as_bad ("%s `%s'", error, str);
+ }
+ else
+ {
+ gas_assert (insn.insn_mo->pinfo != INSN_MACRO);
+ append_insn (&insn, &imm_expr, imm_reloc);
+ }
+
+ *input_line_pointer = save_c;
+ demand_empty_rest_of_line ();
+}
+
+/* Update arch and priv attributes. If we don't set the corresponding ELF
+ attributes, then try to output the default ones. */
+
+static void
+riscv_write_out_attrs (void)
+{
+ const char *arch_str, *priv_str, *p;
+ /* versions[0] is major, versions[1] is minor,
+ and versions[3] is revision. */
+ unsigned versions[3] = {0}, number = 0;
+ unsigned int i;
+
+ /* Re-write arch attribute to normalize the arch string. */
+ arch_str = riscv_arch_str (xlen, &riscv_subsets);
+ bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str);
+ xfree ((void *)arch_str);
+
+ /* For the file without any instruction, we don't set the default_priv_spec
+ according to the priv attributes since the md_assemble isn't called.
+ Call riscv_set_default_priv_spec here for the above case, although
+ it seems strange. */
+ if (!start_assemble
+ && !riscv_set_default_priv_spec (NULL))
+ return;
+
+ /* If we already have set elf priv attributes, then no need to do anything,
+ assembler will generate them according to what you set. Otherwise, don't
+ generate or update them when no CSR and priv instructions are used.
+ Generate the priv attributes according to default_priv_spec, which can be
+ set by -mpriv-spec and --with-priv-spec, and be updated by the original
+ priv attribute sets. */
+ if (!explicit_priv_attr)
+ return;
+
+ /* Re-write priv attributes by default_priv_spec. */
+ priv_str = riscv_get_priv_spec_name (default_priv_spec);
+ p = priv_str;
+ for (i = 0; *p; ++p)
+ {
+ if (*p == '.' && i < 3)
+ {
+ versions[i++] = number;
+ number = 0;
+ }
+ else if (ISDIGIT (*p))
+ number = (number * 10) + (*p - '0');
+ else
+ {
+ as_bad (_("internal: bad RISC-V priv spec string (%s)"), priv_str);
+ return;
+ }
+ }
+ versions[i] = number;
+
+ /* Set the priv attributes. */
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec, versions[0]);
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec_minor, versions[1]);
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec_revision, versions[2]);
+}
+
+/* Add the default contents for the .riscv.attributes section. If any
+ ELF attribute or -march-attr options is set, call riscv_write_out_attrs
+ to update the arch and priv attributes. */
+
+static void
+riscv_set_public_attributes (void)
+{
+ if (riscv_opts.arch_attr || explicit_attr)
+ riscv_write_out_attrs ();
+}
+
+/* Called after all assembly has been done. */
+
+void
+riscv_md_end (void)
+{
+ riscv_set_public_attributes ();
+}
+
+/* Given a symbolic attribute NAME, return the proper integer value.
+ Returns -1 if the attribute is not known. */
+
+int
+riscv_convert_symbolic_attribute (const char *name)
+{
+ static const struct
+ {
+ const char * name;
+ const int tag;
+ }
+ attribute_table[] =
+ {
+ /* When you modify this table you should
+ also modify the list in doc/c-riscv.texi. */
+#define T(tag) {#tag, Tag_RISCV_##tag}, {"Tag_RISCV_" #tag, Tag_RISCV_##tag}
+ T(arch),
+ T(priv_spec),
+ T(priv_spec_minor),
+ T(priv_spec_revision),
+ T(unaligned_access),
+ T(stack_align),
+#undef T
+ };
+
+ unsigned int i;
+
+ if (name == NULL)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
+ if (strcmp (name, attribute_table[i].name) == 0)
+ return attribute_table[i].tag;
+
+ return -1;
+}
+
+/* Parse a .attribute directive. */
+
+static void
+s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+ int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
+ unsigned old_xlen;
+ obj_attribute *attr;
+
+ explicit_attr = TRUE;
+ switch (tag)
+ {
+ case Tag_RISCV_arch:
+ old_xlen = xlen;
+ attr = elf_known_obj_attributes_proc (stdoutput);
+ if (!start_assemble)
+ riscv_set_arch (attr[Tag_RISCV_arch].s);
+ else
+ as_fatal (_(".attribute arch must set before any instructions"));
+
+ if (old_xlen != xlen)
+ {
+ /* We must re-init bfd again if xlen is changed. */
+ unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32;
+ bfd_find_target (riscv_target_format (), stdoutput);
+
+ if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
+ as_warn (_("Could not set architecture and machine"));
+ }
+ break;
+
+ case Tag_RISCV_priv_spec:
+ case Tag_RISCV_priv_spec_minor:
+ case Tag_RISCV_priv_spec_revision:
+ if (start_assemble)
+ as_fatal (_(".attribute priv spec must set before any instructions"));
+ break;
+
+ default:
+ break;
+ }
+}
+