Re: [patch, ping, pushed] AVR: Add support for .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS)

Georg-Johann Lay via Binutils <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=8818c47980038800239da822cfef2aa63e0fac1f

Approved here: 
https://gcc.gnu.org/pipermail/gcc-patches/2026-August/727700.html

There was quite some internal changes in the generic .gnu-attribute
handling, so that the applied patch needed some more adjustments,
see the attached patch.

Johann

--

Am 11.08.26 um 17:04 schrieb Georg-Johann Lay via Binutils:
> Ping: https://sourceware.org/pipermail/binutils/2026-July/149967.html
> 
> 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.
binutils-attr-gnu-vtable-as-v3.diff (text/x-patch, 17 KB)
    AVR: Add support for .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS).
    
    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.
    
            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/
            * configure.ac (tb) [avr_elf32_vec]: Add elf-attrs.lo.
            * configure: Rebuild.
            * 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/
            * configure.ac (extra_objects) [avr]: Add config/obj-elf-attr.o.
            * configure: Rebuild.
            * config/tc-avr.h (TC_OBJ_ATTR_v1): Define to 1.
            * doc/as.texi (GNU Object Attributes) [AVR Attributes]: New subsection.
            * NEWS: Mention PR34305.
    
    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.
            * NEWS: Mention PR34305.
    
    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.

diff --git a/bfd/configure b/bfd/configure
index 12d43a5aeae..a4326160c57 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -15892,7 +15892,7 @@ do
     arm_pei_wince_be_vec)	 tb="$tb pei-arm-wince.lo pei-arm.lo peigen.lo $coff" ;;
     arm_pei_wince_le_vec)	 tb="$tb pei-arm-wince.lo pei-arm.lo peigen.lo $coff" ;;
     arm_mach_o_vec)		 tb="$tb mach-o-arm.lo" ;;
-    avr_elf32_vec)		 tb="$tb elf32-avr.lo elf32.lo $elf" ;;
+    avr_elf32_vec)		 tb="$tb elf32-avr.lo elf32.lo elf-attrs.lo $elf" ;;
     bfin_elf32_vec)		 tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
     bfin_elf32_fdpic_vec)	 tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
     cr16_elf32_vec)		 tb="$tb elf32-cr16.lo elf32.lo $elf" ;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index ee335f75dd9..8c71af69237 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -433,7 +433,7 @@ do
     arm_pei_wince_be_vec)	 tb="$tb pei-arm-wince.lo pei-arm.lo peigen.lo $coff" ;;
     arm_pei_wince_le_vec)	 tb="$tb pei-arm-wince.lo pei-arm.lo peigen.lo $coff" ;;
     arm_mach_o_vec)		 tb="$tb mach-o-arm.lo" ;;
-    avr_elf32_vec)		 tb="$tb elf32-avr.lo elf32.lo $elf" ;;
+    avr_elf32_vec)		 tb="$tb elf32-avr.lo elf32.lo elf-attrs.lo $elf" ;;
     bfin_elf32_vec)		 tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
     bfin_elf32_fdpic_vec)	 tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
     cr16_elf32_vec)		 tb="$tb elf32-cr16.lo elf32.lo $elf" ;;
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c
index f2d9bdc7501..1d0298d57c3 100644
--- a/bfd/elf32-avr.c
+++ b/bfd/elf32-avr.c
@@ -26,6 +26,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;
@@ -4097,6 +4098,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
@@ -4121,6 +4183,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"
diff --git a/bfd/elf32-avr.h b/bfd/elf32-avr.h
index 93b872579fe..2b9079bc11e 100644
--- a/bfd/elf32-avr.h
+++ b/bfd/elf32-avr.h
@@ -29,6 +29,9 @@ extern int elf32_avr_setup_section_lists (bfd *, struct bfd_link_info *);
 extern bool 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"
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5d924a49675..b5ccc675af6 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18365,6 +18365,30 @@ display_arm_attribute (const unsigned char * p,
   return display_tag_value (tag, p, end);
 }
 
+static const unsigned char *
+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;
+
+      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 const unsigned char *
 display_gnu_attribute (const unsigned char * p,
 		       const unsigned char * (* display_proc_gnu_attribute)
@@ -24167,6 +24191,10 @@ process_arch_specific (Filedata * filedata)
       return process_attributes_v2 (filedata, "aeabi", SHT_AARCH64_ATTRIBUTES,
 				    display_aarch64_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, false);
diff --git a/gas/NEWS b/gas/NEWS
index 165e23361bb..70cfbf41a7a 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* The avr target supports .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS).
+  For details, see https://sourceware.org/PR34305
+
 Changes in 2.47:
 
 * New command line option --reloc-section-sym=[all|internal|none]
diff --git a/gas/config/tc-avr.h b/gas/config/tc-avr.h
index d047546c393..4b197e6d814 100644
--- a/gas/config/tc-avr.h
+++ b/gas/config/tc-avr.h
@@ -251,3 +251,6 @@ extern const char *avr_line_separator_chars;
 
 #define tc_fix_adjustable(FIX) avr_fix_adjustable (FIX)
 extern bool avr_fix_adjustable (struct fix *);
+
+/* The target supports Object Attributes v1.  */
+#define TC_OBJ_ATTR_v1 1
diff --git a/gas/configure b/gas/configure
index 3b120d3f441..8afaf2729ed 100755
--- a/gas/configure
+++ b/gas/configure
@@ -12717,7 +12717,7 @@ _ACEOF
 
     # Does the target support Object Attributes ?
     case ${cpu_type} in
-      aarch64* | arc* | arm* | csky | loongarch | m68k | mips* | msp430 \
+      aarch64* | arc* | arm* | avr | csky | loongarch | m68k | mips* | msp430 \
       | ppc* | riscv* | s390* | sparc* | tic6x)
 	for f in config/obj-elf-attr.o; do
 	  case " $extra_objects " in
diff --git a/gas/configure.ac b/gas/configure.ac
index 69547f5ffb9..4dc7c019ce2 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -443,7 +443,7 @@ changequote([,])dnl
 
     # Does the target support Object Attributes ?
     case ${cpu_type} in
-      aarch64* | arc* | arm* | csky | loongarch | m68k | mips* | msp430 \
+      aarch64* | arc* | arm* | avr | csky | loongarch | m68k | mips* | msp430 \
       | ppc* | riscv* | s390* | sparc* | tic6x)
 	for f in config/obj-elf-attr.o; do
 	  case " $extra_objects " in
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 5d7772d62d3..eaa10f42bc9 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -8100,6 +8100,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
diff --git a/include/elf/avr.h b/include/elf/avr.h
index 4d9b15a453a..23f21ecec15 100644
--- a/include/elf/avr.h
+++ b/include/elf/avr.h
@@ -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 */
diff --git a/ld/NEWS b/ld/NEWS
index 53394fee430..e52b0701add 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* The avr target supports .gnu_attribute 4 (Tag_GNU_AVR_VTABLE_AS).
+  For details, see https://sourceware.org/PR34305
+
 Changes in 2.47:
 
 * Add a linker optimization level of zero.  Using "-O 0" on the linker command
diff --git a/ld/testsuite/ld-avr/attr-gnu-4-1.d b/ld/testsuite/ld-avr/attr-gnu-4-1.d
new file mode 100644
index 00000000000..461db4f8e92
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-4-1.d
@@ -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\)
diff --git a/ld/testsuite/ld-avr/attr-gnu-4-1.s b/ld/testsuite/ld-avr/attr-gnu-4-1.s
new file mode 100644
index 00000000000..e985a56f6b1
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-4-1.s
@@ -0,0 +1 @@
+.gnu_attribute 4,1
diff --git a/ld/testsuite/ld-avr/attr-gnu-4-1_2.d b/ld/testsuite/ld-avr/attr-gnu-4-1_2.d
new file mode 100644
index 00000000000..5e7ea5c667e
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-4-1_2.d
@@ -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
diff --git a/ld/testsuite/ld-avr/attr-gnu-4-2.d b/ld/testsuite/ld-avr/attr-gnu-4-2.d
new file mode 100644
index 00000000000..2a823c1b280
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-4-2.d
@@ -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\)
diff --git a/ld/testsuite/ld-avr/attr-gnu-4-2.s b/ld/testsuite/ld-avr/attr-gnu-4-2.s
new file mode 100644
index 00000000000..54ebf4ed8dd
--- /dev/null
+++ b/ld/testsuite/ld-avr/attr-gnu-4-2.s
@@ -0,0 +1 @@
+.gnu_attribute 4,2
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.