From e484c345d1b60339c724569751dc3558e71d6f60 Mon Sep 17 00:00:00 2001
From: Kito Cheng <kito.cheng@gmail.com>
Date: Tue, 4 Dec 2018 14:28:13 +0800
Subject: [PATCH] RISC-V: Support ELF attribute for gas and readelf

---
 bfd/ChangeLog                               |  16 ++++
 bfd/elfnn-riscv.c                           |  17 ++++
 bfd/elfxx-riscv.c                           |  89 +++++++++++++++++++
 bfd/elfxx-riscv.h                           |   3 +
 binutils/ChangeLog                          |  12 +++
 binutils/readelf.c                          | 100 ++++++++++++++++++++++
 binutils/testsuite/binutils-all/strip-3.d   |   2 +-
 gas/ChangeLog                               |  47 ++++++++++
 gas/config.in                               |   4 +
 gas/config/tc-riscv.c                       | 127 ++++++++++++++++++++++++++++
 gas/config/tc-riscv.h                       |   6 ++
 gas/configure                               |  34 +++++++-
 gas/configure.ac                            |  25 ++++++
 gas/doc/c-riscv.texi                        |  57 +++++++++++++
 gas/testsuite/gas/elf/elf.exp               |  17 +++-
 gas/testsuite/gas/elf/section2.e-riscv      |   9 ++
 gas/testsuite/gas/riscv/attribute-01.d      |   6 ++
 gas/testsuite/gas/riscv/attribute-02.d      |   6 ++
 gas/testsuite/gas/riscv/attribute-03.d      |   6 ++
 gas/testsuite/gas/riscv/attribute-04.d      |   6 ++
 gas/testsuite/gas/riscv/attribute-04.s      |   1 +
 gas/testsuite/gas/riscv/attribute-05.d      |  11 +++
 gas/testsuite/gas/riscv/attribute-05.s      |   6 ++
 gas/testsuite/gas/riscv/attribute-06.d      |   6 ++
 gas/testsuite/gas/riscv/attribute-06.s      |   1 +
 gas/testsuite/gas/riscv/attribute-07.d      |   6 ++
 gas/testsuite/gas/riscv/attribute-07.s      |   1 +
 gas/testsuite/gas/riscv/attribute-08.d      |   6 ++
 gas/testsuite/gas/riscv/attribute-08.s      |   1 +
 gas/testsuite/gas/riscv/attribute-unknown.d |   8 ++
 gas/testsuite/gas/riscv/attribute-unknown.s |   2 +
 gas/testsuite/gas/riscv/empty.l             |   1 +
 include/ChangeLog                           |  10 +++
 include/elf/riscv.h                         |  16 ++++
 34 files changed, 658 insertions(+), 7 deletions(-)
 create mode 100644 gas/testsuite/gas/elf/section2.e-riscv
 create mode 100644 gas/testsuite/gas/riscv/attribute-01.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-02.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-03.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-04.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-04.s
 create mode 100644 gas/testsuite/gas/riscv/attribute-05.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-05.s
 create mode 100644 gas/testsuite/gas/riscv/attribute-06.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-06.s
 create mode 100644 gas/testsuite/gas/riscv/attribute-07.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-07.s
 create mode 100644 gas/testsuite/gas/riscv/attribute-08.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-08.s
 create mode 100644 gas/testsuite/gas/riscv/attribute-unknown.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-unknown.s
 create mode 100644 gas/testsuite/gas/riscv/empty.l

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 7a75517..c077adf 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,19 @@
+2019-01-16  Kito Cheng  <kito@andestech.com>
+	    Nelson Chu  <nelson@andestech.com>
+
+	* elfnn-riscv.c (riscv_elf_obj_attrs_arg_type): New.
+	(elf_backend_obj_attrs_vendor): Define.
+	(elf_backend_obj_attrs_section_type): Likewise.
+	(elf_backend_obj_attrs_section): Likewise.
+	(elf_backend_obj_attrs_arg_type): Define as
+	riscv_elf_obj_attrs_arg_type.
+	* elfxx-riscv.c (riscv_estimate_digit): New.
+	(riscv_estimate_arch_strlen1): Likewise.
+	(riscv_estimate_arch_strlen): Likewise.
+	(riscv_arch_str1): Likewise.
+	(riscv_arch_str): Likewise.
+	* elfxx-riscv.h (riscv_arch_str): Declare.
+
 2019-01-14  Maamoun Tarsha  <maamountk@hotmail.com>
 
 	PR 20113
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 78ab051..5430f61 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -3654,6 +3654,14 @@ riscv_elf_object_p (bfd *abfd)
   return TRUE;
 }
 
+/* Determine whether an object attribute tag takes an integer, a
+   string or both.  */
+
+static int
+riscv_elf_obj_attrs_arg_type (int tag)
+{
+  return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL;
+}
 
 #define TARGET_LITTLE_SYM		riscv_elfNN_vec
 #define TARGET_LITTLE_NAME		"elfNN-littleriscv"
@@ -3696,4 +3704,13 @@ riscv_elf_object_p (bfd *abfd)
 #define elf_backend_rela_normal		1
 #define elf_backend_default_execstack	0
 
+#undef  elf_backend_obj_attrs_vendor
+#define elf_backend_obj_attrs_vendor            "riscv"
+#undef  elf_backend_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type          riscv_elf_obj_attrs_arg_type
+#undef  elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type      SHT_RISCV_ATTRIBUTES
+#undef  elf_backend_obj_attrs_section
+#define elf_backend_obj_attrs_section           ".riscv.attributes"
+
 #include "elfNN-target.h"
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 535ba7b..29592db 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1484,3 +1484,92 @@ riscv_release_subset_list (riscv_subset_list_t *subset_list)
 
   subset_list->tail = NULL;
 }
+
+/* Return the number of digits for the input.  */
+
+static size_t
+riscv_estimate_digit (unsigned num)
+{
+  size_t digit = 0;
+  if (num == 0)
+    return 1;
+
+  for (digit = 0; num ; num /= 10)
+    digit++;
+
+  return digit;
+}
+
+/* Auxiliary function to estimate string length of subset list.  */
+
+static size_t
+riscv_estimate_arch_strlen1 (const riscv_subset_t *subset)
+{
+  if (subset == NULL)
+    return 6; /* For rv32/rv64/rv128 and string terminator.  */
+
+  return riscv_estimate_arch_strlen1 (subset->next)
+	 + strlen (subset->name)
+	 + riscv_estimate_digit (subset->major_version)
+	 + 1 /* For version seperator: 'p'.  */
+	 + riscv_estimate_digit (subset->minor_version)
+	 + 1 /* For underscore.  */;
+}
+
+/* Estimate the string length of this subset list.  */
+
+static size_t
+riscv_estimate_arch_strlen (const riscv_subset_list_t *subset_list)
+{
+  return riscv_estimate_arch_strlen1 (subset_list->head);
+}
+
+/* Auxiliary function to convert subset info to string.  */
+
+static void
+riscv_arch_str1 (riscv_subset_t *subset,
+		 char *attr_str, char *buf, size_t bufsz)
+{
+  const char *underline = "_";
+
+  if (subset == NULL)
+    return;
+
+  /* No underline between rvXX and i/e.   */
+  if ((strcasecmp (subset->name, "i") == 0)
+      || (strcasecmp (subset->name, "e") == 0))
+    underline = "";
+
+  snprintf (buf, bufsz, "%s%s%dp%d",
+	    underline,
+            subset->name,
+            subset->major_version,
+            subset->minor_version);
+
+  strncat (attr_str, buf, bufsz);
+
+  /* Skip 'i' extension after 'e'.  */
+  if ((strcasecmp (subset->name, "e") == 0)
+      && subset->next
+      && (strcasecmp (subset->next->name, "i") == 0))
+    riscv_arch_str1 (subset->next->next, attr_str, buf, bufsz);
+  else
+    riscv_arch_str1 (subset->next, attr_str, buf, bufsz);
+}
+
+/* Convert subset info to string with explicit version info.  */
+
+char *
+riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset)
+{
+  size_t arch_str_len = riscv_estimate_arch_strlen (subset);
+  char *attr_str = xmalloc (arch_str_len);
+  char *buf = xmalloc (arch_str_len);
+
+  snprintf (attr_str, arch_str_len, "rv%u", xlen);
+
+  riscv_arch_str1 (subset->head, attr_str, buf, arch_str_len);
+  free (buf);
+
+  return attr_str;
+}
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 03b4484..19f7bd2 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -83,3 +83,6 @@ riscv_supported_std_ext (void);
 
 extern void
 riscv_release_subset_list (riscv_subset_list_t *);
+
+extern char *
+riscv_arch_str (unsigned, const riscv_subset_list_t *);
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index de167f0..bec3ddc 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,15 @@
+2019-01-16  Kito Cheng  <kito@andestech.com>
+	    Nelson Chu  <nelson@andestech.com>
+
+	* readelf.c (get_riscv_section_type_name): New function.
+	(get_section_type_name): Add handler for RISC-V.
+	(riscv_attr_tag_t): Declare.
+	(riscv_attr_tag): New.
+	(display_riscv_attribute): New function.
+	(process_attributes): Add handler for RISC-V.
+	* testsuite/binutils-all/strip-3.d: Remove .riscv.attribute
+	section.
+
 2019-01-10  Nick Clifton  <nickc@redhat.com>
 
 	PR 23963
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 56b80cc..6920db4 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -4205,6 +4205,16 @@ get_v850_section_type_name (unsigned int sh_type)
 }
 
 static const char *
+get_riscv_section_type_name (unsigned int sh_type)
+{
+  switch (sh_type)
+    {
+    case SHT_RISCV_ATTRIBUTES:  return "RISCV_ATTRIBUTES";
+    default: return NULL;
+    }
+}
+
+static const char *
 get_section_type_name (Filedata * filedata, unsigned int sh_type)
 {
   static char buff[32];
@@ -4284,6 +4294,9 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
 	    case EM_CYGNUS_V850:
 	      result = get_v850_section_type_name (sh_type);
 	      break;
+	    case EM_RISCV:
+	      result = get_riscv_section_type_name (sh_type);
+	      break;
 	    default:
 	      result = NULL;
 	      break;
@@ -15362,6 +15375,88 @@ display_msp430x_attribute (unsigned char * p,
   return p;
 }
 
+struct riscv_attr_tag_t {
+  const char *name;
+  int tag;
+};
+
+static struct riscv_attr_tag_t riscv_attr_tag[] =
+{
+#define T(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
+};
+
+static unsigned char *
+display_riscv_attribute (unsigned char *p,
+			 const unsigned char * const end)
+{
+  unsigned int len;
+  int val;
+  int tag;
+  struct riscv_attr_tag_t *attr = NULL;
+  unsigned i;
+
+  tag = read_uleb128 (p, &len, end);
+  p += len;
+
+  /* Find the name of attribute. */
+  for (i = 0; i < ARRAY_SIZE (riscv_attr_tag); i++)
+    {
+      if (riscv_attr_tag[i].tag == tag)
+	{
+	  attr = &riscv_attr_tag[i];
+	  break;
+	}
+    }
+
+  if (attr)
+    printf ("  %s: ", attr->name);
+  else
+    return display_tag_value (tag, p, end);
+
+  switch (tag)
+    {
+    case Tag_RISCV_priv_spec:
+    case Tag_RISCV_priv_spec_minor:
+    case Tag_RISCV_priv_spec_revision:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf (_("%d\n"), val);
+      break;
+    case Tag_RISCV_unaligned_access:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      switch (val)
+	{
+	case 0:
+	  printf (_("No unaligned access\n"));
+	  break;
+	case 1:
+	  printf (_("Unaligned access\n"));
+	  break;
+	}
+      break;
+    case Tag_RISCV_stack_align:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf (_("%d-bytes\n"), val);
+      break;
+    case Tag_RISCV_arch:
+      p =  display_tag_value (-1, p, end);
+      break;
+    default:
+      return display_tag_value (tag, p, end);
+    }
+
+  return p;
+}
+
 static bfd_boolean
 process_attributes (Filedata * filedata,
 		    const char * public_name,
@@ -18896,6 +18991,11 @@ process_arch_specific (Filedata * filedata)
 				display_msp430x_attribute,
 				display_generic_attribute);
 
+    case EM_RISCV:
+     return process_attributes (filedata, "riscv", SHT_RISCV_ATTRIBUTES,
+				display_riscv_attribute,
+				display_generic_attribute);
+
     case EM_NDS32:
       return process_nds32_specific (filedata);
 
diff --git a/binutils/testsuite/binutils-all/strip-3.d b/binutils/testsuite/binutils-all/strip-3.d
index 8a375d8..2a886d2 100644
--- a/binutils/testsuite/binutils-all/strip-3.d
+++ b/binutils/testsuite/binutils-all/strip-3.d
@@ -1,6 +1,6 @@
 #PROG: strip
 #source: empty.s
-#strip: -R .text -R .data -R .bss -R .ARM.attributes -R .reginfo -R .gnu.attributes -R .MIPS.abiflags -R .pdr -R .xtensa.info -R .ARC.attributes -R .note.gnu.property
+#strip: -R .text -R .data -R .bss -R .ARM.attributes -R .reginfo -R .gnu.attributes -R .MIPS.abiflags -R .pdr -R .xtensa.info -R .ARC.attributes -R .note.gnu.property -R .riscv.attributes
 #readelf: -S --wide
 #name: strip empty file
 #target: *-*-linux* *-*-gnu* arm*-*-uclinuxfdpiceabi
diff --git a/gas/ChangeLog b/gas/ChangeLog
index abc0923..2048bcf 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,50 @@
+2019-01-16  Kito Cheng  <kito@andestech.com>
+	    Nelson Chu  <nelson@andestech.com>
+
+	* config/tc-riscv.c (DEFAULT_RISCV_ATTR): Define to 0 if not defined.
+	(riscv_set_options): Add `arch_attr` field.
+	(riscv_opts): Set default value for arch_attr.
+	(riscv_write_out_arch_attr): New.
+	(riscv_set_public_attributes): Likewise.
+	(riscv_md_end): Likewise.
+	(riscv_convert_symbolic_attribute): Likewise.
+	(s_riscv_attribute): Likewise.
+	(explicit_arch_attr): Likewise.
+	(riscv_pseudo_table): Add .attribute to the table.
+	(options): Add OPTION_ARCH_ATTR and OPTION_NO_ARCH_ATTR
+	enumeration constants.
+	(md_longopts): Add `march-attr' and `mno-arch-attr' options.
+	(md_parse_option): Handle the new options.
+	(md_show_usage): Document the `march-attr' option.
+	* config/tc-riscv.h (md_end): Define as riscv_md_end
+	(riscv_md_end): Declare.
+	(CONVERT_SYMBOLIC_ATTRIBUTE): Define as
+	riscv_convert_symbolic_attribute.
+	(riscv_convert_symbolic_attribute): Declare.
+	(start_assemble): Declare.
+	* testsuite/gas/elf/elf.exp: Adjust test case for section2.e.
+	* testsuite/gas/elf/section2.e-riscv: New.
+	* testsuite/gas/riscv/attribute-01.d: New test
+	* testsuite/gas/riscv/attribute-02.d: Likewise.
+	* testsuite/gas/riscv/attribute-03.d: Likewise.
+	* testsuite/gas/riscv/attribute-04.d: Likewise.
+	* testsuite/gas/riscv/attribute-04.s: Likewise.
+	* testsuite/gas/riscv/attribute-05.d: Likewise.
+	* testsuite/gas/riscv/attribute-05.s: Likewise.
+	* testsuite/gas/riscv/attribute-06.d: Likewise.
+	* testsuite/gas/riscv/attribute-06.s: Likewise.
+	* testsuite/gas/riscv/attribute-07.d: Likewise.
+	* testsuite/gas/riscv/attribute-07.s: Likewise.
+	* testsuite/gas/riscv/attribute-08.d: Likewise.
+	* testsuite/gas/riscv/attribute-08.s: Likewise.
+	* testsuite/gas/riscv/attribute-unknown.d: Likewise.
+	* testsuite/gas/riscv/attribute-unknown.s: Likewise.
+	* testsuite/gas/riscv/empty.l: Likewise.
+	* doc/c-riscv.texi (.attribute): Add documentation.
+	* configure.ac (--enable-default-riscv-attribute): New options.
+	* configure: Re-generate.
+	* config.in: Re-generate.
+
 2019-01-14  Srinath Parvathaneni  <srinath.parvathaneni@arm.com>
 
 	* config/tc-arm.c (arm_ext_v6k_v6t2): Define.
diff --git a/gas/config.in b/gas/config.in
index 9c15a07..dac7579 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -50,6 +50,10 @@
 /* Define to 1 if you want to generate x86 relax relocations by default. */
 #undef DEFAULT_GENERATE_X86_RELAX_RELOCATIONS
 
+/* Define to 1 if you want to generate RISC-V used arch attribute by default.
+   */
+#undef DEFAULT_RISCV_ATTR
+
 /* Define to 1 if you want to generate GNU x86 used ISA and feature properties
    by default. */
 #undef DEFAULT_X86_USED_NOTE
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 31b0b1b..9931615 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -59,6 +59,10 @@ struct riscv_cl_insn
 #define DEFAULT_ARCH "riscv64"
 #endif
 
+#ifndef DEFAULT_RISCV_ATTR
+#define DEFAULT_RISCV_ATTR 0
+#endif
+
 static const char default_arch[] = DEFAULT_ARCH;
 
 static unsigned xlen = 0; /* width of an x-register */
@@ -78,6 +82,7 @@ struct riscv_set_options
   int rvc; /* Generate RVC code.  */
   int rve; /* Generate RVE code.  */
   int relax; /* Emit relocs the linker is allowed to relax.  */
+  int arch_attr; /* Emit arch attribute.  */
 };
 
 static struct riscv_set_options riscv_opts =
@@ -86,6 +91,7 @@ static struct riscv_set_options riscv_opts =
   0,	/* rvc */
   0,	/* rve */
   1,	/* relax */
+  DEFAULT_RISCV_ATTR, /* arch_attr */
 };
 
 static void
@@ -170,6 +176,12 @@ const char EXP_CHARS[] = "eE";
 /* or    0d1.2345e12 */
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
+/* Indicate we are already assemble any instructions or not.  */
+static bfd_boolean start_assemble = FALSE;
+
+/* Indicate arch attribute is explictly set.  */
+static bfd_boolean explicit_arch_attr = FALSE;
+
 /* Macros for encoding relaxation state for RVC branches and far jumps.  */
 #define RELAX_BRANCH_ENCODE(uncond, rvc, length)	\
   ((relax_substateT) 					\
@@ -2097,6 +2109,8 @@ md_assemble (char *str)
 
   const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
 
+  start_assemble = TRUE;
+
   if (error)
     {
       as_bad ("%s `%s'", error, str);
@@ -2131,6 +2145,8 @@ enum options
   OPTION_MABI,
   OPTION_RELAX,
   OPTION_NO_RELAX,
+  OPTION_ARCH_ATTR,
+  OPTION_NO_ARCH_ATTR,
   OPTION_END_OF_ENUM
 };
 
@@ -2143,6 +2159,8 @@ struct option md_longopts[] =
   {"mabi", required_argument, NULL, OPTION_MABI},
   {"mrelax", no_argument, NULL, OPTION_RELAX},
   {"mno-relax", no_argument, NULL, OPTION_NO_RELAX},
+  {"march-attr", no_argument, NULL, OPTION_ARCH_ATTR},
+  {"mno-arch-attr", no_argument, NULL, OPTION_NO_ARCH_ATTR},
 
   {NULL, no_argument, NULL, 0}
 };
@@ -2213,6 +2231,14 @@ md_parse_option (int c, const char *arg)
       riscv_opts.relax = FALSE;
       break;
 
+    case OPTION_ARCH_ATTR:
+      riscv_opts.arch_attr = TRUE;
+      break;
+
+    case OPTION_NO_ARCH_ATTR:
+      riscv_opts.arch_attr = FALSE;
+      break;
+
     default:
       return 0;
     }
@@ -2948,6 +2974,8 @@ RISC-V options:\n\
   -mabi=ABI      set the RISC-V ABI\n\
   -mrelax        enable relax (default)\n\
   -mno-relax     disable relax\n\
+  -march-attr    generate RISC-V arch attribute\n\
+  -mno-arch-attr don't generate RISC-V arch attribute\n\
 "));
 }
 
@@ -3031,6 +3059,104 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Update arch attributes.  */
+
+static void
+riscv_write_out_arch_attr (void)
+{
+  const char *arch_str = riscv_arch_str (xlen, &riscv_subsets);
+
+  bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str);
+
+  xfree ((void *)arch_str);
+}
+
+/* Add the default contents for the .riscv.attributes section.  */
+
+static void
+riscv_set_public_attributes (void)
+{
+  if (riscv_opts.arch_attr || explicit_arch_attr)
+    /* Re-write arch attribute to normalize the arch string.  */
+    riscv_write_out_arch_attr ();
+}
+
+/* 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);
+
+  if (tag == Tag_RISCV_arch)
+    {
+      unsigned old_xlen = xlen;
+
+      explicit_arch_attr = TRUE;
+      obj_attribute *attr;
+      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"));
+	}
+    }
+}
+
 /* Pseudo-op table.  */
 
 static const pseudo_typeS riscv_pseudo_table[] =
@@ -3046,6 +3172,7 @@ static const pseudo_typeS riscv_pseudo_table[] =
   {"uleb128", s_riscv_leb128, 0},
   {"sleb128", s_riscv_leb128, 1},
   {"insn", s_riscv_insn, 0},
+  {"attribute", s_riscv_attribute, 0},
 
   { NULL, NULL, 0 },
 };
diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h
index 7548bff..e1dd508 100644
--- a/gas/config/tc-riscv.h
+++ b/gas/config/tc-riscv.h
@@ -120,4 +120,10 @@ extern void riscv_elf_final_processing (void);
 /* Adjust debug_line after relaxation.  */
 #define DWARF2_USE_FIXED_ADVANCE_PC 1
 
+#define md_end riscv_md_end
+#define CONVERT_SYMBOLIC_ATTRIBUTE riscv_convert_symbolic_attribute
+
+extern void riscv_md_end (void);
+extern int riscv_convert_symbolic_attribute (const char *);
+
 #endif /* TC_RISCV */
diff --git a/gas/configure b/gas/configure
index ea85e1b..64de9f1 100755
--- a/gas/configure
+++ b/gas/configure
@@ -809,6 +809,7 @@ enable_x86_relax_relocations
 enable_elf_stt_common
 enable_generate_build_notes
 enable_x86_used_note
+enable_default_riscv_attribute
 enable_werror
 enable_build_warnings
 with_cpu
@@ -1471,6 +1472,8 @@ Optional Features:
                           generate GNU Build notes if none are provided by the
                           input
   --enable-x86-used-note  generate GNU x86 used ISA and feature properties
+  --enable-default-riscv-attribute
+                          generate RISC-V arch attribute by default
   --enable-werror         treat compile warnings as errors
   --enable-build-warnings enable build-time compiler warnings
   --disable-nls           do not use Native Language Support
@@ -11337,7 +11340,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11340 "configure"
+#line 11343 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11443,7 +11446,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11446 "configure"
+#line 11449 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12125,6 +12128,16 @@ if test "${enable_x86_used_note+set}" = set; then :
 esac
 fi
 
+# Decide if the RISC-V ELF assembler should default to generating attribute.
+ac_default_generate_riscv_attr=unset
+# Provide a configuration option to override the default.
+# Check whether --enable-default-riscv-attribute was given.
+if test "${enable_default_riscv_attribute+set}" = set; then :
+  enableval=$enable_default_riscv_attribute; case "${enableval}" in
+  yes)  ac_default_generate_riscv_attr=1 ;;
+  no)   ac_default_generate_riscv_attr=0 ;;
+esac
+fi
 
 using_cgen=no
 
@@ -13102,6 +13115,23 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+if test ${ac_default_generate_riscv_attr} = unset; then
+    case ${target_os} in
+      elf)
+	ac_default_generate_riscv_attr=1
+	;;
+      *)
+	ac_default_generate_riscv_attr=0
+	;;
+  esac
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_RISCV_ATTR $ac_default_generate_riscv_attr
+_ACEOF
+
+
 if test x$ac_default_compressed_debug_sections = xyes ; then
 
 $as_echo "#define DEFAULT_FLAG_COMPRESS_DEBUG 1" >>confdefs.h
diff --git a/gas/configure.ac b/gas/configure.ac
index 2fe9f78..105d708 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -125,6 +125,16 @@ AC_ARG_ENABLE(x86-used-note,
   no)   ac_default_generate_x86_used_note=0 ;;
 esac])dnl
 
+# Decide if the RISC-V ELF assembler should default to generating attribute.
+ac_default_generate_riscv_attr=unset
+# Provide a configuration option to override the default.
+AC_ARG_ENABLE(default-riscv-attribute,
+	      AS_HELP_STRING([--enable-default-riscv-attribute],
+	      [generate RISC-V arch attribute by default]),
+[case "${enableval}" in
+  yes)  ac_default_generate_riscv_attr=1 ;;
+  no)   ac_default_generate_riscv_attr=0 ;;
+esac])dnl
 
 using_cgen=no
 
@@ -663,6 +673,21 @@ AC_DEFINE_UNQUOTED(DEFAULT_X86_USED_NOTE,
   [Define to 1 if you want to generate GNU x86 used ISA and feature
    properties by default.])
 
+if test ${ac_default_generate_riscv_attr} = unset; then
+    case ${target_os} in
+      elf)
+	ac_default_generate_riscv_attr=1
+	;;
+      *)
+	ac_default_generate_riscv_attr=0
+	;;
+  esac
+fi
+
+AC_DEFINE_UNQUOTED(DEFAULT_RISCV_ATTR,
+  $ac_default_generate_riscv_attr,
+  [Define to 1 if you want to generate RISC-V arch attribute by default.])
+
 if test x$ac_default_compressed_debug_sections = xyes ; then
   AC_DEFINE(DEFAULT_FLAG_COMPRESS_DEBUG, 1, [Define if you want compressed debug sections by default.])
 fi
diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi
index 74f626f..9d7146c 100644
--- a/gas/doc/c-riscv.texi
+++ b/gas/doc/c-riscv.texi
@@ -18,6 +18,7 @@
 * RISC-V-Options::        RISC-V Options
 * RISC-V-Directives::     RISC-V Directives
 * RISC-V-Formats::        RISC-V Instruction Formats
+* RISC-V-ATTRIBUTE::      RISC-V Object Attribute
 @end menu
 
 @node RISC-V-Options
@@ -168,6 +169,15 @@ instruction formats for @samp{.insn} (@ref{RISC-V-Formats}).
 For example, the instruction @samp{add a0, a1, a2} could be written as
 @samp{.insn r 0x33, 0, 0, a0, a1, a2}.
 
+@cindex @code{.attribute} directive, RISC-V
+@item .attribute @var{tag}, @var{value}
+Set the object attribute @var{tag} to @var{value}.
+
+The @var{tag} is either an attribute number, or one of the following:
+@code{Tag_RISCV_arch}, @code{Tag_RISCV_stack_align},
+@code{Tag_RISCV_unaligned_access}, @code{Tag_RISCV_priv_spec},
+@code{Tag_RISCV_priv_spec_minor}, @code{Tag_RISCV_priv_spec_revision}
+
 @end table
 
 @node RISC-V-Formats
@@ -409,3 +419,50 @@ with the @samp{.insn} pseudo directive:
 
 For the complete list of all instruction format variants see
 The RISC-V Instruction Set Manual Volume I: User-Level ISA.
+
+@node RISC-V-ATTRIBUTE
+@section RISC-V Object Attribute
+@cindex Object Attribute, RISC-V
+
+RISC-V attributes have a string value if the tag number is odd and an integer
+value if the tag number is even.
+
+@table @r
+@item Tag_RISCV_stack_align (4)
+Tag_RISCV_strict_align records the N-byte stack alignment for this object. The
+default value is 16 for RV32I or RV64I, and 4 for RV32E.
+
+The smallest value will be used if object files with different
+Tag_RISCV_stack_align values are merged.
+
+@item Tag_RISCV_arch (5)
+Tag_RISCV_arch contains the string about the target architecture from the option
+@option{-march}. Different architectures will be integrated into a superset
+when object files are merged.
+
+Note that the version information of target architecture must be presented
+explicitly in the attribute and abbreviation must be expanded. The version
+information, if not given by @option{-march}, must be accordance with the
+default specified by the tool. For example, the architecture @code{RV32I} had
+to be recorded in the attribute as @code{RV32I2P0} in which @code{2P0} stands
+for the default version of its based ISA. On the other hand, the architecture
+@code{RV32G} has to be presented as @code{RV32I2P0_M2P0_A2P0_F2P0_D2P0} in
+which the abbreviation @code{G} is expanded to the @code{IMAFD} combination
+with default versions of the standard extensions.
+
+@item Tag_RISCV_unaligned_access (6)
+@itemize
+@item
+0 for files does not allow any unaligned memory accesses..
+@item
+1 for files allows unaligned memory accesses.
+@end itemize
+
+@item Tag_RISCV_priv_spec (8)
+@item Tag_RISCV_priv_spec_minor (10)
+@item Tag_RISCV_priv_spec_revision (12)
+Tag_RISCV_priv_spec contains the major/minor/revision version information about
+the privileged specification. It will report errors if object files of different
+privileged specification versions are merged.
+
+@end table
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index efd24f8..d616d5d 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -76,6 +76,9 @@ if { [is_elf_format] } then {
     if {[istarget "rx-*-*"]} then {
 	set target_machine -rx
     }
+    if {[istarget "riscv*-*-*"]} then {
+	set target_machine -riscv
+    }
     if {[istarget "v850*-*-*"]} then {
 	set target_machine -v850
     }
@@ -170,10 +173,16 @@ if { [is_elf_format] } then {
     if {! [istarget "h8300-*-*"]} then {
 	# The h8300 port issues a warning message for
 	# new sections created without atrributes.
-	if  { [istarget "i*86-*-*"] || [istarget "x86_64-*-*"] } then {
-	    run_elf_list_test "section2" "$target_machine" "-al -mx86-used-note=no" "-s" ""
-	} {
-	    run_elf_list_test "section2" "$target_machine" "-al" "-s" ""
+	case $target_triplet in {
+	    { i*86-*-* x86_64-*-* } {
+		run_elf_list_test "section2" "$target_machine" "-al -mx86-used-note=no" "-s" ""
+	    }
+	    { riscv*-*-* } {
+		run_elf_list_test "section2" "$target_machine" "-al -march-attr" "-s" ""
+	    }
+	    default {
+		run_elf_list_test "section2" "$target_machine" "-al" "-s" ""
+	    }
 	}
     }
     run_dump_test "section3"
diff --git a/gas/testsuite/gas/elf/section2.e-riscv b/gas/testsuite/gas/elf/section2.e-riscv
new file mode 100644
index 0000000..115bae2
--- /dev/null
+++ b/gas/testsuite/gas/elf/section2.e-riscv
@@ -0,0 +1,9 @@
+
+Symbol table '.symtab' contains 6 entries:
+ +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
+ +0: 0+0 +0 +NOTYPE +LOCAL +DEFAULT +UND 
+ +1: 0+0 +0 +SECTION +LOCAL +DEFAULT +1 
+ +2: 0+0 +0 +SECTION +LOCAL +DEFAULT +2 
+ +3: 0+0 +0 +SECTION +LOCAL +DEFAULT +3 
+ +4: 0+0 +0 +SECTION +LOCAL +DEFAULT +4 
+ +5: 0+0 +0 +SECTION +LOCAL +DEFAULT +5 
diff --git a/gas/testsuite/gas/riscv/attribute-01.d b/gas/testsuite/gas/riscv/attribute-01.d
new file mode 100644
index 0000000..e22773e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-01.d
@@ -0,0 +1,6 @@
+#as: -march=rv32g -march-attr
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0"
diff --git a/gas/testsuite/gas/riscv/attribute-02.d b/gas/testsuite/gas/riscv/attribute-02.d
new file mode 100644
index 0000000..bc3295b
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-02.d
@@ -0,0 +1,6 @@
+#as: -march=rv32gxargle -march-attr
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0"
diff --git a/gas/testsuite/gas/riscv/attribute-03.d b/gas/testsuite/gas/riscv/attribute-03.d
new file mode 100644
index 0000000..78b706a
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-03.d
@@ -0,0 +1,6 @@
+#as: -march=rv32gxargle_xfoo -march-attr
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0_xfoo2p0"
diff --git a/gas/testsuite/gas/riscv/attribute-04.d b/gas/testsuite/gas/riscv/attribute-04.d
new file mode 100644
index 0000000..c97bf03
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-04.d
@@ -0,0 +1,6 @@
+#as: -march-attr
+#readelf: -A
+#source: attribute-04.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0"
diff --git a/gas/testsuite/gas/riscv/attribute-04.s b/gas/testsuite/gas/riscv/attribute-04.s
new file mode 100644
index 0000000..2636227
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-04.s
@@ -0,0 +1 @@
+	.attribute arch,"rv32g"
diff --git a/gas/testsuite/gas/riscv/attribute-05.d b/gas/testsuite/gas/riscv/attribute-05.d
new file mode 100644
index 0000000..f9b65f2
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-05.d
@@ -0,0 +1,11 @@
+#as: -march-attr
+#readelf: -A
+#source: attribute-05.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_stack_align: 16-bytes
+  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0"
+  Tag_RISCV_unaligned_access: Unaligned access
+  Tag_RISCV_priv_spec: 1
+  Tag_RISCV_priv_spec_minor: 2
+  Tag_RISCV_priv_spec_revision: 3
diff --git a/gas/testsuite/gas/riscv/attribute-05.s b/gas/testsuite/gas/riscv/attribute-05.s
new file mode 100644
index 0000000..3b3b7f6
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-05.s
@@ -0,0 +1,6 @@
+	.attribute arch, "rv32g"
+	.attribute priv_spec, 1
+	.attribute priv_spec_minor, 2
+	.attribute priv_spec_revision, 3
+	.attribute unaligned_access, 1
+	.attribute stack_align, 16
diff --git a/gas/testsuite/gas/riscv/attribute-06.d b/gas/testsuite/gas/riscv/attribute-06.d
new file mode 100644
index 0000000..1abeb47
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-06.d
@@ -0,0 +1,6 @@
+#as: -march=rv32g2p0 -march-attr
+#readelf: -A
+#source: attribute-06.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i2p0"
diff --git a/gas/testsuite/gas/riscv/attribute-06.s b/gas/testsuite/gas/riscv/attribute-06.s
new file mode 100644
index 0000000..de50251
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-06.s
@@ -0,0 +1 @@
+	.attribute arch, "rv32i"
diff --git a/gas/testsuite/gas/riscv/attribute-07.d b/gas/testsuite/gas/riscv/attribute-07.d
new file mode 100644
index 0000000..dfd7e6b
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-07.d
@@ -0,0 +1,6 @@
+#as: -march=rv64g2p0 -march-attr
+#readelf: -A
+#source: attribute-07.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv64i2p0"
diff --git a/gas/testsuite/gas/riscv/attribute-07.s b/gas/testsuite/gas/riscv/attribute-07.s
new file mode 100644
index 0000000..35e6ae3
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-07.s
@@ -0,0 +1 @@
+	.attribute arch, "rv64i"
diff --git a/gas/testsuite/gas/riscv/attribute-08.d b/gas/testsuite/gas/riscv/attribute-08.d
new file mode 100644
index 0000000..c10ac0c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-08.d
@@ -0,0 +1,6 @@
+#as: -march-attr
+#readelf: -A
+#source: attribute-08.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32e1p9"
diff --git a/gas/testsuite/gas/riscv/attribute-08.s b/gas/testsuite/gas/riscv/attribute-08.s
new file mode 100644
index 0000000..44e7a8d
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-08.s
@@ -0,0 +1 @@
+	.attribute arch, "rv32e1p9"
diff --git a/gas/testsuite/gas/riscv/attribute-unknown.d b/gas/testsuite/gas/riscv/attribute-unknown.d
new file mode 100644
index 0000000..667f21a
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-unknown.d
@@ -0,0 +1,8 @@
+#as: -march-attr
+#readelf: -A
+#source: attribute-unknown.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: [a-zA-Z0-9_\"].*
+  Tag_unknown_255: "test"
+  Tag_unknown_256: 123 \(0x7b\)
diff --git a/gas/testsuite/gas/riscv/attribute-unknown.s b/gas/testsuite/gas/riscv/attribute-unknown.s
new file mode 100644
index 0000000..7e63a35
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-unknown.s
@@ -0,0 +1,2 @@
+	.attribute 255, "test"
+	.attribute 256, 123
diff --git a/gas/testsuite/gas/riscv/empty.l b/gas/testsuite/gas/riscv/empty.l
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gas/testsuite/gas/riscv/empty.l
@@ -0,0 +1 @@
+
diff --git a/include/ChangeLog b/include/ChangeLog
index e49dbbd..45f52af 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,13 @@
+2019-01-16  Kito Cheng  <kito@andestech.com>
+
+	* elf/riscv.h (SHT_RISCV_ATTRIBUTES): Define.
+	(Tag_RISCV_arch): Likewise.
+	(Tag_RISCV_priv_spec): Likewise.
+	(Tag_RISCV_priv_spec_minor): Likewise.
+	(Tag_RISCV_priv_spec_revision): Likewise.
+	(Tag_RISCV_unaligned_access): Likewise.
+	(Tag_RISCV_stack_align): Likewise.
+
 2019-01-14  Pavel I. Kryukov  <kryukov@frtk.ru>
 
 	* dis-asm.h: include <string.h>
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 7b10929..2f98aa4 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -116,4 +116,20 @@ END_RELOC_NUMBERS (R_RISCV_max)
 /* The name of the global pointer symbol.  */
 #define RISCV_GP_SYMBOL "__global_pointer$"
 
+/* Additional section types.  */
+#define SHT_RISCV_ATTRIBUTES   0x70000003  /* Section holds attributes.  */
+
+/* Object attributes.  */
+
+enum
+{
+  /* 0-3 are generic.  */
+  Tag_RISCV_stack_align = 4,
+  Tag_RISCV_arch = 5,
+  Tag_RISCV_unaligned_access = 6,
+  Tag_RISCV_priv_spec = 8,
+  Tag_RISCV_priv_spec_minor = 10,
+  Tag_RISCV_priv_spec_revision = 12
+};
+
 #endif /* _ELF_RISCV_H */
-- 
1.8.3.1

