Add support for new functionality in the msp430 backend of GCC.
[deliverable/binutils-gdb.git] / gas / config / tc-msp430.c
index 56d202434999613a44bc4930ce5652035315e03b..41413f0de92dd9c5c3ebc6627f18bf0619329f8a 100644 (file)
@@ -689,6 +689,8 @@ static bfd_boolean do_unknown_interrupt_nops = TRUE;
 static bfd_boolean move_data = FALSE;
 #define OPTION_DATA_REGION 'r'
 static bfd_boolean upper_data_region_in_use = FALSE;
+/* The default is to use the lower region only.  */
+static bfd_boolean lower_data_region_only = TRUE;
 
 enum
 {
@@ -1473,6 +1475,13 @@ md_parse_option (int c, const char * arg)
       if (strcmp (arg, "upper") == 0
          || strcmp (arg, "either") == 0)
        upper_data_region_in_use = TRUE;
+      if (strcmp (arg, "upper") == 0
+         || strcmp (arg, "either") == 0
+         /* With data-region=none, the compiler has generated code assuming
+            data could be in the upper region, but nothing has been explicitly
+            placed there.  */
+         || strcmp (arg, "none") == 0)
+       lower_data_region_only = FALSE;
       return 1;
     }
 
@@ -1598,6 +1607,120 @@ msp430_refsym (int arg ATTRIBUTE_UNUSED)
   (void) symbol_find_or_make (sym_name);
 }
 
+/* Handle a .mspabi_attribute or .gnu_attribute directive.
+   attr_type is 0 for .mspabi_attribute or 1 for .gnu_attribute.
+   This is only used for validating the attributes in the assembly file against
+   the options gas has been invoked with.  If the attributes and options are
+   compatible then we add the attributes to the assembly file in
+   msp430_md_end.  */
+static void
+msp430_object_attribute (int attr_type)
+{
+  char tag_name_s[32];
+  char tag_value_s[32];
+  int tag_name, tag_value;
+  /* First operand is the tag name, second is the tag value e.g.
+     ".mspabi_attribute 4, 2".  */
+  input_line_pointer = extract_operand (input_line_pointer, tag_name_s, 32);
+  input_line_pointer = extract_operand (input_line_pointer, tag_value_s, 32);
+  tag_name = atoi (tag_name_s);
+  tag_value = atoi (tag_value_s);
+  /* If the attribute directive is present, the tag_value should never be set
+     to 0.  */
+  if (tag_name == 0 || tag_value == 0)
+    as_bad (_("bad arguments \"%s\" and/or \"%s\" in %s directive"),
+             tag_name_s, tag_value_s, (attr_type ? ".gnu_attribute"
+                                       : ".mspabi_attribute"));
+  else if (attr_type == 0)
+    /* Handle .mspabi_attribute.  */
+    switch (tag_name)
+      {
+      case OFBA_MSPABI_Tag_ISA:
+       switch (tag_value)
+         {
+         case OFBA_MSPABI_Val_ISA_MSP430:
+           if (target_is_430x ())
+             as_bad (_("file was compiled for the 430 ISA but the %s ISA is "
+                       "selected"), (target_is_430xv2 () ? "430X" : "430Xv2"));
+           break;
+         case OFBA_MSPABI_Val_ISA_MSP430X:
+           if (!target_is_430x ())
+             as_bad (_("file was compiled for the 430X ISA but the 430 ISA is "
+                       "selected"));
+           break;
+         default:
+           as_bad (_("unknown MSPABI build attribute value '%d' for "
+                     "OFBA_MSPABI_Tag_ISA(%d) in .mspabi_attribute directive"),
+                   tag_value, OFBA_MSPABI_Tag_ISA);
+           break;
+         }
+       break;
+      case OFBA_MSPABI_Tag_Code_Model:
+       /* Fall through.  */
+      case OFBA_MSPABI_Tag_Data_Model:
+       /* FIXME: Might we want to set the memory model to large if the assembly
+          file has the large model attribute, but -ml has not been passed?  */
+       switch (tag_value)
+         {
+         case OFBA_MSPABI_Val_Code_Model_SMALL:
+           if (large_model)
+             as_bad (_("file was compiled for the small memory model, but the "
+                       "large memory model is selected"));
+           break;
+         case OFBA_MSPABI_Val_Code_Model_LARGE:
+           if (!large_model)
+             as_bad (_("file was compiled for the large memory model, "
+                       "but the small memory model is selected"));
+           break;
+         default:
+           as_bad (_("unknown MSPABI build attribute value '%d' for %s(%d) "
+                     "in .mspabi_attribute directive"), tag_value,
+                   (tag_name == OFBA_MSPABI_Tag_Code_Model
+                    ? "OFBA_MSPABI_Tag_Code_Model"
+                    : "OFBA_MSPABI_Tag_Data_Model"),
+                   (tag_name == OFBA_MSPABI_Tag_Code_Model
+                    ? OFBA_MSPABI_Tag_Code_Model
+                    : OFBA_MSPABI_Tag_Data_Model));
+           break;
+         }
+       break;
+      default:
+       as_bad (_("unknown MSPABI build attribute tag '%d' in "
+                 ".mspabi_attribute directive"), tag_name);
+       break;
+      }
+  else if (attr_type == 1)
+    /* Handle .gnu_attribute.  */
+    switch (tag_name)
+      {
+      case Tag_GNU_MSP430_Data_Region:
+       /* This attribute is only applicable in the large memory model.  */
+       if (!large_model)
+         break;
+       switch (tag_value)
+         {
+         case Val_GNU_MSP430_Data_Region_Lower:
+           if (!lower_data_region_only)
+             as_bad (_("file was compiled assuming all data will be in the "
+                       "lower memory region, but the upper region is in use"));
+           break;
+         case Val_GNU_MSP430_Data_Region_Any:
+           if (lower_data_region_only)
+             as_bad (_("file was compiled assuming data could be in the upper "
+                       "memory region, but the lower data region is "
+                       "exclusively in use"));
+           break;
+         default:
+           as_bad (_("unknown GNU build attribute value '%d' for "
+                     "Tag_GNU_MSP430_Data_Region(%d) in .gnu_attribute "
+                     "directive"), tag_value, Tag_GNU_MSP430_Data_Region);
+         }
+      }
+  else
+    as_bad (_("internal: unexpected argument '%d' to msp430_object_attribute"),
+           attr_type);
+}
+
 const pseudo_typeS md_pseudo_table[] =
 {
   {"arch", msp430_set_arch, OPTION_MMCU},
@@ -1611,6 +1734,8 @@ const pseudo_typeS md_pseudo_table[] =
   {"refsym", msp430_refsym, 0},
   {"comm", msp430_comm, 0},
   {"lcomm", msp430_lcomm, 0},
+  {"mspabi_attribute", msp430_object_attribute, 0},
+  {"gnu_attribute", msp430_object_attribute, 1},
   {NULL, NULL, 0}
 };
 
@@ -4919,7 +5044,7 @@ msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED)
   return FALSE;
 }
 
-/* Set the contents of the .MSP430.attributes section.  */
+/* Set the contents of the .MSP430.attributes and .GNU.attributes sections.  */
 
 void
 msp430_md_end (void)
@@ -4936,14 +5061,27 @@ msp430_md_end (void)
        as_warn (_(WARN_NOP_AT_EOF));
     }
 
+  /* We have already emitted an error if any of the following attributes
+     disagree with the attributes in the input assembly file.  See
+     msp430_object_attribute.  */
   bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_ISA,
-                            target_is_430x () ? 2 : 1);
+                            target_is_430x () ? OFBA_MSPABI_Val_ISA_MSP430X
+                            : OFBA_MSPABI_Val_ISA_MSP430);
 
   bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_Code_Model,
-                            large_model ? 2 : 1);
+                            large_model ? OFBA_MSPABI_Val_Code_Model_LARGE
+                            : OFBA_MSPABI_Val_Code_Model_SMALL);
 
   bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_Data_Model,
-                            large_model ? 2 : 1);
+                            large_model ? OFBA_MSPABI_Val_Code_Model_LARGE
+                            : OFBA_MSPABI_Val_Code_Model_SMALL);
+
+  /* The data region GNU attribute is ignored for the small memory model.  */
+  if (large_model)
+    bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+                             Tag_GNU_MSP430_Data_Region, lower_data_region_only
+                             ? Val_GNU_MSP430_Data_Region_Lower
+                             : Val_GNU_MSP430_Data_Region_Any);
 }
 
 /* Returns FALSE if there is a msp430 specific reason why the
This page took 0.025515 seconds and 4 git commands to generate.