Add support for new functionality in the msp430 backend of GCC.
authorJozef Lawrynowicz <jozef.l@mittosystems.com>
Mon, 7 Oct 2019 15:34:31 +0000 (16:34 +0100)
committerNick Clifton <nickc@redhat.com>
Mon, 7 Oct 2019 15:34:31 +0000 (16:34 +0100)
This functionality will generate a new GNU object attribute for the "data region"
has been added. This object attribute is used
mark whether the compiler has generated code assuming that data could be in the
upper or lower memory regions.

Code which assumes data is always in the lower memory region is incompatible
with code which uses the full memory range for data.

The patch also adds a new assembler directive ".mspabi_attribute" to handle the
existing MSPABI object attributes. GCC will now emit both .gnu_attribute and
.mspabi_attribute directives to indicate what options the source file was
compiled with.

The assembler will now check the values set in these directives against the
options that the it has been invoked with. If there is a discrepancy, the
assembler will exit with an error.

bfd * elf32-msp430.c (elf32_msp430_merge_mspabi_attributes): Rename to..
(elf32_msp430_merge_msp430_attributes): Add support for merging the GNU
object attribute for data region.

binutils* readelf.c (display_msp430_gnu_attribute): New.
(process_arch_specific): Use msp430 specific handler for GNU
attributes.

gas * config/tc-msp430.c (md_parse_option): Set lower_data_region_only to
FALSE if the data region is set to "upper", "either" or "none".
(msp430_object_attribute): New.
(md_pseudo_table): Handle .mspabi_attribute and .gnu_attribute.
(msp430_md_end): Replace hard-coded attribute values with enums.
Handle data region object attribute.
* doc/as.texi: Document MSP430 Data Region object attribute.
* doc/c-msp430.texi: Document the .mspabi_attribute directive.
* testsuite/gas/msp430/attr-430-small-bad.d: New test.
* testsuite/gas/msp430/attr-430-small-bad.l: New test.
* testsuite/gas/msp430/attr-430-small-good.d: New test.
* testsuite/gas/msp430/attr-430-small.s: New test.
* testsuite/gas/msp430/attr-430x-large-any-bad.d: New test.
* testsuite/gas/msp430/attr-430x-large-any-bad.l: New test.
* testsuite/gas/msp430/attr-430x-large-any-good.d: New test.
* testsuite/gas/msp430/attr-430x-large-any.s: New test.
* testsuite/gas/msp430/attr-430x-large-lower-bad.d: New test.
* testsuite/gas/msp430/attr-430x-large-lower-bad.l: New test.
* testsuite/gas/msp430/attr-430x-large-lower-good.d: New test.
* testsuite/gas/msp430/attr-430x-large-lower.s: New test.
* testsuite/gas/msp430/msp430.exp: Run new tests.

include * elf/msp430.h: Add enums for MSPABI and GNU object attribute tag names
and values.

ld * testsuite/ld-msp430-elf/attr-gnu-main.s: New test.
* testsuite/ld-msp430-elf/attr-gnu-obj.s: New test.
* testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d: New test.
* testsuite/ld-msp430-elf/attr-gnu-region-lower.d: New test.
* testsuite/ld-msp430-elf/attr-gnu-region-upper.d: New test.
* testsuite/ld-msp430-elf/msp430-elf.exp: Run new tests.

30 files changed:
bfd/ChangeLog
bfd/elf32-msp430.c
binutils/ChangeLog
binutils/readelf.c
gas/ChangeLog
gas/config/tc-msp430.c
gas/doc/as.texi
gas/doc/c-msp430.texi
gas/testsuite/gas/msp430/attr-430-small-bad.d [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430-small-bad.l [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430-small-good.d [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430-small.s [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-any-bad.d [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-any-bad.l [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-any-good.d [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-any.s [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-lower-bad.d [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-lower-bad.l [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-lower-good.d [new file with mode: 0644]
gas/testsuite/gas/msp430/attr-430x-large-lower.s [new file with mode: 0644]
gas/testsuite/gas/msp430/msp430.exp
include/ChangeLog
include/elf/msp430.h
ld/ChangeLog
ld/testsuite/ld-msp430-elf/attr-gnu-main.s [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/attr-gnu-obj.s [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/attr-gnu-region-lower.d [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/attr-gnu-region-upper.d [new file with mode: 0644]
ld/testsuite/ld-msp430-elf/msp430-elf.exp

index 72737181b0daef63a3554e3a7984c98b8a147075..6062d38a28dc78a75595a3a043b69a9d8be63e76 100644 (file)
@@ -1,3 +1,9 @@
+2019-10-07  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * elf32-msp430.c (elf32_msp430_merge_mspabi_attributes): Rename to..
+       (elf32_msp430_merge_msp430_attributes): Add support for merging
+       the GNU object attribute for data region.
+
 2019-10-07  Alan Modra  <amodra@gmail.com>
 
        * elf64-ppc.c (ppc64_elf_size_dynamic_sections): Do allocate
index 4dcc8d480da870c4f263b45cbccd3803a2d4227d..d581dbcd9308a67e18fd3cb6b35ac2ca7014d176 100644 (file)
@@ -2408,15 +2408,15 @@ data_model (int model)
     }
 }
 
-/* Merge MSPABI object attributes from IBFD into OBFD.
+/* Merge MSPABI and GNU object attributes from IBFD into OBFD.
    Raise an error if there are conflicting attributes.  */
 
 static bfd_boolean
-elf32_msp430_merge_mspabi_attributes (bfd *ibfd, struct bfd_link_info *info)
+elf32_msp430_merge_msp430_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
-  obj_attribute *in_attr;
-  obj_attribute *out_attr;
+  obj_attribute *in_msp_attr, *in_gnu_attr;
+  obj_attribute *out_msp_attr, *out_gnu_attr;
   bfd_boolean result = TRUE;
   static bfd * first_input_bfd = NULL;
 
@@ -2435,45 +2435,48 @@ elf32_msp430_merge_mspabi_attributes (bfd *ibfd, struct bfd_link_info *info)
     {
       _bfd_elf_copy_obj_attributes (ibfd, obfd);
 
-      out_attr = elf_known_obj_attributes_proc (obfd);
+      out_msp_attr = elf_known_obj_attributes_proc (obfd);
 
       /* Use the Tag_null value to indicate that
         the attributes have been initialized.  */
-      out_attr[0].i = 1;
+      out_msp_attr[0].i = 1;
 
       first_input_bfd = ibfd;
       return TRUE;
     }
 
-  in_attr = elf_known_obj_attributes_proc (ibfd);
-  out_attr = elf_known_obj_attributes_proc (obfd);
+  in_msp_attr = elf_known_obj_attributes_proc (ibfd);
+  out_msp_attr = elf_known_obj_attributes_proc (obfd);
+  in_gnu_attr = elf_known_obj_attributes (ibfd) [OBJ_ATTR_GNU];
+  out_gnu_attr = elf_known_obj_attributes (obfd) [OBJ_ATTR_GNU];
 
   /* The ISAs must be the same.  */
-  if (in_attr[OFBA_MSPABI_Tag_ISA].i != out_attr[OFBA_MSPABI_Tag_ISA].i)
+  if (in_msp_attr[OFBA_MSPABI_Tag_ISA].i != out_msp_attr[OFBA_MSPABI_Tag_ISA].i)
     {
       _bfd_error_handler
        /* xgettext:c-format */
        (_("error: %pB uses %s instructions but %pB uses %s"),
-        ibfd, isa_type (in_attr[OFBA_MSPABI_Tag_ISA].i),
-        first_input_bfd, isa_type (out_attr[OFBA_MSPABI_Tag_ISA].i));
+        ibfd, isa_type (in_msp_attr[OFBA_MSPABI_Tag_ISA].i),
+        first_input_bfd, isa_type (out_msp_attr[OFBA_MSPABI_Tag_ISA].i));
       result = FALSE;
     }
 
   /* The code models must be the same.  */
-  if (in_attr[OFBA_MSPABI_Tag_Code_Model].i !=
-      out_attr[OFBA_MSPABI_Tag_Code_Model].i)
+  if (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i
+      != out_msp_attr[OFBA_MSPABI_Tag_Code_Model].i)
     {
       _bfd_error_handler
        /* xgettext:c-format */
        (_("error: %pB uses the %s code model whereas %pB uses the %s code model"),
-        ibfd, code_model (in_attr[OFBA_MSPABI_Tag_Code_Model].i),
-        first_input_bfd, code_model (out_attr[OFBA_MSPABI_Tag_Code_Model].i));
+        ibfd, code_model (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i),
+        first_input_bfd,
+        code_model (out_msp_attr[OFBA_MSPABI_Tag_Code_Model].i));
       result = FALSE;
     }
 
   /* The large code model is only supported by the MSP430X.  */
-  if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 2
-      && out_attr[OFBA_MSPABI_Tag_ISA].i != 2)
+  if (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i == 2
+      && out_msp_attr[OFBA_MSPABI_Tag_ISA].i != 2)
     {
       _bfd_error_handler
        /* xgettext:c-format */
@@ -2483,41 +2486,69 @@ elf32_msp430_merge_mspabi_attributes (bfd *ibfd, struct bfd_link_info *info)
     }
 
   /* The data models must be the same.  */
-  if (in_attr[OFBA_MSPABI_Tag_Data_Model].i !=
-      out_attr[OFBA_MSPABI_Tag_Data_Model].i)
+  if (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i
+      != out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i)
     {
       _bfd_error_handler
        /* xgettext:c-format */
        (_("error: %pB uses the %s data model whereas %pB uses the %s data model"),
-        ibfd, data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i),
-        first_input_bfd, data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i));
+        ibfd, data_model (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i),
+        first_input_bfd,
+        data_model (out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i));
       result = FALSE;
     }
 
   /* The small code model requires the use of the small data model.  */
-  if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 1
-      && out_attr[OFBA_MSPABI_Tag_Data_Model].i != 1)
+  if (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i == 1
+      && out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i != 1)
     {
       _bfd_error_handler
        /* xgettext:c-format */
        (_("error: %pB uses the small code model but %pB uses the %s data model"),
         ibfd, first_input_bfd,
-        data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i));
+        data_model (out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i));
       result = FALSE;
     }
 
   /* The large data models are only supported by the MSP430X.  */
-  if (in_attr[OFBA_MSPABI_Tag_Data_Model].i > 1
-      && out_attr[OFBA_MSPABI_Tag_ISA].i != 2)
+  if (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i > 1
+      && out_msp_attr[OFBA_MSPABI_Tag_ISA].i != 2)
     {
       _bfd_error_handler
        /* xgettext:c-format */
        (_("error: %pB uses the %s data model but %pB only uses MSP430 instructions"),
-        ibfd, data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i),
+        ibfd, data_model (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i),
         first_input_bfd);
       result = FALSE;
     }
 
+  /* Just ignore the data region unless the large memory model is in use.
+     We have already checked that ibfd and obfd use the same memory model.  */
+  if ((in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i
+       == OFBA_MSPABI_Val_Code_Model_LARGE)
+      && (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i
+         == OFBA_MSPABI_Val_Data_Model_LARGE))
+    {
+      /* We cannot allow "lower region only" to be linked with any other
+        values (i.e. ANY or NONE).
+        Before this attribute existed, "ANY" region was the default.  */
+      bfd_boolean ibfd_lower_region_used
+       = (in_gnu_attr[Tag_GNU_MSP430_Data_Region].i
+          == Val_GNU_MSP430_Data_Region_Lower);
+      bfd_boolean obfd_lower_region_used
+       = (out_gnu_attr[Tag_GNU_MSP430_Data_Region].i
+          == Val_GNU_MSP430_Data_Region_Lower);
+      if (ibfd_lower_region_used != obfd_lower_region_used)
+       {
+         _bfd_error_handler
+           (_("error: %pB can use the upper region for data, "
+              "but %pB assumes data is exclusively in lower memory"),
+            ibfd_lower_region_used ? obfd : ibfd,
+            ibfd_lower_region_used ? ibfd : obfd);
+         result = FALSE;
+       }
+    }
+
   return result;
 }
 
@@ -2536,7 +2567,7 @@ elf32_msp430_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
                               max (bfd_get_mach (ibfd), bfd_get_mach (obfd)));
 #undef max
 
-  return elf32_msp430_merge_mspabi_attributes (ibfd, info);
+  return elf32_msp430_merge_msp430_attributes (ibfd, info);
 }
 
 static bfd_boolean
index 00a1a1d8ee63e7e11fcb12d7ea50eef655dbd380..b9e2fcf1a46b0245a709cb56f464812705cda2df 100644 (file)
@@ -1,3 +1,9 @@
+2019-10-07  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * readelf.c (display_msp430_gnu_attribute): New.
+       (process_arch_specific): Use msp430 specific handler for GNU
+       attributes.
+
 2019-09-30  Nick Alcock  <nick.alcock@oracle.com>
 
        * objdump.c (main): Fix tabdamage.
index 2a9d1455647bb04d2c874b8560019265e554be41..de77237e0ec9ffddf22437b644f8b81407ce1f14 100644 (file)
@@ -15738,6 +15738,36 @@ display_msp430x_attribute (unsigned char * p,
   return p;
 }
 
+static unsigned char *
+display_msp430_gnu_attribute (unsigned char * p,
+                             unsigned int tag,
+                             const unsigned char * const end)
+{
+  if (tag == Tag_GNU_MSP430_Data_Region)
+    {
+      unsigned int len;
+      int val;
+
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_GNU_MSP430_Data_Region: ");
+
+      switch (val)
+       {
+       case Val_GNU_MSP430_Data_Region_Any:
+         printf (_("Any Region\n"));
+         break;
+       case Val_GNU_MSP430_Data_Region_Lower:
+         printf (_("Lower Region Only\n"));
+         break;
+       default:
+         printf ("??? (%d)\n", val);
+       }
+      return p;
+    }
+  return display_tag_value (tag & 1, p, end);
+}
+
 struct riscv_attr_tag_t {
   const char *name;
   int tag;
@@ -19562,7 +19592,7 @@ process_arch_specific (Filedata * filedata)
     case EM_MSP430:
      return process_attributes (filedata, "mspabi", SHT_MSP430_ATTRIBUTES,
                                display_msp430x_attribute,
-                               display_generic_attribute);
+                               display_msp430_gnu_attribute);
 
     case EM_RISCV:
      return process_attributes (filedata, "riscv", SHT_RISCV_ATTRIBUTES,
index abb8bf0c6dbbab5de2431e5896a820ef4ae3105b..41bcaa33327cea53745099368fca9e6e27faeaa5 100644 (file)
@@ -1,3 +1,27 @@
+2019-10-07  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * config/tc-msp430.c (md_parse_option): Set lower_data_region_only
+       to FALSE if the data region is set to "upper", "either" or "none".
+       (msp430_object_attribute): New.
+       (md_pseudo_table): Handle .mspabi_attribute and .gnu_attribute.
+       (msp430_md_end): Replace hard-coded attribute values with enums.
+       Handle data region object attribute.
+       * doc/as.texi: Document MSP430 Data Region object attribute.
+       * doc/c-msp430.texi: Document the .mspabi_attribute directive.
+       * testsuite/gas/msp430/attr-430-small-bad.d: New test.
+       * testsuite/gas/msp430/attr-430-small-bad.l: New test.
+       * testsuite/gas/msp430/attr-430-small-good.d: New test.
+       * testsuite/gas/msp430/attr-430-small.s: New test.
+       * testsuite/gas/msp430/attr-430x-large-any-bad.d: New test.
+       * testsuite/gas/msp430/attr-430x-large-any-bad.l: New test.
+       * testsuite/gas/msp430/attr-430x-large-any-good.d: New test.
+       * testsuite/gas/msp430/attr-430x-large-any.s: New test.
+       * testsuite/gas/msp430/attr-430x-large-lower-bad.d: New test.
+       * testsuite/gas/msp430/attr-430x-large-lower-bad.l: New test.
+       * testsuite/gas/msp430/attr-430x-large-lower-good.d: New test.
+       * testsuite/gas/msp430/attr-430x-large-lower.s: New test.
+       * testsuite/gas/msp430/msp430.exp: Run new tests.
+
 2019-10-07  Jan Beulich  <jbeulich@suse.com>
 
        * config/tc-i386.c (check_string): Make reported operand number
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
index b4598e86dc6e188aa04d46252391c3cdc3354475..93e80f9a4301df860fe5225b8726ff5cc9aa168c 100644 (file)
@@ -7585,6 +7585,23 @@ The vector ABI used by this object file.  The value will be:
 @end itemize
 @end table
 
+@subsection MSP430 Attributes
+
+@table @r
+@item Tag_GNU_MSP430_Data_Region (4)
+The data region used by this object file.  The value will be:
+
+@itemize @bullet
+@item
+0 for files not using the large memory model.
+@item
+1 for files which have been compiled with the condition that all
+data is in the lower memory region, i.e. below address 0x10000.
+@item
+2 for files which allow data to be placed in the full 20-bit memory range.
+@end itemize
+@end table
+
 @node Defining New Object Attributes
 @section Defining New Object Attributes
 
index 516c0038900e46c7e90cc0c175aebabdae1b445f..3691f21bca1521a6d24d3b80e93d64c93d184c40 100644 (file)
@@ -322,6 +322,18 @@ exist purely for pulling in object files from archives.  Note that
 this reloc is not sufficient to prevent garbage collection; use a
 KEEP() directive in the linker file to preserve such objects.
 
+@cindex @code{mspabi_attribute} directive, MSP430
+@item .mspabi_attribute
+This directive tells the assembler what the MSPABI build attributes for this
+file are.  This is used for validating the command line options passed to
+the assembler against the options the original source file was compiled with.
+The expected format is:
+@samp{.mspabi_attribute tag_name, tag_value}
+For example, to set the tag @code{OFBA_MSPABI_Tag_ISA} to @code{MSP430X}:
+@samp{.mspabi_attribute 4, 2}
+
+See the @cite{MSP430 EABI, document slaa534} for the details on tag names and
+values.
 @end table
 
 @node MSP430 Opcodes
diff --git a/gas/testsuite/gas/msp430/attr-430-small-bad.d b/gas/testsuite/gas/msp430/attr-430-small-bad.d
new file mode 100644 (file)
index 0000000..302ba57
--- /dev/null
@@ -0,0 +1,4 @@
+#name: Error when 430 ISA and small memory model object attributes conflict with options
+#source: attr-430-small.s
+#as: -mdata-region=none -ml
+#error_output: attr-430-small-bad.l
diff --git a/gas/testsuite/gas/msp430/attr-430-small-bad.l b/gas/testsuite/gas/msp430/attr-430-small-bad.l
new file mode 100644 (file)
index 0000000..c339ecf
--- /dev/null
@@ -0,0 +1,4 @@
+[^:]*: Assembler messages:
+[^:]*:1: Error: file was compiled for the 430 ISA but the 430X ISA is selected
+[^:]*:2: Error: file was compiled for the small memory model, but the large memory model is selected
+[^:]*:3: Error: file was compiled for the small memory model, but the large memory model is selected
diff --git a/gas/testsuite/gas/msp430/attr-430-small-good.d b/gas/testsuite/gas/msp430/attr-430-small-good.d
new file mode 100644 (file)
index 0000000..5f3137f
--- /dev/null
@@ -0,0 +1,6 @@
+#name: 430 ISA and small memory model object attributes
+#source: attr-430-small.s
+#as: -mcpu=msp430
+#objdump: -t
+
+#pass
diff --git a/gas/testsuite/gas/msp430/attr-430-small.s b/gas/testsuite/gas/msp430/attr-430-small.s
new file mode 100644 (file)
index 0000000..2bdb1db
--- /dev/null
@@ -0,0 +1,3 @@
+.mspabi_attribute 4, 1 ; OFBA_MSPABI_Tag_ISA == 430
+.mspabi_attribute 6, 1 ; OFBA_MSPABI_Tag_Code_Model == Small
+.mspabi_attribute 8, 1 ; OFBA_MSPABI_Tag_Data_Model == Small
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any-bad.d b/gas/testsuite/gas/msp430/attr-430x-large-any-bad.d
new file mode 100644 (file)
index 0000000..6793f7c
--- /dev/null
@@ -0,0 +1,4 @@
+#name: Error when 430X ISA, large memory model and any data region object attributes conflict with options
+#source: attr-430x-large-any.s
+#as: -mcpu=msp430 -ml
+#error_output: attr-430x-large-any-bad.l
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any-bad.l b/gas/testsuite/gas/msp430/attr-430x-large-any-bad.l
new file mode 100644 (file)
index 0000000..c7f2282
--- /dev/null
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:1: Error: file was compiled for the 430X ISA but the 430 ISA is selected
+[^:]*:4: Error: file was compiled assuming data could be in the upper memory region, but the lower data region is exclusively in use
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any-good.d b/gas/testsuite/gas/msp430/attr-430x-large-any-good.d
new file mode 100644 (file)
index 0000000..603aab1
--- /dev/null
@@ -0,0 +1,6 @@
+#name: 430X ISA, large memory model and any data region object attributes
+#source: attr-430x-large-any.s
+#as: -ml -mdata-region=none
+#objdump: -t
+
+#pass
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any.s b/gas/testsuite/gas/msp430/attr-430x-large-any.s
new file mode 100644 (file)
index 0000000..593c171
--- /dev/null
@@ -0,0 +1,4 @@
+.mspabi_attribute 4, 2 ; OFBA_MSPABI_Tag_ISA == 430x
+.mspabi_attribute 6, 2 ; OFBA_MSPABI_Tag_Code_Model == Large
+.mspabi_attribute 8, 2 ; OFBA_MSPABI_Tag_Data_Model == Large
+.gnu_attribute 4, 2 ; Tag_GNU_MSP430_Data_Region == Any
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.d b/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.d
new file mode 100644 (file)
index 0000000..fb7e5ca
--- /dev/null
@@ -0,0 +1,4 @@
+#name: Error when 430X ISA, large memory model and lower data region object attributes conflict with options
+#source: attr-430x-large-lower.s
+#as: -mdata-region=none -mcpu=msp430 -ml
+#error_output: attr-430x-large-lower-bad.l
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.l b/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.l
new file mode 100644 (file)
index 0000000..a21b640
--- /dev/null
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:1: Error: file was compiled for the 430X ISA but the 430 ISA is selected
+[^:]*:4: Error: file was compiled assuming all data will be in the lower memory region, but the upper region is in use
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower-good.d b/gas/testsuite/gas/msp430/attr-430x-large-lower-good.d
new file mode 100644 (file)
index 0000000..c4a395c
--- /dev/null
@@ -0,0 +1,6 @@
+#name: 430X ISA, large memory model and lower data region object attributes
+#source: attr-430x-large-lower.s
+#as: -ml
+#objdump: -t
+
+#pass
diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower.s b/gas/testsuite/gas/msp430/attr-430x-large-lower.s
new file mode 100644 (file)
index 0000000..4ab0b5d
--- /dev/null
@@ -0,0 +1,4 @@
+.mspabi_attribute 4, 2 ; OFBA_MSPABI_Tag_ISA == 430x
+.mspabi_attribute 6, 2 ; OFBA_MSPABI_Tag_Code_Model == Large
+.mspabi_attribute 8, 2 ; OFBA_MSPABI_Tag_Data_Model == Large
+.gnu_attribute 4, 1 ; Tag_GNU_MSP430_Data_Region == Lower
index 9c7a1975f9418f8f65c84317ade785c84ad62efa..ef3164da2b3c43174e3546d688923d1f32e501c7 100644 (file)
@@ -46,4 +46,10 @@ if [expr [istarget "msp430-*-*"]]  then {
     run_dump_test "preinit-array"
     run_dump_test "init-array"
     run_dump_test "fini-array"
+    run_dump_test "attr-430-small-bad"
+    run_dump_test "attr-430-small-good"
+    run_dump_test "attr-430x-large-lower-bad"
+    run_dump_test "attr-430x-large-lower-good"
+    run_dump_test "attr-430x-large-any-bad"
+    run_dump_test "attr-430x-large-any-good"
 }
index c409344df0030dbc104a81a3b1e8ebd79640ebf1..13b15f00a7165018b0c48622e3944c702624ce06 100644 (file)
@@ -1,3 +1,8 @@
+2019-10-07  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * elf/msp430.h: Add enums for MSPABI and GNU object attribute tag
+       names and values.
+
 2019-09-23  Nick Alcock  <nick.alcock@oracle.com>
 
        * ctf-api.h (ctf_cuname_set): Can now fail, returning int.
index e060804b6655a322e0eee2794de0e1a64f60411f..ce2cf5b3c7df26db93a3afd2ee1f637f2102a9d9 100644 (file)
 #define OFBA_MSPABI_Tag_ISA            4
 #define OFBA_MSPABI_Tag_Code_Model     6
 #define OFBA_MSPABI_Tag_Data_Model     8
+#define OFBA_MSPABI_Tag_enum_size      10      /* Unused by GNU.  */
+
+/* GNU Object attribute tags.  */
+enum
+{
+  /* 0-3 are generic.  */
+
+  /* Define a GNU attribute for keeping track of whether the compiler has
+     generated code assuming that the upper region could be in use.
+     Added by the assembler based on the -mdata-region option.
+     This tag is ignored unless the large memory model is in use.  */
+  Tag_GNU_MSP430_Data_Region = 4,
+};
+
+/* Object attribute values.  */
+enum
+{
+  /* Values defined for OFBA_MSPABI_Tag_ISA.  */
+  OFBA_MSPABI_Val_ISA_NONE = 0,
+  OFBA_MSPABI_Val_ISA_MSP430 = 1,
+  OFBA_MSPABI_Val_ISA_MSP430X = 2,
+
+  /* Values defined for OFBA_MSPABI_Tag_Code_Model.  */
+  OFBA_MSPABI_Val_Code_Model_NONE = 0,
+  OFBA_MSPABI_Val_Code_Model_SMALL = 1,
+  OFBA_MSPABI_Val_Code_Model_LARGE = 2,
+
+  /* Values defined for OFBA_MSPABI_Tag_Data_Model.  */
+  OFBA_MSPABI_Val_Data_Model_NONE = 0,
+  OFBA_MSPABI_Val_Data_Model_SMALL = 1,
+  OFBA_MSPABI_Val_Data_Model_LARGE = 2,
+  OFBA_MSPABI_Val_Data_Model_RESTRICTED = 3,   /* Unused by GNU.  */
+
+  /* Values defined for Tag_GNU_MSP430_Data_Region.  */
+  Val_GNU_MSP430_Data_Region_NONE = 0,
+  /* The default data region.  Assumes all data is below address 0x10000.  */
+  Val_GNU_MSP430_Data_Region_Lower = 1,
+  /* Set if -mdata-region={none,upper,either}.  Assumes
+     data could be placed at or above address 0x10000.  */
+  Val_GNU_MSP430_Data_Region_Any = 2,
+};
 
 /* Relocations.  */
 START_RELOC_NUMBERS (elf_msp430_reloc_type)
index ddec8c79ce362018d2d329926533d89d5062ce2b..a54576540880a82e6b27f212fe87f29572c77e34 100644 (file)
@@ -1,3 +1,12 @@
+2019-10-07  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * testsuite/ld-msp430-elf/attr-gnu-main.s: New test.
+       * testsuite/ld-msp430-elf/attr-gnu-obj.s: New test.
+       * testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d: New test.
+       * testsuite/ld-msp430-elf/attr-gnu-region-lower.d: New test.
+       * testsuite/ld-msp430-elf/attr-gnu-region-upper.d: New test.
+       * testsuite/ld-msp430-elf/msp430-elf.exp: Run new tests.
+
 2019-10-07  Alan Modra  <amodra@gmail.com>
 
        * ldmisc.c (vfinfo): Save and restore bfd_error around bfd
diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-main.s b/ld/testsuite/ld-msp430-elf/attr-gnu-main.s
new file mode 100644 (file)
index 0000000..e07a58c
--- /dev/null
@@ -0,0 +1,8 @@
+.text
+       .balign 2
+       .global main
+       .type   main, @function
+main:
+.L2:
+       BRA     #.L2
+       .size   main, .-main
diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-obj.s b/ld/testsuite/ld-msp430-elf/attr-gnu-obj.s
new file mode 100644 (file)
index 0000000..d256e40
--- /dev/null
@@ -0,0 +1,2 @@
+.text
+       .comm   a,2,2
diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d b/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d
new file mode 100644 (file)
index 0000000..70f8e35
--- /dev/null
@@ -0,0 +1,6 @@
+#name: prevent merging of lower and upper attributes
+#source: attr-gnu-main.s -ml -mdata-region=lower
+#source: attr-gnu-obj.s -ml -mdata-region=upper
+#ld:
+#error: .*can use the upper region for data, but.*assumes data is exclusively in lower memory.*
+#error: .*failed to merge target specific data of file.*
diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower.d b/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower.d
new file mode 100644 (file)
index 0000000..57345aa
--- /dev/null
@@ -0,0 +1,12 @@
+#source: attr-gnu-main.s -ml -mdata-region=lower
+#source: attr-gnu-obj.s -ml
+#readelf: -A
+
+Attribute Section: mspabi
+File Attributes
+  Tag_ISA: MSP430X
+  Tag_Code_Model: Large
+  Tag_Data_Model: Large
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_MSP430_Data_Region: Lower Region Only
diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-region-upper.d b/ld/testsuite/ld-msp430-elf/attr-gnu-region-upper.d
new file mode 100644 (file)
index 0000000..225968d
--- /dev/null
@@ -0,0 +1,13 @@
+#source: attr-gnu-main.s -ml -mdata-region=upper
+#source: attr-gnu-obj.s -ml -mdata-region=none
+#ld: --data-region=either
+#readelf: -A
+
+Attribute Section: mspabi
+File Attributes
+  Tag_ISA: MSP430X
+  Tag_Code_Model: Large
+  Tag_Data_Model: Large
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_MSP430_Data_Region: Any Region
index b6f3151c80dd4907b166249f11a3f9d7cf2c5fa3..08620b57ff56fdb31424856bd30487ccd5e6bcad 100644 (file)
@@ -46,6 +46,7 @@ if { ![istarget "msp430*elf*"] } {
 #     treated as a sign of an error and FAILs the test.
 #
 #
+
 set msp430regionprefixtests {
   {"Move main() to .upper.text" "-T msp430.ld --code-region=upper"
     "" "" {main-with-text-rodata.s} {{objdump -d main-text-upper.d}} "main-upper"}
@@ -162,7 +163,7 @@ set msp430warntests {
         {{ld warn-no-lower-data.r}} "warn-no-lower-data"}
 }
 
-# Don't run section shuffle tests when msp430 ISA is selected
+# Don't run further tests when msp430 ISA is selected
 if {[string match "*-mcpu=msp430 *" [board_info [target_info name] multilib_flags]]
   || [string match "*-mcpu=msp430" [board_info [target_info name] multilib_flags]]} {
     return
@@ -173,3 +174,12 @@ run_ld_link_tests $msp430eithershuffletests
 run_ld_link_tests $msp430warntests
 
 run_dump_test valid-map
+
+# Don't run data region tests if a data region is specified
+if {[string match "*-mdata-region*" [board_info [target_info name] multilib_flags]]} {
+    return
+}
+# GNU object attribute dump tests
+run_dump_test attr-gnu-region-lower
+run_dump_test attr-gnu-region-upper
+run_dump_test attr-gnu-region-lower-upper