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