AVR: Support .gnu_attribute to encode the size of [long] double

Georg-Johann Lay via Binutils <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
AVR GCC allows to chose the size of double and long double at
compile time by means of -m[long-]double={32|64}.  As these
options select a different ABI, Binutils should complain when
an attempt is being made to link incompatible object files.

This patch adds
    .gnu_attribute 8 (Tag_GNU_AVR_BITS_DOUBLE)
    .gnu_attribute 12 (Tag_GNU_AVR_BITS_LONG_DOUBLE)
and some simple test cases.

A tag value of 0 is compatible with all other tag values.
Two non-zero tag values are compatible iff they are the same.

Ok for trunk?

Johann

--

	PR ld/34557
include/
	* elf/avr.h (Tag_GNU_AVR_BITS_DOUBLE = 8)
	(Tag_GNU_AVR_BITS_LONG_DOUBLE = 12): Define new enum values.
bfd/
	* elf32-avr.c (avr_elf_merge_obj_attributes): Support
	Tag_GNU_AVR_BITS_DOUBLE, Tag_GNU_AVR_BITS_LONG_DOUBLE.
binutils/
	* readelf.c (display_avr_gnu_attribute): Support
	Tag_GNU_AVR_BITS_DOUBLE, Tag_GNU_AVR_BITS_LONG_DOUBLE.
gas/
	* doc/as.texi (AVR Attributes): Document
	Tag_GNU_AVR_BITS_DOUBLE, Tag_GNU_AVR_BITS_LONG_DOUBLE.
ld/
	* testsuite/ld-avr/attr-gnu-8-0.s: New file.
	* testsuite/ld-avr/attr-gnu-8-32.s: New file.
	* testsuite/ld-avr/attr-gnu-8-64.s: New file.
	* testsuite/ld-avr/attr-gnu-8-32.d: New test.
	* testsuite/ld-avr/attr-gnu-8-32_0.d: New test.
	* testsuite/ld-avr/attr-gnu-8-32_64.d: New test.
	* testsuite/ld-avr/attr-gnu-8_12.d: New test.
	* testsuite/ld-avr/attr-gnu-12-0.s: New file.
	* testsuite/ld-avr/attr-gnu-12-64.s: New file.
	* testsuite/ld-avr/attr-gnu-12-32.s: New file.
	* testsuite/ld-avr/attr-gnu-12-32.d: New test.
	* testsuite/ld-avr/attr-gnu-12-32_0.d: New test.
	* testsuite/ld-avr/attr-gnu-12-32_64.d: New test.
binutils-attr-double.diff (text/x-patch, 11.8 KB)
    AVR: ld/34557 - Support .gnu_attribute to encode the size of [long] double.
    
    AVR GCC allows to chose the size of double and long double at
    compile time by means of -m[long-]double={32|64}.  As these
    options select a different ABI, Binutils should complain when
    an attempt is being made to link incompatible object files.
    
    This patch adds
       .gnu_attribute 8 (Tag_GNU_AVR_BITS_DOUBLE)
       .gnu_attribute 12 (Tag_GNU_AVR_BITS_LONG_DOUBLE)
    and some simple test cases.
    
    A tag value of 0 is compatible with all other tag values.
    Two non-zero tag values are compatible iff they are the same.
    
            PR ld/34557
    include/
            * elf/avr.h (Tag_GNU_AVR_BITS_DOUBLE = 8)
            (Tag_GNU_AVR_BITS_LONG_DOUBLE = 12): Define new enum values.
    bfd/
            * elf32-avr.c (avr_elf_merge_obj_attributes): Support
            Tag_GNU_AVR_BITS_DOUBLE, Tag_GNU_AVR_BITS_LONG_DOUBLE.
    binutils/
            * readelf.c (display_avr_gnu_attribute): Support
            Tag_GNU_AVR_BITS_DOUBLE, Tag_GNU_AVR_BITS_LONG_DOUBLE.
    gas/
            * doc/as.texi (AVR Attributes): Document
            Tag_GNU_AVR_BITS_DOUBLE, Tag_GNU_AVR_BITS_LONG_DOUBLE.
    ld/
            * testsuite/ld-avr/attr-gnu-8-0.s: New file.
            * testsuite/ld-avr/attr-gnu-8-32.s: New file.
            * testsuite/ld-avr/attr-gnu-8-64.s: New file.
            * testsuite/ld-avr/attr-gnu-8-32.d: New test.
            * testsuite/ld-avr/attr-gnu-8-32_0.d: New test.
            * testsuite/ld-avr/attr-gnu-8-32_64.d: New test.
            * testsuite/ld-avr/attr-gnu-8_12.d: New test.
            * testsuite/ld-avr/attr-gnu-12-0.s: New file.
            * testsuite/ld-avr/attr-gnu-12-64.s: New file.
            * testsuite/ld-avr/attr-gnu-12-32.s: New file.
            * testsuite/ld-avr/attr-gnu-12-32.d: New test.
            * testsuite/ld-avr/attr-gnu-12-32_0.d: New test.
            * testsuite/ld-avr/attr-gnu-12-32_64.d: New test.

diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c
index 929a2fe2519..3cc79adec68 100644
--- a/bfd/elf32-avr.c
+++ b/bfd/elf32-avr.c
@@ -4200,7 +4200,6 @@ avr_elf32_property_record_name (struct avr_property_record *rec)
 static bool
 avr_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
-  static bfd *last_fp;
   obj_attribute *in_attr, *in_attrs;
   obj_attribute *out_attr, *out_attrs;
   bfd *obfd = info->output_bfd;
@@ -4208,6 +4207,9 @@ avr_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
   out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
 
+  // Merge Tag_GNU_AVR_VTABLE_AS (4).
+
+  static bfd *last_fp_vtab;
   in_attr = &in_attrs[Tag_GNU_AVR_VTABLE_AS];
   out_attr = &out_attrs[Tag_GNU_AVR_VTABLE_AS];
 
@@ -4218,7 +4220,7 @@ avr_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 	{
 	  out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
 	  out_attr->i = in_attr->i;
-	  last_fp = ibfd;
+	  last_fp_vtab = ibfd;
 	}
     }
   else if (in_attr->i != out_attr->i)
@@ -4227,11 +4229,70 @@ avr_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
       const char *const iname = avr_tag_vtable_as_name (in_attr->i);
       const char *const oname = avr_tag_vtable_as_name (out_attr->i);
 
-      _bfd_error_handler
-	/* xgettext:c-format */
-	(_("%pB uses %s tag %d (%s), %pB uses %s tag %d (%s)"),
-	 ibfd, tag, in_attr->i, iname,
-	 last_fp, tag, out_attr->i, oname);
+      // xgettext:c-format
+      _bfd_error_handler (_("%pB uses %s tag %d (%s), %pB uses %s tag %d (%s)"),
+			  ibfd, tag, in_attr->i, iname,
+			  last_fp_vtab, tag, out_attr->i, oname);
+
+      out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+    }
+
+  // Merge Tag_GNU_AVR_BITS_DOUBLE (8).
+
+  static bfd *last_fp_dbl;
+  in_attr = &in_attrs[Tag_GNU_AVR_BITS_DOUBLE];
+  out_attr = &out_attrs[Tag_GNU_AVR_BITS_DOUBLE];
+
+  if (in_attr->i == 0
+      || out_attr->i == 0)
+    {
+      if (in_attr->i != 0)
+	{
+	  out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+	  out_attr->i = in_attr->i;
+	  last_fp_dbl = ibfd;
+	}
+    }
+  else if (in_attr->i != out_attr->i)
+    {
+      const char *const tag = "Tag_GNU_AVR_BITS_DOUBLE";
+
+      // xgettext:c-format
+      _bfd_error_handler (_("%pB uses %s tag %d, %pB uses %s tag %d"),
+			  ibfd, tag, in_attr->i,
+			  last_fp_dbl, tag, out_attr->i);
+
+      out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+    }
+
+  // Merge Tag_GNU_AVR_BITS_LONG_DOUBLE (12).
+
+  static bfd *last_fp_ldbl;
+  in_attr = &in_attrs[Tag_GNU_AVR_BITS_LONG_DOUBLE];
+  out_attr = &out_attrs[Tag_GNU_AVR_BITS_LONG_DOUBLE];
+
+  if (in_attr->i == 0
+      || out_attr->i == 0)
+    {
+      if (in_attr->i != 0)
+	{
+	  out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+	  out_attr->i = in_attr->i;
+	  last_fp_ldbl = ibfd;
+	}
+    }
+  else if (in_attr->i != out_attr->i)
+    {
+      const char *const tag = "Tag_GNU_AVR_BITS_LONG_DOUBLE";
+
+      // xgettext:c-format
+      _bfd_error_handler (_("%pB uses %s tag %d, %pB uses %s tag %d"),
+			  ibfd, tag, in_attr->i,
+			  last_fp_ldbl, tag, out_attr->i);
 
       out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
       bfd_set_error (bfd_error_bad_value);
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b5ccc675af6..2b594d632fa 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18370,10 +18370,14 @@ display_avr_gnu_attribute (const unsigned char * p,
 			   unsigned int tag,
 			   const unsigned char * const end)
 {
-  if (tag == Tag_GNU_AVR_VTABLE_AS)
+  unsigned int val;
+
+  switch (tag)
     {
-      unsigned int val;
+    default:
+      break;
 
+    case Tag_GNU_AVR_VTABLE_AS:
       printf ("  Tag_GNU_AVR_VTABLE_AS (%u): ", tag);
       if (p == end)
 	{
@@ -18384,6 +18388,28 @@ display_avr_gnu_attribute (const unsigned char * p,
       READ_ULEB (val, p, end);
       printf ("%d (%s)\n", val, avr_tag_vtable_as_name (val));
       return p;
+
+    case Tag_GNU_AVR_BITS_DOUBLE:
+      printf ("  Tag_GNU_AVR_BITS_DOUBLE (%u): ", tag);
+      if (p == end)
+	printf (_("<corrupt>\n"));
+      else
+	{
+	  READ_ULEB (val, p, end);
+	  printf ("%d\n", val);
+	}
+      return p;
+
+    case Tag_GNU_AVR_BITS_LONG_DOUBLE:
+      printf ("  Tag_GNU_AVR_BITS_LONG_DOUBLE (%u): ", tag);
+      if (p == end)
+	printf (_("<corrupt>\n"));
+      else
+	{
+	  READ_ULEB (val, p, end);
+	  printf ("%d\n", val);
+	}
+      return p;
     }
 
   return display_tag_value (tag & 1, p, end);
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index ebe23da340a..2cf4bdfe610 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -8117,6 +8117,12 @@ for C++ virtual tables used by this object file:
 @item 7 for files that use the 16-bit address space @code{__flash5}.
 @item 8 for files that use the 24-bit address space @code{__flashx}.
 @end itemize
+
+@item Tag_GNU_AVR_BITS_DOUBLE (8)
+Bit size of the @code{double} type, or 0 if no @code{double} is used.
+
+@item Tag_GNU_AVR_BITS_LONG_DOUBLE (12)
+Bit size of the @code{long double} type, or 0 if no @code{long double} is used.
 @end table
 
 @subsection M680x0 Attributes
diff --git a/include/elf/avr.h b/include/elf/avr.h
index 23f21ecec15..1b7cdb648bc 100644
--- a/include/elf/avr.h
+++ b/include/elf/avr.h
@@ -99,6 +99,12 @@ enum
 
   // VTABLE is located in some named address space.
   Tag_GNU_AVR_VTABLE_AS = 4,
+
+  // Bits used by the double type, or 0 if no see.
+  Tag_GNU_AVR_BITS_DOUBLE = 8,
+
+  // Bits used by the long double type, or 0 if no see.
+  Tag_GNU_AVR_BITS_LONG_DOUBLE = 12,
 };
 
 
diff --git a/ld/testsuite/ld-avr/attr-gnu-12-0.s b/ld/testsuite/ld-avr/attr-gnu-12-0.s
new file mode 100644
index 00000000000..9486de20476
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-12-0.s
@@ -0,0 +1 @@
+.gnu_attribute 12,0
diff --git a/ld/testsuite/ld-avr/attr-gnu-12-32.d b/ld/testsuite/ld-avr/attr-gnu-12-32.d
new file mode 100644
index 00000000000..5843e18bdee
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-12-32.d
@@ -0,0 +1,8 @@
+#name: AVR Tag_AVR_GNU_BITS_LONG_DOUBLE 32
+#source: attr-gnu-12-32.s
+#readelf: -A
+#target: avr-*-*
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_AVR_BITS_LONG_DOUBLE \(12\): 32
diff --git a/ld/testsuite/ld-avr/attr-gnu-12-32.s b/ld/testsuite/ld-avr/attr-gnu-12-32.s
new file mode 100644
index 00000000000..ce87ca76660
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-12-32.s
@@ -0,0 +1 @@
+.gnu_attribute 12,32
diff --git a/ld/testsuite/ld-avr/attr-gnu-12-32_0.d b/ld/testsuite/ld-avr/attr-gnu-12-32_0.d
new file mode 100644
index 00000000000..114823957ba
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-12-32_0.d
@@ -0,0 +1,11 @@
+#name: AVR Tag_AVR_GNU_BITS_LONG_DOUBLE 32 + 0
+#source: attr-gnu-12-32.s
+#source: attr-gnu-12-0.s
+#as:
+#ld:
+#readelf: -A
+#target: avr-*-*
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_AVR_BITS_LONG_DOUBLE \(12\): 32
diff --git a/ld/testsuite/ld-avr/attr-gnu-12-32_64.d b/ld/testsuite/ld-avr/attr-gnu-12-32_64.d
new file mode 100644
index 00000000000..689d8036fbe
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-12-32_64.d
@@ -0,0 +1,7 @@
+#name: AVR Tag_AVR_GNU_BITS_LONG_DOUBLE conflict
+#source: attr-gnu-12-32.s
+#source: attr-gnu-12-64.s
+#as:
+#ld:
+#target: avr-*-*
+#error: failed to merge target specific data of file
diff --git a/ld/testsuite/ld-avr/attr-gnu-12-64.s b/ld/testsuite/ld-avr/attr-gnu-12-64.s
new file mode 100644
index 00000000000..883d0c791a2
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-12-64.s
@@ -0,0 +1 @@
+.gnu_attribute 12,64
diff --git a/ld/testsuite/ld-avr/attr-gnu-8-0.s b/ld/testsuite/ld-avr/attr-gnu-8-0.s
new file mode 100644
index 00000000000..b28c578da07
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-8-0.s
@@ -0,0 +1 @@
+.gnu_attribute 8,0
diff --git a/ld/testsuite/ld-avr/attr-gnu-8-32.d b/ld/testsuite/ld-avr/attr-gnu-8-32.d
new file mode 100644
index 00000000000..47918d379db
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-8-32.d
@@ -0,0 +1,8 @@
+#name: AVR Tag_AVR_GNU_BITS_DOUBLE 32
+#source: attr-gnu-8-32.s
+#readelf: -A
+#target: avr-*-*
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_AVR_BITS_DOUBLE \(8\): 32
diff --git a/ld/testsuite/ld-avr/attr-gnu-8-32.s b/ld/testsuite/ld-avr/attr-gnu-8-32.s
new file mode 100644
index 00000000000..6bfa47d0bda
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-8-32.s
@@ -0,0 +1 @@
+.gnu_attribute 8,32
diff --git a/ld/testsuite/ld-avr/attr-gnu-8-32_0.d b/ld/testsuite/ld-avr/attr-gnu-8-32_0.d
new file mode 100644
index 00000000000..345b1add438
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-8-32_0.d
@@ -0,0 +1,11 @@
+#name: AVR Tag_AVR_GNU_BITS_DOUBLE 32 + 0
+#source: attr-gnu-8-32.s
+#source: attr-gnu-8-0.s
+#as:
+#ld:
+#readelf: -A
+#target: avr-*-*
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_AVR_BITS_DOUBLE \(8\): 32
diff --git a/ld/testsuite/ld-avr/attr-gnu-8-32_64.d b/ld/testsuite/ld-avr/attr-gnu-8-32_64.d
new file mode 100644
index 00000000000..3e780858661
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-8-32_64.d
@@ -0,0 +1,7 @@
+#name: AVR Tag_AVR_GNU_BITS_DOUBLE conflict
+#source: attr-gnu-8-32.s
+#source: attr-gnu-8-64.s
+#as:
+#ld:
+#target: avr-*-*
+#error: failed to merge target specific data of file
diff --git a/ld/testsuite/ld-avr/attr-gnu-8-64.s b/ld/testsuite/ld-avr/attr-gnu-8-64.s
new file mode 100644
index 00000000000..34141651524
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-8-64.s
@@ -0,0 +1 @@
+.gnu_attribute 8,64
diff --git a/ld/testsuite/ld-avr/attr-gnu-8_12.d b/ld/testsuite/ld-avr/attr-gnu-8_12.d
new file mode 100644
index 00000000000..f35f9e48d61
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-8_12.d
@@ -0,0 +1,12 @@
+#name: AVR Tag_AVR_GNU_BITS DOUBLE + LONG_DOUBLE
+#source: attr-gnu-8-32.s
+#source: attr-gnu-12-64.s
+#as:
+#ld:
+#readelf: -A
+#target: avr-*-*
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_AVR_BITS_DOUBLE \(8\): 32
+  Tag_GNU_AVR_BITS_LONG_DOUBLE \(12\): 64
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.