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 (_("\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 (_("\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