+/* Parse a .arc_attribute directive. */
+
+static void
+arc_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+ int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
+
+ if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
+ attributes_set_explicitly[tag] = TRUE;
+}
+
+/* Set an attribute if it has not already been set by the user. */
+
+static void
+arc_set_attribute_int (int tag, int value)
+{
+ if (tag < 1
+ || tag >= NUM_KNOWN_OBJ_ATTRIBUTES
+ || !attributes_set_explicitly[tag])
+ bfd_elf_add_proc_attr_int (stdoutput, tag, value);
+}
+
+static void
+arc_set_attribute_string (int tag, const char *value)
+{
+ if (tag < 1
+ || tag >= NUM_KNOWN_OBJ_ATTRIBUTES
+ || !attributes_set_explicitly[tag])
+ bfd_elf_add_proc_attr_string (stdoutput, tag, value);
+}
+
+/* Allocate and concatenate two strings. s1 can be NULL but not
+ s2. s1 pointer is freed at end of this procedure. */
+
+static char *
+arc_stralloc (char * s1, const char * s2)
+{
+ char * p;
+ int len = 0;
+
+ if (s1)
+ len = strlen (s1) + 1;
+
+ /* Only s1 can be null. */
+ gas_assert (s2);
+ len += strlen (s2) + 1;
+
+ p = (char *) xmalloc (len);
+ if (p == NULL)
+ as_fatal (_("Virtual memory exhausted"));
+
+ if (s1)
+ {
+ strcpy (p, s1);
+ strcat (p, ",");
+ strcat (p, s2);
+ free (s1);
+ }
+ else
+ strcpy (p, s2);
+
+ return p;
+}
+
+/* Set the public ARC object attributes. */
+
+static void
+arc_set_public_attributes (void)
+{
+ int base = 0;
+ char *s = NULL;
+ unsigned int i;
+
+ /* Tag_ARC_CPU_name. */
+ arc_set_attribute_string (Tag_ARC_CPU_name, selected_cpu.name);
+
+ /* Tag_ARC_CPU_base. */
+ switch (selected_cpu.eflags & EF_ARC_MACH_MSK)
+ {
+ case E_ARC_MACH_ARC600:
+ case E_ARC_MACH_ARC601:
+ base = TAG_CPU_ARC6xx;
+ break;
+ case E_ARC_MACH_ARC700:
+ base = TAG_CPU_ARC7xx;
+ break;
+ case EF_ARC_CPU_ARCV2EM:
+ base = TAG_CPU_ARCEM;
+ break;
+ case EF_ARC_CPU_ARCV2HS:
+ base = TAG_CPU_ARCHS;
+ break;
+ default:
+ base = 0;
+ break;
+ }
+ if (attributes_set_explicitly[Tag_ARC_CPU_base]
+ && (base != bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
+ Tag_ARC_CPU_base)))
+ as_warn (_("Overwrite explicitly set Tag_ARC_CPU_base"));
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_CPU_base, base);
+
+ /* Tag_ARC_ABI_osver. */
+ if (attributes_set_explicitly[Tag_ARC_ABI_osver])
+ {
+ int val = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
+ Tag_ARC_ABI_osver);
+
+ selected_cpu.eflags = ((selected_cpu.eflags & ~EF_ARC_OSABI_MSK)
+ | (val & 0x0f << 8));
+ }
+ else
+ {
+ arc_set_attribute_int (Tag_ARC_ABI_osver, E_ARC_OSABI_CURRENT >> 8);
+ }
+
+ /* Tag_ARC_ISA_config. */
+ arc_check_feature();
+
+ for (i = 0; i < ARRAY_SIZE (feature_list); i++)
+ if (selected_cpu.features & feature_list[i].feature)
+ s = arc_stralloc (s, feature_list[i].attr);
+
+ if (s)
+ arc_set_attribute_string (Tag_ARC_ISA_config, s);
+
+ /* Tag_ARC_ISA_mpy_option. */
+ arc_set_attribute_int (Tag_ARC_ISA_mpy_option, mpy_option);
+
+ /* Tag_ARC_ABI_pic. */
+ arc_set_attribute_int (Tag_ARC_ABI_pic, pic_option);
+
+ /* Tag_ARC_ABI_sda. */
+ arc_set_attribute_int (Tag_ARC_ABI_sda, sda_option);
+
+ /* Tag_ARC_ABI_tls. */
+ arc_set_attribute_int (Tag_ARC_ABI_tls, tls_option);
+
+ /* Tag_ARC_ATR_version. */
+ arc_set_attribute_int (Tag_ARC_ATR_version, 1);
+
+ /* Tag_ARC_ABI_rf16. */
+ if (attributes_set_explicitly[Tag_ARC_ABI_rf16]
+ && bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
+ Tag_ARC_ABI_rf16)
+ && !rf16_only)
+ {
+ as_warn (_("Overwrite explicitly set Tag_ARC_ABI_rf16 to full "
+ "register file"));
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_ABI_rf16, 0);
+ }
+}
+
+/* Add the default contents for the .ARC.attributes section. */
+
+void
+arc_md_end (void)
+{
+ arc_set_public_attributes ();
+
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
+ as_fatal (_("could not set architecture and machine"));
+
+ bfd_set_private_flags (stdoutput, selected_cpu.eflags);
+}
+
+void arc_copy_symbol_attributes (symbolS *dest, symbolS *src)
+{
+ ARC_GET_FLAG (dest) = ARC_GET_FLAG (src);
+}
+
+int arc_convert_symbolic_attribute (const char *name)
+{
+ static const struct
+ {
+ const char * name;
+ const int tag;
+ }
+ attribute_table[] =
+ {
+#define T(tag) {#tag, tag}
+ T (Tag_ARC_PCS_config),
+ T (Tag_ARC_CPU_base),
+ T (Tag_ARC_CPU_variation),
+ T (Tag_ARC_CPU_name),
+ T (Tag_ARC_ABI_rf16),
+ T (Tag_ARC_ABI_osver),
+ T (Tag_ARC_ABI_sda),
+ T (Tag_ARC_ABI_pic),
+ T (Tag_ARC_ABI_tls),
+ T (Tag_ARC_ABI_enumsize),
+ T (Tag_ARC_ABI_exceptions),
+ T (Tag_ARC_ABI_double_size),
+ T (Tag_ARC_ISA_config),
+ T (Tag_ARC_ISA_apex),
+ T (Tag_ARC_ISA_mpy_option),
+ T (Tag_ARC_ATR_version)
+#undef T
+ };
+ unsigned int i;
+
+ if (name == NULL)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
+ if (streq (name, attribute_table[i].name))
+ return attribute_table[i].tag;
+
+ return -1;
+}
+