]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
AVR: Support .rodata in Flash for AVR64* and AVR128* Devices.
authorGeorg-Johann Lay <avr@gjlay.de>
Thu, 11 Jan 2024 21:11:25 +0000 (22:11 +0100)
committerGeorg-Johann Lay <avr@gjlay.de>
Sun, 14 Jan 2024 18:11:24 +0000 (19:11 +0100)
These devices see a 32 KiB block of their program memory (flash) in
the RAM address space.  This can be used to support .rodata in flash
provided Binutils support PR31124 (Add new emulations which locate
.rodata in flash).  This patch does the following:

* configure checks availability of Binutils PR31124.

* Add new command line options -mrodata-in-ram and -mflmap.
While -flmap is for internal usage (communicate hardware properties
from device-specs to the compiler proper), -mrodata-in-ram is a user
space option that allows to return to the current rodata-in-ram layout.

* Adjust gen-avr-mmcu-specs.cc so that device-specs are generated
that sanity check options, and that translate -m[no-]rodata-in-ram
to its emulation.

* Objects in .rodata don't drag __do_copy_data.

* Document new options and built-in macros.

PR target/112944

gcc/
* configure.ac [target=avr]: Check availability of emulations
avrxmega2_flmap and avrxmega4_flmap, resulting in new config vars
HAVE_LD_AVR_AVRXMEGA2_FLMAP and HAVE_LD_AVR_AVRXMEGA4_FLMAP.
* configure: Regenerate.
* config.in: Regenerate.
* doc/invoke.texi (AVR Options): Document -mflmap, -mrodata-in-ram,
__AVR_HAVE_FLMAP__, __AVR_RODATA_IN_RAM__.

* config/avr/avr.opt (-mflmap, -mrodata-in-ram): New options.
* config/avr/avr-arch.h (enum avr_device_specific_features):
Add AVR_ISA_FLMAP.
* config/avr/avr-mcus.def (AVR_MCU) [avr64*, avr128*]: Set isa flag
AVR_ISA_FLMAP.
* config/avr/avr.cc (avr_arch_index, avr_has_rodata_p): New vars.
(avr_set_core_architecture): Set avr_arch_index.
(have_avrxmega2_flmap, have_avrxmega4_flmap)
(have_avrxmega3_rodata_in_flash): Set new static const bool according
to configure results.
(avr_rodata_in_flash_p): New function using them.
(avr_asm_init_sections): Let readonly_data_section->unnamed.callback
track avr_need_copy_data_p only if not avr_rodata_in_flash_p().
(avr_asm_named_section): Track avr_has_rodata_p.
(avr_file_end): Emit __do_copy_data also when avr_has_rodata_p
and not avr_rodata_in_flash_p ().
* config/avr/specs.h (CC1_SPEC): Add %(cc1_rodata_in_ram).
(LINK_SPEC): Add %(link_rodata_in_ram).
(LINK_ARCH_SPEC): Remove.
* config/avr/gen-avr-mmcu-specs.cc (have_avrxmega3_rodata_in_flash)
(have_avrxmega2_flmap, have_avrxmega4_flmap): Set new static
const bool according to configure results.
(diagnose_mrodata_in_ram): New function.
(print_mcu): Generate specs with the following changes:
<*cc1_misc, *asm_misc, *link_misc>: New specs so that we don't
need to extend avr/specs.h each time we add a new bell or whistle.
<*cc1_rodata_in_ram, *link_rodata_in_ram>: New specs to diagnose
-m[no-]rodata-in-ram.
<*cpp_rodata_in_ram>: New. Does -D__AVR_RODATA_IN_RAM__=0/1.
<*cpp_mcu>: Add -D__AVR_AVR_FLMAP__ if it applies.
<*cpp>: Add %(cpp_rodata_in_ram).
<*link_arch>: Use emulation avrxmega2_flmap, avrxmega4_flmap as
requested.
<*self_spec>: Add -mflmap or %<mflmap as needed.

gcc/testsuite/
* gcc.target/avr/torture/pr112944-flmap-0.c: New test.
* gcc.target/avr/torture/pr112944-flmap-1.c: New test.

12 files changed:
gcc/config.in
gcc/config/avr/avr-arch.h
gcc/config/avr/avr-mcus.def
gcc/config/avr/avr.cc
gcc/config/avr/avr.opt
gcc/config/avr/gen-avr-mmcu-specs.cc
gcc/config/avr/specs.h
gcc/configure
gcc/configure.ac
gcc/doc/invoke.texi
gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-0.c [new file with mode: 0644]
gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-1.c [new file with mode: 0644]

index b499bbfdda7522ac349c1b15e6e5d20d45147dca..99fd2d89fe3c540a12ccaa452dbe1e20d20a4f31 100644 (file)
 #endif
 
 
+/* Define if your linker supports emulation avrxmega2_flmap. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_AVR_AVRXMEGA2_FLMAP
+#endif
+
+
 /* Define if your default avr linker script for avrxmega3 leaves .rodata in
    flash. */
 #ifndef USED_FOR_TARGET
 #endif
 
 
+/* Define if your linker supports emulation avrxmega4_flmap. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_AVR_AVRXMEGA4_FLMAP
+#endif
+
+
 /* Define if your linker supports -z bndplt */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_BNDPLT_SUPPORT
index 03b3263d5296f4f2f017b7f6530057b8426b7b6e..d0a297d81e45743e5fe88d1d8e5bc6135a141b92 100644 (file)
@@ -166,7 +166,35 @@ AVR_ISA_RCALL
   assume these instructions are not available and we set the built-in
   macro __AVR_HAVE_JMP_CALL__ accordingly.  This macro is used to
   determine a rough estimate of flash size in libgcc, and AVR-LibC uses
-  this macro to determine vector sizes.  */
+  this macro to determine vector sizes.
+
+AVR_ISA_FLMAP
+  The device has the NVMCTRL_CTRLB.FLMAP bitfield.  The value of FLMAP
+  determines which 32 KiB segment of the program memory (flash) is visible
+  in the RAM address space at 0x8000.
+
+  If Binutils support emulations avrxmega2_flmap resp. avrxmega4_flmap
+  (PR31124), then  the location of the .rodata section can be determined
+  by means of option -m[no-]rodata-in-ram.  If .rodata is located in flash,
+  the user can chose which 32 KiB flash block is visible in RAM space by
+  means of defining symbol __flmap.
+
+  The startup code from AVR-LibC initializes FLMAP according to __flmap
+  provided one of the avrxmega*_flmap emulations is used. If avrxmega2/4
+  is used, then the startup code does not initialize FLMAP.
+
+  __AVR_HAVE_FLMAP__ is a macro defined in device-specs and supposed to be
+  consumed by code that sets FLMAP, like the startup code for example.
+  The macro is defined when all of the following conditions are met:
+    * The device is AVR_ISA_FLMAP.
+    * It's not known at compile time / assembler time whether or not .rodata
+      will be located in flash or in RAM. This implies Binutils PR31124.
+    * The definition of the macro is independent of -m[no-]rodata-in-ram.
+
+  AVR_ISA_FLMAP does not affect multilib layout or selection in any way.
+
+  For details on which symbols are defined in which way depending on the
+  emulation, see <Binutils>/ld/scripttempl/avr.sc.  */
 
 enum avr_device_specific_features
 {
@@ -175,9 +203,12 @@ enum avr_device_specific_features
   AVR_SHORT_SP    = 0x2, /* Stack Pointer has 8 bits width. */
   AVR_ERRATA_SKIP = 0x4, /* device has a core erratum. */
   AVR_ISA_LDS     = 0x8, /* whether LDS / STS is valid for all data in static
-                            storage.  Only useful for reduced Tiny.  */
-  AVR_ISA_RCALL   = 0x10 /* Use RJMP / RCALL even though JMP / CALL
-                            are available (-mshort-calls).  */
+                           storage.  Only useful for reduced Tiny.      */
+  AVR_ISA_RCALL          = 0x10, /* Use RJMP / RCALL even though JMP / CALL
+                            are available (-mshort-calls).      */
+  AVR_ISA_FLMAP          = 0x20  /* Has NVMCTRL_CTRLB.FLMAP to select which 32 KiB
+                            block of program memory is visible in the RAM
+                            address space.      */
 };
 
 /* Map architecture to its texinfo string.  */
index 87b59245e3cb3bdfbbd1b4d11ce4d734ce74cb28..9fb23776d39936f5ada003168f6994fb8a7e223a 100644 (file)
@@ -306,21 +306,21 @@ AVR_MCU ("atxmega16c4",      ARCH_AVRXMEGA2, AVR_ISA_RMW,  "__AVR_ATxmega16C4__"
 AVR_MCU ("atxmega32a4u",     ARCH_AVRXMEGA2, AVR_ISA_RMW,  "__AVR_ATxmega32A4U__", 0x2000, 0x0, 0x9000, 0)
 AVR_MCU ("atxmega32c4",      ARCH_AVRXMEGA2, AVR_ISA_RMW,  "__AVR_ATxmega32C4__",  0x2000, 0x0, 0x9000, 0)
 AVR_MCU ("atxmega32e5",      ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_ATxmega32E5__",  0x2000, 0x0, 0x9000, 0)
-AVR_MCU ("avr64da28",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA28__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64da32",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA32__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64da48",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA48__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64da64",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA64__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64db28",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB28__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64db32",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB32__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64db48",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB48__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64db64",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB64__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64dd14",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD14__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64dd20",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD20__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64dd28",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD28__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64dd32",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DD32__",    0x6000, 0x0, 0x10000, 0)
-AVR_MCU ("avr64ea28",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64EA28__",    0x6800, 0x0, 0x10000, 0)
-AVR_MCU ("avr64ea32",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64EA32__",    0x6800, 0x0, 0x10000, 0)
-AVR_MCU ("avr64ea48",        ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64EA48__",    0x6800, 0x0, 0x10000, 0)
+AVR_MCU ("avr64da28",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA28__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64da32",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA32__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64da48",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA48__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64da64",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DA64__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64db28",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB28__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64db32",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB32__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64db48",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB48__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64db64",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DB64__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64dd14",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD14__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64dd20",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD20__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64dd28",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD28__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64dd32",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD32__",   0x6000, 0x0, 0x10000, 0)
+AVR_MCU ("avr64ea28",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA28__",   0x6800, 0x0, 0x10000, 0)
+AVR_MCU ("avr64ea32",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA32__",   0x6800, 0x0, 0x10000, 0)
+AVR_MCU ("avr64ea48",        ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA48__",   0x6800, 0x0, 0x10000, 0)
 /* Xmega, Flash + RAM < 64K, flash visible in RAM address space */
 AVR_MCU ("avrxmega3",        ARCH_AVRXMEGA3, AVR_ISA_NONE,  NULL,                  0x3f00, 0x0, 0x8000, 0)
 AVR_MCU ("attiny202",        ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny202__",   0x3f80, 0x0, 0x800,  0x8000)
@@ -393,14 +393,14 @@ AVR_MCU ("atxmega64b1",      ARCH_AVRXMEGA4, AVR_ISA_RMW,  "__AVR_ATxmega64B1__"
 AVR_MCU ("atxmega64b3",      ARCH_AVRXMEGA4, AVR_ISA_RMW,  "__AVR_ATxmega64B3__",  0x2000, 0x0, 0x11000, 0)
 AVR_MCU ("atxmega64c3",      ARCH_AVRXMEGA4, AVR_ISA_RMW,  "__AVR_ATxmega64C3__",  0x2000, 0x0, 0x11000, 0)
 AVR_MCU ("atxmega64d4",      ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_ATxmega64D4__",  0x2000, 0x0, 0x11000, 0)
-AVR_MCU ("avr128da28",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA28__",   0x4000, 0x0, 0x20000, 0)
-AVR_MCU ("avr128da32",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA32__",   0x4000, 0x0, 0x20000, 0)
-AVR_MCU ("avr128da48",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA48__",   0x4000, 0x0, 0x20000, 0)
-AVR_MCU ("avr128da64",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA64__",   0x4000, 0x0, 0x20000, 0)
-AVR_MCU ("avr128db28",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB28__",   0x4000, 0x0, 0x20000, 0)
-AVR_MCU ("avr128db32",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB32__",   0x4000, 0x0, 0x20000, 0)
-AVR_MCU ("avr128db48",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB48__",   0x4000, 0x0, 0x20000, 0)
-AVR_MCU ("avr128db64",       ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB64__",   0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128da28",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA28__",  0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128da32",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA32__",  0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128da48",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA48__",  0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128da64",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DA64__",  0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128db28",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB28__",  0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128db32",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB32__",  0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128db48",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB48__",  0x4000, 0x0, 0x20000, 0)
+AVR_MCU ("avr128db64",       ARCH_AVRXMEGA4, AVR_ISA_FLMAP, "__AVR_AVR128DB64__",  0x4000, 0x0, 0x20000, 0)
 /* Xmega, 64K < Flash <= 128K, RAM > 64K */
 AVR_MCU ("avrxmega5",        ARCH_AVRXMEGA5, AVR_ISA_NONE, NULL,                   0x2000, 0x0, 0x11000, 0)
 AVR_MCU ("atxmega64a1",      ARCH_AVRXMEGA5, AVR_ISA_NONE, "__AVR_ATxmega64A1__",  0x2000, 0x0, 0x11000, 0)
index 4bc3cf929de9c100a3d058acd0a454adf604c59a..d77e1aad5cd8c0c1ecf28e7ed951781e3754158e 100644 (file)
@@ -220,6 +220,7 @@ static GTY(()) rtx xstring_e;
 
 /* Current architecture.  */
 const avr_arch_t *avr_arch;
+enum avr_arch_id avr_arch_index;
 
 /* Unnamed sections associated to __attribute__((progmem)) aka. PROGMEM
    or to address space __flash* or __memx.  Only used as singletons inside
@@ -229,9 +230,10 @@ static GTY(()) section *progmem_section[ADDR_SPACE_COUNT];
 /* Condition for insns/expanders from avr-dimode.md.  */
 bool avr_have_dimode = true;
 
-/* To track if code will use .bss and/or .data.  */
+/* To track if code will use .bss, .data, .rodata.  */
 bool avr_need_clear_bss_p = false;
 bool avr_need_copy_data_p = false;
+bool avr_has_rodata_p = false;
 
 \f
 /* Transform UP into lowercase and write the result to LO.
@@ -1059,6 +1061,7 @@ avr_set_core_architecture (void)
               && mcu->macro == NULL)
         {
           avr_arch = &avr_arch_types[mcu->arch_id];
+         avr_arch_index = mcu->arch_id;
           if (avr_n_flash < 0)
             avr_n_flash = 1 + (mcu->flash_size - 1) / 0x10000;
 
@@ -10758,6 +10761,49 @@ avr_insert_attributes (tree node, tree *attributes)
     }
 }
 
+#ifdef HAVE_LD_AVR_AVRXMEGA2_FLMAP
+static const bool have_avrxmega2_flmap = true;
+#else
+static const bool have_avrxmega2_flmap = false;
+#endif
+
+#ifdef HAVE_LD_AVR_AVRXMEGA4_FLMAP
+static const bool have_avrxmega4_flmap = true;
+#else
+static const bool have_avrxmega4_flmap = false;
+#endif
+
+#ifdef HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH
+static const bool have_avrxmega3_rodata_in_flash = true;
+#else
+static const bool have_avrxmega3_rodata_in_flash = false;
+#endif
+
+
+static bool
+avr_rodata_in_flash_p ()
+{
+  switch (avr_arch_index)
+    {
+    default:
+      break;
+
+    case ARCH_AVRTINY:
+      return true;
+
+    case ARCH_AVRXMEGA3:
+      return have_avrxmega3_rodata_in_flash;
+
+    case ARCH_AVRXMEGA2:
+      return avr_flmap && have_avrxmega2_flmap && avr_rodata_in_ram != 1;
+
+    case ARCH_AVRXMEGA4:
+      return avr_flmap && have_avrxmega4_flmap && avr_rodata_in_ram != 1;
+    }
+
+  return false;
+}
+
 
 /* Implement `ASM_OUTPUT_ALIGNED_DECL_LOCAL'.  */
 /* Implement `ASM_OUTPUT_ALIGNED_DECL_COMMON'.  */
@@ -10890,13 +10936,11 @@ avr_output_addr_attrib (tree decl, const char *name,
 static void
 avr_asm_init_sections (void)
 {
-  /* Override section callbacks to keep track of `avr_need_clear_bss_p'
-     resp. `avr_need_copy_data_p'.  If flash is not mapped to RAM then
-     we have also to track .rodata because it is located in RAM then.  */
+  /* Override section callbacks to keep track of `avr_need_clear_bss_p',
+     `avr_need_copy_data_p' and `avr_has_rodata_p'.
+     Track also .rodata for the case when .rodata is located in RAM.  */
 
-#if defined HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH
-  if (avr_arch->flash_pm_offset == 0)
-#endif
+  if (! avr_rodata_in_flash_p ())
     readonly_data_section->unnamed.callback = avr_output_data_section_asm_op;
   data_section->unnamed.callback = avr_output_data_section_asm_op;
   bss_section->unnamed.callback = avr_output_bss_section_asm_op;
@@ -10937,13 +10981,9 @@ avr_asm_named_section (const char *name, unsigned int flags, tree decl)
     avr_need_copy_data_p = (startswith (name, ".data")
                            || startswith (name, ".gnu.linkonce.d"));
 
-  if (!avr_need_copy_data_p
-#if defined HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH
-      && avr_arch->flash_pm_offset == 0
-#endif
-      )
-    avr_need_copy_data_p = (startswith (name, ".rodata")
-                           || startswith (name, ".gnu.linkonce.r"));
+  if (!avr_has_rodata_p)
+    avr_has_rodata_p = (startswith (name, ".rodata")
+                        || startswith (name, ".gnu.linkonce.r"));
 
   if (!avr_need_clear_bss_p)
     avr_need_clear_bss_p = startswith (name, ".bss");
@@ -11273,7 +11313,8 @@ avr_file_end (void)
      linking in the initialization code from libgcc if resp.
      sections are empty, see PR18145.  */
 
-  if (avr_need_copy_data_p)
+  if (avr_need_copy_data_p
+      || (avr_has_rodata_p && ! avr_rodata_in_flash_p ()))
     fputs (".global __do_copy_data\n", asm_out_file);
 
   if (avr_need_clear_bss_p)
index e75730857f562bd0b30730f6ce6660192458f6de..ee0b40603f09762a9a336d4d1a31e272c44dc6c5 100644 (file)
@@ -94,6 +94,14 @@ mstrict-X
 Target Var(avr_strict_X) Init(0)
 When accessing RAM, use X as imposed by the hardware, i.e. just use pre-decrement, post-increment and indirect addressing with the X register.  Without this option, the compiler may assume that there is an addressing mode X+const similar to Y+const and Z+const and emit instructions to emulate such an addressing mode for X.
 
+mflmap
+Target Var(avr_flmap) Init(0)
+The device has the bitfield NVMCTRL_CTRLB.FLMAP.  This option is used internally.
+
+mrodata-in-ram
+Target Var(avr_rodata_in_ram) Init(-1)
+The device has the .rodata section located in the RAM area.
+
 ;; For rationale behind -msp8 see explanation in avr.h.
 msp8
 Target RejectNegative Var(avr_sp8) Init(0)
index 89f8680e2440aed8fc18ab95a4cc9e455cd155dc..eb9ab8854d8dc160a09bf307898fd2405f9f6508 100644 (file)
@@ -50,6 +50,8 @@
 #define SPECFILE_USAGE_URL                              \
   "https://gcc.gnu.org/gcc-5/changes.html"
 
+#define WIKI_URL                                       \
+  "https://gcc.gnu.org/wiki/avr-gcc#spec-files"
 
 static const char header[] =
   "#\n"
@@ -68,9 +70,13 @@ static const char header[] =
 
 static const char help_copy_paste[] =
   "# If you intend to use an existing device specs file as a starting point\n"
-  "# for a new device spec file, make sure you are copying from a specs\n"
-  "# file for a device from the same core architecture and SP width.\n"
-  "# See <" SPECFILE_USAGE_URL "> for a description\n"
+  "# for a new device spec file, make sure you are copying from a specs file\n"
+  "# for a device from the same or compatible:\n"
+  "#     compiler version, compiler vendor, core architecture, SP width,\n"
+  "#     short-calls and FLMAP.\n"
+  "# Otherwise, errors and wrong or sub-optimal code may likely occur.\n"
+  "# See <" WIKI_URL ">\n"
+  "# and <" SPECFILE_USAGE_URL "> for a description\n"
   "# of how to use such own spec files.\n";
 
 #if defined (WITH_AVRLIBC)
@@ -103,6 +109,60 @@ static const char help_dev_lib_name[] =
   "\n";
 #endif // WITH_AVRLIBC
 
+
+#ifdef HAVE_LD_AVR_AVRXMEGA2_FLMAP
+static const bool have_avrxmega2_flmap = true;
+#else
+static const bool have_avrxmega2_flmap = false;
+#endif
+
+#ifdef HAVE_LD_AVR_AVRXMEGA4_FLMAP
+static const bool have_avrxmega4_flmap = true;
+#else
+static const bool have_avrxmega4_flmap = false;
+#endif
+
+#ifdef HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH
+static const bool have_avrxmega3_rodata_in_flash = true;
+#else
+static const bool have_avrxmega3_rodata_in_flash = false;
+#endif
+
+
+static void
+diagnose_mrodata_in_ram (FILE *f, const char *spec, const avr_mcu_t *mcu)
+{
+  enum avr_arch_id arch_id = mcu->arch_id;
+  const avr_arch_t *arch = &avr_arch_types[arch_id];
+  const bool is_arch = mcu->macro == NULL;
+  const bool flmap = (mcu->dev_attribute & AVR_ISA_FLMAP);
+  const bool have_flmap2 = have_avrxmega2_flmap && arch_id == ARCH_AVRXMEGA2;
+  const bool have_flmap4 = have_avrxmega4_flmap && arch_id == ARCH_AVRXMEGA4;
+  const bool have_flmap = flmap && (have_flmap2 || have_flmap4);
+
+  const bool rodata_in_flash = (arch_id == ARCH_AVRTINY
+                               || (arch_id == ARCH_AVRXMEGA3
+                                   && have_avrxmega3_rodata_in_flash));
+  fprintf (f, "%s:\n", spec);
+  if (rodata_in_flash && is_arch)
+    fprintf (f, "\t%%{mrodata-in-ram: %%e-mrodata-in-ram not supported"
+            " for %s}", mcu->name);
+  else if (rodata_in_flash)
+    fprintf (f, "\t%%{mrodata-in-ram: %%e-mrodata-in-ram not supported"
+            " for %s (arch=%s)}", mcu->name, arch->name);
+  else if (is_arch)
+    {
+      if (! have_flmap2 && ! have_flmap4)
+       fprintf (f, "\t%%{mno-rodata-in-ram: %%e-mno-rodata-in-ram not"
+                " supported for %s}", mcu->name);
+    }
+  else if (! have_flmap)
+    fprintf (f, "\t%%{mno-rodata-in-ram: %%e-mno-rodata-in-ram not supported"
+            " for %s (arch=%s)}", mcu->name, arch->name);
+  fprintf (f, "\n\n");
+}
+
+
 static void
 print_mcu (const avr_mcu_t *mcu)
 {
@@ -130,6 +190,7 @@ print_mcu (const avr_mcu_t *mcu)
   bool rmw = (mcu->dev_attribute & AVR_ISA_RMW) != 0;
   bool sp8 = (mcu->dev_attribute & AVR_SHORT_SP) != 0;
   bool rcall = (mcu->dev_attribute & AVR_ISA_RCALL);
+  bool flmap = (mcu->dev_attribute & AVR_ISA_FLMAP);
   bool is_arch = mcu->macro == NULL;
   bool is_device = ! is_arch;
   int flash_pm_offset = 0;
@@ -166,13 +227,24 @@ print_mcu (const avr_mcu_t *mcu)
       rcall_spec = rcall ? "-mshort-calls" : "%<mshort-calls";
     }
 
+  const char *flmap_spec = flmap ? "-mflmap" : "%<mflmap";
+  const char *link_arch_spec = "%{mmcu=*:-m%*}";
+  const char *link_arch_flmap_spec = "%{mmcu=*:-m%*%{!mrodata-in-ram:_flmap}}";
+  const bool have_flmap2 = have_avrxmega2_flmap && arch_id == ARCH_AVRXMEGA2;
+  const bool have_flmap4 = have_avrxmega4_flmap && arch_id == ARCH_AVRXMEGA4;
+  const bool have_flmap = flmap && (have_flmap2 || have_flmap4);
+
+  if (have_flmap)
+    link_arch_spec = link_arch_flmap_spec;
+
   fprintf (f, "#\n"
            "# Auto-generated specs for AVR ");
   if (is_arch)
     fprintf (f, "core architecture %s\n", arch->name);
   else
-    fprintf (f, "device %s (core %s, %d-bit SP%s)\n", mcu->name,
-             arch->name, sp8 ? 8 : 16, rcall ? ", short-calls" : "");
+    fprintf (f, "device %s (core %s, %d-bit SP%s%s)\n", mcu->name,
+            arch->name, sp8 ? 8 : 16, rcall ? ", short-calls" : "",
+            have_flmap ? ", FLMAP" : "");
   fprintf (f, "%s\n", header);
 
   if (is_device)
@@ -212,6 +284,11 @@ print_mcu (const avr_mcu_t *mcu)
            ? "\t%{!mno-absdata: -mabsdata}"
            : "\t%{mabsdata}");
 
+  // -m[no-]rodata-in-ram basically affects linking, but sanity-check early.
+  diagnose_mrodata_in_ram (f, "*cc1_rodata_in_ram", mcu);
+
+  fprintf (f, "*cc1_misc:\n\t%%(cc1_rodata_in_ram)\n\n");
+
   // avr-gcc specific specs for assembling / the assembler.
 
   fprintf (f, "*asm_arch:\n\t-mmcu=%s\n\n", arch->name);
@@ -235,6 +312,8 @@ print_mcu (const avr_mcu_t *mcu)
            ? "\t%{mno-skip-bug}"
            : "\t%{!mskip-bug: -mno-skip-bug}");
 
+  fprintf (f, "*asm_misc:\n" /* empty */ "\n\n");
+
   // avr-specific specs for linking / the linker.
 
   int wrap_k =
@@ -253,7 +332,10 @@ print_mcu (const avr_mcu_t *mcu)
 
   fprintf (f, "*link_relax:\n\t%s\n\n", LINK_RELAX_SPEC);
 
-  fprintf (f, "*link_arch:\n\t%s", LINK_ARCH_SPEC);
+  // -m[no-]rodata-in-ram affects linking.  Sanity check its usage.
+  diagnose_mrodata_in_ram (f, "*link_rodata_in_ram", mcu);
+
+  fprintf (f, "*link_arch:\n\t%s", link_arch_spec);
   if (is_device
       && flash_pm_offset)
     fprintf (f, " --defsym=__RODATA_PM_OFFSET__=0x%x", flash_pm_offset);
@@ -274,12 +356,15 @@ print_mcu (const avr_mcu_t *mcu)
       fprintf (f, "\n\n");
     }
 
+  fprintf (f, "*link_misc:\n\t%%(link_rodata_in_ram)\n\n");
+
   // Specs known to GCC.
 
   if (is_device)
     {
       fprintf (f, "*self_spec:\n");
       fprintf (f, "\t%%<mmcu=* -mmcu=%s ", arch->name);
+      fprintf (f, "%s ", flmap_spec);
       fprintf (f, "%s ", rcall_spec);
       fprintf (f, "%s\n\n", sp8_spec);
 
@@ -298,10 +383,26 @@ print_mcu (const avr_mcu_t *mcu)
          fprintf (f, " -U__AVR_PM_BASE_ADDRESS__");
          fprintf (f, " -D__AVR_PM_BASE_ADDRESS__=0x%x", flash_pm_offset);
        }
+      if (have_flmap)
+       fprintf (f, " -D__AVR_HAVE_FLMAP__");
+
+      fprintf (f, "\n\n"); // *cpp_mcu
+
+      const bool rodata_in_flash = (arch_id == ARCH_AVRTINY
+                                   || (arch_id == ARCH_AVRXMEGA3
+                                       && have_avrxmega3_rodata_in_flash));
+      fprintf (f, "*cpp_rodata_in_ram:\n\t-D__AVR_RODATA_IN_RAM__=");
+      if (rodata_in_flash)
+       fprintf (f, "0");
+      else if (! have_flmap)
+       fprintf (f, "1");
+      else
+       fprintf (f, "%%{!mrodata-in-ram:%%{!mno-rodata-in-ram:0}}"
+                "%%{mrodata-in-ram:1}" "%%{mno-rodata-in-ram:0}");
       fprintf (f, "\n\n");
 
       fprintf (f, "*cpp:\n");
-      fprintf (f, "\t%%(cpp_mcu)");
+      fprintf (f, "\t%%(cpp_mcu) %%(cpp_rodata_in_ram)");
 #if defined (WITH_AVRLIBC)
       fprintf (f, " %%(cpp_avrlibc)");
 #endif // WITH_AVRLIBC
index 433231fb6a96bf254398afeefd79324df435d870..574402035bc5d5dab811f19014647dda535e7305 100644 (file)
@@ -35,7 +35,8 @@ along with GCC; see the file COPYING3.  If not see
   "%(cc1_n_flash) "                             \
   "%(cc1_errata_skip) "                         \
   "%(cc1_rmw) "                                 \
-  "%(cc1_absdata) "
+  "%(cc1_absdata) "                             \
+  "%(cc1_misc) "
 
 #undef  CC1PLUS_SPEC
 #define CC1PLUS_SPEC                                    \
@@ -53,10 +54,8 @@ along with GCC; see the file COPYING3.  If not see
   "%(asm_relax) "                               \
   "%(asm_rmw) "                                 \
   "%(asm_gccisr) "                              \
-  "%(asm_errata_skip) "
-
-#define LINK_ARCH_SPEC                          \
-  "%{mmcu=*:-m%*} "
+  "%(asm_errata_skip) "                         \
+  "%(asm_misc) "
 
 #define LINK_RELAX_SPEC                         \
   "%{mrelax:--relax} "
@@ -68,6 +67,7 @@ along with GCC; see the file COPYING3.  If not see
   "%(link_text_start) "                         \
   "%(link_relax) "                              \
   "%(link_pmem_wrap) "                          \
+  "%(link_misc) "                               \
   "%{shared:%eshared is not supported} "
 
 #undef  LIB_SPEC
index 996046f51982c396e03e138a4191ce6a25f995c6..4acb254d830074b22bafc83e980b7e7bdbfdceb0 100755 (executable)
@@ -28455,6 +28455,7 @@ $as_echo "#define HAVE_AS_AVR_MGCCISR_OPTION 1" >>confdefs.h
 fi
 
 
+    avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`"
     # Check how default linker description file implements .rodata for
     # avrxmega3 (PR21472).  avr-gcc assumes .rodata is *not* loaded to
     # RAM so avr-gcc skips __do_copy_data for .rodata objects.
@@ -28499,7 +28500,6 @@ $as_echo "#define HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH 1" >>confdefs.h
 $as_echo "no: avrxmega3 .rodata located in RAM" >&6; }
            echo "$as_me: nm output was" >&5
            cat conftest.nm >&5
-           avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`"
            { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: support for avrxmega3 .rodata in flash needs Binutils 2.29 or higher (have $avr_ld_ver)" >&5
 $as_echo "$as_me: WARNING: support for avrxmega3 .rodata in flash needs Binutils 2.29 or higher (have $avr_ld_ver)" >&2;}
        fi
@@ -28512,6 +28512,74 @@ $as_echo "test failed" >&6; }
 $as_echo "$as_me: WARNING: see \`config.log' for details" >&2;}
     fi
     rm -f conftest.s conftest.o conftest.elf conftest.nm
+
+    # Check for emulation avrxmega2_flmap.
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking binutils for avrxmega2_flmap support (PR31124)" >&5
+$as_echo_n "checking binutils for avrxmega2_flmap support (PR31124)... " >&6; }
+    cat > conftest.s <<EOF
+        .section .text,"ax",@progbits
+        ldi r16, __flmap_value_with_lock
+EOF
+    { ac_try='$gcc_cv_as -mmcu=avrxmega2 conftest.s -o conftest.o'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    { ac_try='$gcc_cv_ld -mavrxmega2_flmap conftest.o -o conftest.elf'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    if test -s conftest.elf
+    then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_LD_AVR_AVRXMEGA2_FLMAP 1" >>confdefs.h
+
+    else
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: support for avrxmega2_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&5
+$as_echo "$as_me: WARNING: support for avrxmega2_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: see \`config.log' for details" >&5
+$as_echo "$as_me: WARNING: see \`config.log' for details" >&2;}
+    fi
+    rm -f conftest.o conftest.elf
+
+    # Check for emulation avrxmega4_flmap.
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking binutils for avrxmega4_flmap support (PR31124)" >&5
+$as_echo_n "checking binutils for avrxmega4_flmap support (PR31124)... " >&6; }
+    { ac_try='$gcc_cv_as -mmcu=avrxmega4 conftest.s -o conftest.o'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    { ac_try='$gcc_cv_ld -mavrxmega4_flmap conftest.o -o conftest.elf'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    if test -s conftest.elf
+    then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_LD_AVR_AVRXMEGA4_FLMAP 1" >>confdefs.h
+
+    else
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: support for avrxmega4_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&5
+$as_echo "$as_me: WARNING: support for avrxmega4_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: see \`config.log' for details" >&5
+$as_echo "$as_me: WARNING: see \`config.log' for details" >&2;}
+    fi
+    rm -f conftest.s conftest.o conftest.elf
     ;;
 
   cris-*-*)
index 596e5f22f4fdb860db7fa0f32dfbd85e86dcb9a0..d2ed14496c1a987b06368076dac02a0b9981ba45 100644 (file)
@@ -4549,6 +4549,7 @@ AS_HELP_STRING([--disable-fix-cortex-a53-843419],
       [AC_DEFINE(HAVE_AS_AVR_MGCCISR_OPTION, 1,
                [Define if your avr assembler supports -mgcc-isr option.])])
 
+    avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`"
     # Check how default linker description file implements .rodata for
     # avrxmega3 (PR21472).  avr-gcc assumes .rodata is *not* loaded to
     # RAM so avr-gcc skips __do_copy_data for .rodata objects.
@@ -4574,7 +4575,6 @@ EOF
            AC_MSG_RESULT(no: avrxmega3 .rodata located in RAM)
            echo "$as_me: nm output was" >&AS_MESSAGE_LOG_FD
            cat conftest.nm >&AS_MESSAGE_LOG_FD
-           avr_ld_ver="`$gcc_cv_ld -v | sed -e 's:^.* ::'`"
            AC_MSG_WARN([[support for avrxmega3 .rodata in flash needs Binutils 2.29 or higher (have $avr_ld_ver)]])
        fi
     else
@@ -4584,6 +4584,42 @@ EOF
        AC_MSG_WARN([[see `config.log' for details]])
     fi
     rm -f conftest.s conftest.o conftest.elf conftest.nm
+
+    # Check for emulation avrxmega2_flmap.
+    AC_MSG_CHECKING(binutils for avrxmega2_flmap support (PR31124))
+    cat > conftest.s <<EOF
+        .section .text,"ax",@progbits
+        ldi r16, __flmap_value_with_lock
+EOF
+    AC_TRY_COMMAND([$gcc_cv_as -mmcu=avrxmega2 conftest.s -o conftest.o])
+    AC_TRY_COMMAND([$gcc_cv_ld -mavrxmega2_flmap conftest.o -o conftest.elf])
+    if test -s conftest.elf
+    then
+       AC_MSG_RESULT(yes)
+       AC_DEFINE(HAVE_LD_AVR_AVRXMEGA2_FLMAP, 1,
+           [Define if your linker supports emulation avrxmega2_flmap.])
+    else
+       AC_MSG_RESULT(no)
+       AC_MSG_WARN([[support for avrxmega2_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)]])
+       AC_MSG_WARN([[see `config.log' for details]])
+    fi
+    rm -f conftest.o conftest.elf
+
+    # Check for emulation avrxmega4_flmap.
+    AC_MSG_CHECKING(binutils for avrxmega4_flmap support (PR31124))
+    AC_TRY_COMMAND([$gcc_cv_as -mmcu=avrxmega4 conftest.s -o conftest.o])
+    AC_TRY_COMMAND([$gcc_cv_ld -mavrxmega4_flmap conftest.o -o conftest.elf])
+    if test -s conftest.elf
+    then
+       AC_MSG_RESULT(yes)
+       AC_DEFINE(HAVE_LD_AVR_AVRXMEGA4_FLMAP, 1,
+           [Define if your linker supports emulation avrxmega4_flmap.])
+    else
+       AC_MSG_RESULT(no)
+       AC_MSG_WARN([[support for avrxmega4_flmap requires Binutils 2.42 or higher (have $avr_ld_ver)]])
+       AC_MSG_WARN([[see `config.log' for details]])
+    fi
+    rm -f conftest.s conftest.o conftest.elf
     ;;
 
   cris-*-*)
index b7a201317cea4e1fcfc77cb5f76081a5782a22d3..1773f0d3f0cca672ce55ddf51e53469f4445239c 100644 (file)
@@ -883,11 +883,11 @@ Objective-C and Objective-C++ Dialects}.
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu}  -mabsdata  -maccumulate-args
 -mbranch-cost=@var{cost}
--mcall-prologues  -mgas-isr-prologues  -mint8
+-mcall-prologues  -mgas-isr-prologues  -mint8 -mflmap
 -mdouble=@var{bits} -mlong-double=@var{bits}
 -mn_flash=@var{size}  -mno-interrupts
 -mmain-is-OS_task  -mrelax  -mrmw  -mstrict-X  -mtiny-stack
--mfract-convert-truncate
+-mrodata-in-ram -mfract-convert-truncate
 -mshort-calls  -nodevicelib  -nodevicespecs
 -Waddr-space-convert  -Wmisspelled-isr}
 
@@ -23719,6 +23719,20 @@ differ from instructions in the assembler code.
 Relaxing must be turned on if linker stubs are needed, see the
 section on @code{EIND} and linker stubs below.
 
+@opindex mrodata-in-ram
+@item -mrodata-in-ram
+@itemx -mno-rodata-in-ram
+Locate the @code{.rodata} sections for read-only data in RAM resp.@:
+in program memory.
+For most devices, there is no choice and this option acts rather
+like an assertion.
+
+Since v14 and for the AVR64* and AVR128* devices, @code{.rodata}
+is located in flash memory per default, provided the required GNU Binutils
+support (@w{@uref{https://sourceware.org/PR31124,PR31124}}) is available.
+In that case, @option{-mrodata-in-ram} can be used to return to the old
+layout with @code{.rodata} in RAM.
+
 @opindex mstrict-X
 @item -mstrict-X
 Use address register @code{X} in a way proposed by the hardware.  This means
@@ -24112,6 +24126,23 @@ description file, and is currently available for
 there is no need to use address spaces like @code{__flash} or
 features like attribute @code{progmem} and @code{pgm_read_*}.
 
+@item __AVR_HAVE_FLMAP__
+This macro is defined provided the following conditions are met:
+@itemize @bullet
+@item The device has the @code{NVMCTRL_CTRLB.FLMAP} bitfield.
+This applies to the AVR64* and AVR128* devices.
+@item It's not known at assembler-time which emulation will be used.
+@end itemize
+This implies the compiler was configured with GNU Binutils that implement
+@w{@uref{https://sourceware.org/PR31124,PR31124}}.
+
+@item __AVR_RODATA_IN_RAM__
+This macro is undefined when the code is compiled for a core architecture.
+
+When the code is compiled for a device, the macro is defined to@tie{}1
+when the @code{.rodata} sections for read-only data is located in RAM;
+and defined to@tie{}0, otherwise.
+
 @item __WITH_AVRLIBC__
 The compiler is configured to be used together with AVR-Libc.
 See the @option{--with-avrlibc} configure option.
@@ -24165,6 +24196,11 @@ files.
 Assume that the flash memory has a size of @var{num} times 64@tie{}KiB.
 This determines which @code{__flash@var{N}} address spaces are available.
 
+@opindex mflmap
+@item -mflmap
+The device has the @code{FLMAP} bit field located in special function
+register @code{NVMCTRL_CTRLB}.
+
 @opindex mrmw
 @item -mrmw
 Assume that the device supports the Read-Modify-Write
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-0.c b/gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-0.c
new file mode 100644 (file)
index 0000000..3aae7b5
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-additional-options "-Wl,--defsym,__flmap=0" } */
+
+const int val = 1234;
+
+#ifdef __AVR_HAVE_FLMAP__
+/* Initialize NVMCTRL_CTRLB.FLMAP to __flmap.  */
+#include <avr/io.h>
+__attribute__((naked, section(".init2")))
+__attribute__((used, unused, no_instrument_function))
+static void init_flmap (void)
+{
+  uint8_t ctrlb = NVMCTRL_CTRLB;
+  ctrlb &= ~ NVMCTRL_FLMAP_gm;
+  ctrlb |= 0 << NVMCTRL_FLMAP_gp;
+  NVMCTRL_CTRLB = ctrlb;
+}
+#endif
+
+int main (void)
+{
+  const int *p = & val;
+  __asm ("" : "+r" (p));
+
+  if (*p != 1234)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-1.c b/gcc/testsuite/gcc.target/avr/torture/pr112944-flmap-1.c
new file mode 100644 (file)
index 0000000..f18078d
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-additional-options "-Wl,--defsym,__flmap=1" } */
+
+const int val = 1234;
+
+#ifdef __AVR_HAVE_FLMAP__
+/* Initialize NVMCTRL_CTRLB.FLMAP to __flmap.  */
+#include <avr/io.h>
+__attribute__((naked, section(".init2")))
+__attribute__((used, unused, no_instrument_function))
+static void init_flmap (void)
+{
+  uint8_t ctrlb = NVMCTRL_CTRLB;
+  ctrlb &= ~ NVMCTRL_FLMAP_gm;
+  ctrlb |= 1 << NVMCTRL_FLMAP_gp;
+  NVMCTRL_CTRLB = ctrlb;
+}
+#endif
+
+int main (void)
+{
+  const int *p = & val;
+  __asm ("" : "+r" (p));
+
+  if (*p != 1234)
+    __builtin_abort ();
+
+  return 0;
+}