[binutils-gdb] AVR: ld/34557 - Support .gnu_attribute to encode the size of [long] double.

Georg-Johann Lay gjl@sourceware.org
Wed Sep 2 17:56:41 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=24c9540565df85b1b51f25505d5f99bbbbd18132

commit 24c9540565df85b1b51f25505d5f99bbbbd18132
Author: Georg-Johann Lay <avr@gjlay.de>
Date:   Fri Aug 21 15:20:04 2026 +0200

    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/
            * NEWS: Mention the new avr .gnu_attribute's 8 and 12.
            * 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:
---
 bfd/elf32-avr.c                         | 75 ++++++++++++++++++++++++++++++---
 binutils/readelf.c                      | 30 ++++++++++++-
 gas/doc/as.texi                         |  6 +++
 include/elf/avr.h                       |  6 +++
 ld/NEWS                                 | 10 ++++-
 ld/testsuite/ld-avr/attr-gnu-12-0.s     |  1 +
 ld/testsuite/ld-avr/attr-gnu-12-32.d    |  8 ++++
 ld/testsuite/ld-avr/attr-gnu-12-32.s    |  1 +
 ld/testsuite/ld-avr/attr-gnu-12-32_0.d  | 11 +++++
 ld/testsuite/ld-avr/attr-gnu-12-32_64.d |  7 +++
 ld/testsuite/ld-avr/attr-gnu-12-64.s    |  1 +
 ld/testsuite/ld-avr/attr-gnu-8-0.s      |  1 +
 ld/testsuite/ld-avr/attr-gnu-8-32.d     |  8 ++++
 ld/testsuite/ld-avr/attr-gnu-8-32.s     |  1 +
 ld/testsuite/ld-avr/attr-gnu-8-32_0.d   | 11 +++++
 ld/testsuite/ld-avr/attr-gnu-8-32_64.d  |  7 +++
 ld/testsuite/ld-avr/attr-gnu-8-64.s     |  1 +
 ld/testsuite/ld-avr/attr-gnu-8_12.d     | 12 ++++++
 18 files changed, 186 insertions(+), 11 deletions(-)

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 173179fa857..7a169bb3997 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18360,10 +18360,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)
 	{
@@ -18374,6 +18378,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/NEWS b/ld/NEWS
index e52b0701add..ba88f410fbb 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,7 +1,13 @@
 -*- text -*-
 
-* The avr target supports .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS).
-  For details, see https://sourceware.org/PR34305
+* The avr target supports the following GNU attributes to make sure
+  that object files that are being linked are using the same ABI.
+  The following attributes have been added:
+  - .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS).
+    For details, see https://sourceware.org/PR34305
+  - .gnu_attribute 8 (Tag_GNU_AVR_BITS_DOUBLE).
+    .gnu_attribute 12 (Tag_GNU_AVR_BITS_LONG_DOUBLE).
+    For details, see https://sourceware.org/PR34557
 
 Changes in 2.47:
 
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


More information about the Binutils-cvs mailing list