The upcoming support for ISO/IEC TR 18037 "Embedded C" named
address spaces in G++ would allow to put C++ virtual tables
into such an address spaces, see https://gcc.gnu.org/PR69549.
The current address space used for vtables is the generic
one, which means that RAM is wasted on machines where
.rodata is located in RAM.
The TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA GCC target hook
allows to chose a custom vtable address space. However, in
contrast to current user-selectable address spaces, placing
vtables in a different address space is an ABI change, so
that a means to detect ABI violations is highly appreciated.
The feature of choice is .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS)
which would tag an object file with one of the following values:
0 (Val_GNU_AVR_VTABLE_NONE) for files that neither define nor access
vtables.
1 (Val_GNU_AVR_VTABLE_RAM) use the generic address space.
2 (Val_GNU_AVR_VTABLE_FLASH) use the 16-bit address space __flash.
3 (Val_GNU_AVR_VTABLE_FLASH1) use the 16-bit address space __flash1.
4 (Val_GNU_AVR_VTABLE_FLASH2) use the 16-bit address space __flash2.
5 (Val_GNU_AVR_VTABLE_FLASH3) use the 16-bit address space __flash3.
6 (Val_GNU_AVR_VTABLE_FLASH4) use the 16-bit address space __flash4.
7 (Val_GNU_AVR_VTABLE_FLASH5) use the 16-bit address space __flash5.
8 (Val_GNU_AVR_VTABLE_FLASHX) use the 24-bit address space __flashx.
A tag value of zero is compatible with all other tag values.
Two non-zero tag values are compatible iff they are the same.
Unknown tag values are silently accepted an treated just like
the values above so as to allow for compatibility with future
extensions.
Ok for trunk?
Johann
--
PR ld/34305
include/
* elf/avr.h (libiberty.h): Include for ARRAY_SIZE.
(Tag_GNU_AVR_VTABLE_AS = 4): New enum.
(Val_GNU_AVR_VTABLE_NONE, Val_GNU_AVR_VTABLE_RAM)
(Val_GNU_AVR_VTABLE_FLASH, Val_GNU_AVR_VTABLE_FLASH1)
(Val_GNU_AVR_VTABLE_FLASH2, Val_GNU_AVR_VTABLE_FLASH3)
(Val_GNU_AVR_VTABLE_FLASH4, Val_GNU_AVR_VTABLE_FLASH5)
(Val_GNU_AVR_VTABLE_FLASHX, Val_GNU_AVR_VTABLE_Sentinel): New
enum values for Tag_GNU_AVR_VTABLE_AS.
(avr_tag_vtable_as_name): New static function.
bfd/
* elf32-avr.h (bfd_avr_elf_merge_private_bfd_data): New proto.
* elf32-avr.c (libiberty.h): Include for ARRAY_SIZE.
(avr_elf_merge_obj_attributes): New static function.
(bfd_avr_elf_merge_private_bfd_data): New function that calls it.
(bfd_elf32_bfd_merge_private_bfd_data): Define to
bfd_avr_elf_merge_private_bfd_data.
gas/
* doc/as.texi (GNU Object Attributes) [AVR Attributes]: New subsection.
ld/
* testsuite/ld-avr/attr-gnu-4-1.s: New source.
* testsuite/ld-avr/attr-gnu-4-2.s: New source.
* testsuite/ld-avr/attr-gnu-4-1.d: New test.
* testsuite/ld-avr/attr-gnu-4-2.d: New test.
* testsuite/ld-avr/attr-gnu-4-1_2.d: New test.
binutils/
* readelf.c (display_avr_gnu_attribute): New static function.
(process_arch_specific) <EM_AVR>: Call process_attributes
with display_avr_gnu_attribute as a callback.
@@ -25,6 +25,7 @@
#include "elf-bfd.h"
#include "elf/avr.h"
#include "elf32-avr.h"
+#include "libiberty.h"
/* Enable debugging printout at stdout with this variable. */
static bool debug_relax = false;
@@ -4246,6 +4247,67 @@ avr_elf32_property_record_name (struct avr_property_record *rec)
}
+/* Merge object attributes from IBFD into OBFD. Error if there are
+ conflicting attributes. The follwing attributes are supported:
+ Tag_GNU_AVR_VTABLE_AS
+ One plus avr-g++'s named address-space for VTABLEs.
+*/
+
+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;
+
+ in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+ out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+
+ in_attr = &in_attrs[Tag_GNU_AVR_VTABLE_AS];
+ out_attr = &out_attrs[Tag_GNU_AVR_VTABLE_AS];
+
+ if (in_attr->i == Val_GNU_AVR_VTABLE_NONE
+ || out_attr->i == Val_GNU_AVR_VTABLE_NONE)
+ {
+ if (in_attr->i != Val_GNU_AVR_VTABLE_NONE)
+ {
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+ out_attr->i = in_attr->i;
+ last_fp = ibfd;
+ }
+ }
+ else if (in_attr->i != out_attr->i)
+ {
+ const char *const tag = "Tag_GNU_AVR_VTABLE_AS";
+ 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);
+
+ out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ // Merge any common GNU attributes.
+ return _bfd_elf_merge_object_attributes (ibfd, info);
+}
+
+
+/* Merge backend specific data from an object file to the output
+ object file when linking. */
+
+bool bfd_avr_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
+{
+ return avr_elf_merge_obj_attributes (ibfd, info);
+}
+
+
#define ELF_ARCH bfd_arch_avr
#define ELF_TARGET_ID AVR_ELF_DATA
#define ELF_MACHINE_CODE EM_AVR
@@ -4270,6 +4332,8 @@ avr_elf32_property_record_name (struct avr_property_record *rec)
#define bfd_elf32_bfd_get_relocated_section_contents \
elf32_avr_get_relocated_section_contents
#define bfd_elf32_new_section_hook elf_avr_new_section_hook
+#define bfd_elf32_bfd_merge_private_bfd_data \
+ bfd_avr_elf_merge_private_bfd_data
#define elf_backend_special_sections elf_avr_special_sections
#include "elf32-target.h"
@@ -36,6 +36,9 @@ elf32_avr_size_stubs (bfd *, struct bfd_link_info *, bool);
extern bool
elf32_avr_build_stubs (struct bfd_link_info *);
+extern bool
+bfd_avr_elf_merge_private_bfd_data (bfd *, struct bfd_link_info *);
+
/* The name of the section into which the property records are stored. */
#define AVR_PROPERTY_RECORD_SECTION_NAME ".avr.prop"
@@ -18249,6 +18249,30 @@ display_arm_attribute (unsigned char * p,
return display_tag_value (tag, p, end);
}
+static unsigned char *
+display_avr_gnu_attribute (unsigned char * p,
+ unsigned int tag,
+ const unsigned char * const end)
+{
+ if (tag == Tag_GNU_AVR_VTABLE_AS)
+ {
+ unsigned int val;
+
+ printf (" Tag_GNU_AVR_VTABLE_AS (%u): ", tag);
+ if (p == end)
+ {
+ printf (_("<corrupt>\n"));
+ return p;
+ }
+
+ READ_ULEB (val, p, end);
+ printf ("%d (%s)\n", val, avr_tag_vtable_as_name (val));
+ return p;
+ }
+
+ return display_tag_value (tag & 1, p, end);
+}
+
static unsigned char *
display_gnu_attribute (unsigned char * p,
unsigned char * (* display_proc_gnu_attribute)
@@ -23449,7 +23473,9 @@ process_arch_specific (Filedata * filedata)
return process_attributes (filedata, "aeabi", SHT_ARM_ATTRIBUTES,
display_arm_attribute,
display_generic_attribute);
-
+ case EM_AVR:
+ return process_attributes (filedata, NULL, SHT_GNU_ATTRIBUTES, NULL,
+ display_avr_gnu_attribute);
case EM_MIPS:
case EM_MIPS_RS3_LE:
return process_mips_specific (filedata);
@@ -8000,6 +8000,25 @@ than 1, the file can only be processed by other toolchains under some private
arrangement indicated by the flag value and the vendor name.
@end table
+@subsection AVR Attributes
+
+@table @r
+@item Tag_GNU_AVR_VTABLE_AS (4)
+The @uref{https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html#AVR-Named-Address-Spaces,,named address space}
+for C++ virtual tables used by this object file:
+@itemize @bullet
+@item 0 for files that neither define nor access virtual tables.
+@item 1 for files that use the generic address space.
+@item 2 for files that use the 16-bit address space @code{__flash}.
+@item 3 for files that use the 16-bit address space @code{__flash1}.
+@item 4 for files that use the 16-bit address space @code{__flash2}.
+@item 5 for files that use the 16-bit address space @code{__flash3}.
+@item 6 for files that use the 16-bit address space @code{__flash4}.
+@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
+@end table
+
@subsection M680x0 Attributes
@table @r
@@ -22,6 +22,7 @@
#define _ELF_AVR_H
#include "elf/reloc-macros.h"
+#include "libiberty.h" // ARRAY_SIZE
/* Processor specific flags for the ELF header e_flags field. */
#define EF_AVR_MACH 0x7F
@@ -90,4 +91,76 @@ START_RELOC_NUMBERS (elf_avr_reloc_type)
RELOC_NUMBER (R_AVR_32_PCREL, 36)
END_RELOC_NUMBERS (R_AVR_max)
+
+// Object attribute tags.
+enum
+{
+ // 0-3 are generic.
+
+ // VTABLE is located in some named address space.
+ Tag_GNU_AVR_VTABLE_AS = 4,
+};
+
+
+// Object attribute values.
+enum
+{
+ // There's no VTABLE instance or VTABLE access in the ojbect file.
+ Val_GNU_AVR_VTABLE_NONE = 0,
+
+ // When the module hosts or reads a VTABLE, then Tag_GNU_AVR_VTABLE_AS is
+ // one plus AVR GCC's address space enum from <GCC>/gcc/config/avr/avr.h.
+
+ // VTABLE is located in AS0, the generic address space (RAM).
+ // This includes .rodata. */
+ Val_GNU_AVR_VTABLE_RAM = 0 + 1,
+
+ // __flash: 16-bit flash in 0x0 -- 0xffff.
+ Val_GNU_AVR_VTABLE_FLASH = 1 + 1,
+
+ // __flash1: 16-bit flash in 0x10000 -- 0x1ffff.
+ Val_GNU_AVR_VTABLE_FLASH1 = 2 + 1,
+
+ // __flash2: 16-bit flash in 0x20000 -- 0x2ffff.
+ Val_GNU_AVR_VTABLE_FLASH2 = 3 + 1,
+
+ // __flash3: 16-bit flash in 0x30000 -- 0x3ffff.
+ Val_GNU_AVR_VTABLE_FLASH3 = 4 + 1,
+
+ // __flash4: 16-bit flash in 0x40000 -- 0x4ffff.
+ Val_GNU_AVR_VTABLE_FLASH4 = 5 + 1,
+
+ // __flash5: 16-bit flash in 0x50000 -- 0x5ffff.
+ Val_GNU_AVR_VTABLE_FLASH5 = 6 + 1,
+
+ // __flashx: 24-bit flash.
+ Val_GNU_AVR_VTABLE_FLASHX = 7 + 1,
+
+ Val_GNU_AVR_VTABLE_Sentinel
+};
+
+
+// Map Tag_GNU_AVR_VTABLE_AS to a static string for diagnostics.
+
+static inline const char *
+avr_tag_vtable_as_name (int tag)
+{
+ switch (tag)
+ {
+ default:
+ break;
+ case Val_GNU_AVR_VTABLE_NONE: return "no vtables";
+ case Val_GNU_AVR_VTABLE_RAM: return "generic address space";
+ case Val_GNU_AVR_VTABLE_FLASH: return "__flash";
+ case Val_GNU_AVR_VTABLE_FLASH1: return "__flash1";
+ case Val_GNU_AVR_VTABLE_FLASH2: return "__flash2";
+ case Val_GNU_AVR_VTABLE_FLASH3: return "__flash3";
+ case Val_GNU_AVR_VTABLE_FLASH4: return "__flash4";
+ case Val_GNU_AVR_VTABLE_FLASH5: return "__flash5";
+ case Val_GNU_AVR_VTABLE_FLASHX: return "__flashx";
+ }
+
+ return "<unknown>";
+}
+
#endif /* _ELF_AVR_H */
new file mode 100644
@@ -0,0 +1,8 @@
+#name: AVR Tag_AVR_GNU_VTABLE_AS 1
+#source: attr-gnu-4-1.s
+#readelf: -A
+#target: avr-*-*
+
+Attribute Section: gnu
+File Attributes
+ Tag_GNU_AVR_VTABLE_AS \(4\): 1 \(generic address space\)
new file mode 100644
@@ -0,0 +1 @@
+.gnu_attribute 4,1
new file mode 100644
@@ -0,0 +1,7 @@
+#name: AVR Tag_AVR_GNU_VTABLE_AS conflict
+#source: attr-gnu-4-1.s
+#source: attr-gnu-4-2.s
+#as:
+#ld:
+#target: avr-*-*
+#error: failed to merge target specific data of file
new file mode 100644
@@ -0,0 +1,8 @@
+#name: AVR Tag_AVR_GNU_VTABLE_AS 2
+#source: attr-gnu-4-2.s
+#readelf: -A
+#target: avr-*-*
+
+Attribute Section: gnu
+File Attributes
+ Tag_GNU_AVR_VTABLE_AS \(4\): 2 \(__flash\)
new file mode 100644
@@ -0,0 +1 @@
+.gnu_attribute 4,2