avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] A fork in the road [Was: Linker script patch with __f


From: Georg-Johann Lay
Subject: Re: [avr-gcc-list] A fork in the road [Was: Linker script patch with __flashN size]
Date: Thu, 20 Dec 2012 21:25:01 +0100
User-agent: Thunderbird 2.0.0.24 (Windows/20100228)

Erik Christiansen schrieb:
On 17.12.12 15:01, Erik Christiansen wrote:
I'll outline the benefits of a more structured linker script, mirroring
the desired memory model, in another post.

As Johann is demonstrating, the old linker script architecture, burdened
by a monolithic .text output section, not only does not explicitly
describe the desired memory model of larger and more advanced AVR
devices, but defeats his attempts to make it adequately locate the new
memory spaces, and flow the remaining code without objectionable holes.

Well, this can be solved as indicated with the attached script.

With that script, the flashN sections have flexible lower bounds. And any data at a higher address will follow without holes.

The script puts .progmem1 and .progmem2 into .text and .progmem3 into .flash3. This is just to show that both approaches work.

The script also works fine with an EIND=1 setup, e.g. -Ttext=0x20000 which is not uncommon with bootloaders: The .trampolines assert takes into account how EIND is initialized.

The script uses DEFINED on symbols provided by the compiler, see the patch. The patch does the following

1) Code clean-up: Use ADDR_SPACE_COUNT instead of magic "6".

2) Put __memx data into .progemx.data (formerly .progmem.data).

3) Define a symbol __need_.prohmemN.data for __flashN as needed.

1) and 2) are preferred, anyway.  3) is an almost trivial extension.

Using this extensions with the old ld script will changes nothing, i.e. there are no new problems, i.e. it is backward compatible.

Most striking advantage is that no build scripts must be changes to objcopy -j .lowtext -j .hightec etc. (except in the case where .flash3 is used and .progmem3 is not fused into .text).

This means: Users who do not use new feature can seamlessly upgrade to the new tools. No changes are needed for stuff they don't use.

If progmemN. is put into text -- which is possible without gaps now -- even users who use __flashN won't observe a change.

While we do not have a simple one-page statement of memory map
requirements, those which have come to light recently, if read with one
eye on the old linker script, show that we have four functional
categories of flash memory:

The LOW TEXT, which must be below 128 KiB.
Input sections: .vectors, .trampolines, .jumptables, .lowtext,
                .ctors, .dtors, .progmem.data

Notice .trampolines might be high, e.g. with -Ttext=20000

From zero to five __flashN pages, which must be 0x10000 page-aligned.
Input sections: .progmem1.data*, .progmem2.data*, .progmem3.data*,
                .progmem4.data*, .progmem5.data*

The HIGH TEXT, which is .text that does not need to go below 128 KiB.
It butts up to the last __flashN, or (in)to LOW TEXT, if no __flashN
are used.
Input sections: All the .initN, .text, all the .finiN, and anything else.

__memx: A compiler view which can be laid over more or less any flash
        memory model, with RAM at 0x800000, maintaining compatibility
        with the various binutils tools, and avrdude.

Because __flashN have fixed page addresses in the middle of the AVR
flash memory map, the old monolithic .text output section is now best
split into .lowtext and .hightext, as in the new script. That allows

My main objection is that this will raise myriads of support requests because applications break. Users will upgrade to the new version and *nothing* will work because .text is missing -- no matter whether they use __flash or not. I don't think this is a good idea.

We still can have .hightext between the highest .progmemN and .data, but this will requires that the application explicitly puts functions into .hightext. Default for .text will still be .text, not .lowtext.

our code to open like a clamshell iff one or more __flashN are present.
In the absence of any __flashN, lowtext and .hightext merge into a
contiguous block of code. If .text is of modest size, then everything
(including .text and .data) is packed into the first 128 KiB by the new
script.ยน
Assiduous readers of the thread thus far will be aware that the new
linker script architecture thereby makes visible the avr6 functional
memory model, giving users an immediate feel for how their code is
fitting into the memory spaces they are using, whether explicitly via
__flashN, or implicitly via all that is crammed into .lowtext by all its
input sections. I.e. just run avr-objdump -h, for an instant radar map.

The new architecture also greatly simplifies correct location of the
code in all the various use cases. In addition, it permits the use of
ld's automatic overlap detection, and facilitates manual overflow
detection, using assertions. The many failures Johann reports in his
script attempt are largely due to using a venerable script architecture
which has been obsoleted by the new AVR memory spaces supported in
avr-gcc.

Well, the hacks we need are to work around shortcomings of the linker script language as mentioned in

http://sourceware.org/ml/binutils/2012-12/msg00151.html

There no answer to the question why the script does not work according to the documentation (Erik's answer there is on a different topic).

As running a test case, using Johann's test harness shows, a quick
avr-objdump -h now gives us an instant clear view of where everything
went, and how much overflow or overlap margin there is, well before
trouble strikes, and we cop an error message.

A new flash.sx is attached. It also knows DATA now. Thus we can set the following defines to cook up a test case:

Code in flash: TEXT, LOWTEXT, STUBS, BOOT ("ax" orphan)
Data in flash: CTORS, P0, P1, P2, P3, PX
Data in RAM  : DATA

The new file also sets up __need_.progmemN.data symbols as needed by the new script. It mimics what avr-gcc will do with the patch applied.

My vote is to favour continued development of the tested successful
script candidate over the repeated failures of the other. Its current
effectiveness and resilience bodes well for unanticipated future
enhancements. Any tweaking requests can be knocked over then. (There
does not seem to be any hurry for any of this.)

Remaining trouble:

Binutils generate all scripts from one template, avr.sc. I found no way to get a double quote (") into the generated ld scripts. " will be killed, \" will yield a \" and using single quotes will print single quotes without any effect on "


Johann


gcc/config/avr/
        * config/avr/avr.h (ADDR_SPACE_COUNT): New enum.
        (avr_addrspace_t): Add .section_name field.
        * config/avr/avr.c (progmem_section): Use ADDR_SPACE_COUNT as
        array size.
        (avr_addrspace): Same.  Initialize .section_name.  Remove last
        NULL entry.  Put __memx into .progmemx.data.
        (avr_need_addrspace_p): New static variable.
        (progmem_section_prefix): Remove.
        (avr_asm_init_sections): No need to initialize progmem_section.
        (avr_asm_named_section): Use avr_addrspace[].section_name to get
        section name prefix.  Record avr_need_addrspace_p.
        (avr_asm_select_section): Ditto.  And use get_unnamed_section to
        retrieve the progmem section.
        (avr_asm_function_rodata_section): Record avr_need_addrspace_p.
        (avr_file_end): Reference __need_.progmem<N>.data according to
        avr_need_addrspace_p[N].
        * avr-c.c (avr_cpu_cpp_builtins): Use ADDR_SPACE_COUNT as loop
        boundary to run over avr_addrspace[].
        (avr_register_target_pragmas): Ditto.

libgcc/config/avr/
        * t-avr (LIB1ASMFUNCS): Add: _progmem1, _progmem2, _progmem3,
        _progmem4, _progmem5.
        * lib1funcs.S: Implement them.

diff --git a/avr6.x b/avr6.x
index 3da58e9..92cf044 100644
--- a/avr6.x
+++ b/avr6.x
@@ -76,7 +76,8 @@ SECTIONS
     KEEP(*(.vectors))
     /* For data that needs to reside in the lower 64k of progmem.  */
     *(.progmem.gcc*)
-    *(.progmem*)
+    *(.progmem)
+    *(.progmem.*)
     . = ALIGN(2);
      __trampolines_start = . ;
     /* The jump trampolines for the 16-bit limited relocs will reside here.  */
@@ -85,11 +86,17 @@ SECTIONS
      __trampolines_end = . ;
     /* For future tablejump instruction arrays for 3 byte pc devices.
        We don't relax jump/call instructions within these sections.  */
+     __jumptables_start = . ;
     *(.jumptables)
     *(.jumptables*)
+     __jumptables_end = . ;
     /* For code that needs to reside in the lower 128k progmem.  */
+     __lowtext_start = . ;
     *(.lowtext)
     *(.lowtext*)
+     __lowtext_end = . ;
+    /* From this point on, we don't bother about wether the insns are
+       below or above the 16 bits boundary.  */
      __ctors_start = . ;
      *(.ctors)
      __ctors_end = . ;
@@ -98,8 +105,6 @@ SECTIONS
      __dtors_end = . ;
     KEEP(SORT(*)(.ctors))
     KEEP(SORT(*)(.dtors))
-    /* From this point on, we don't bother about wether the insns are
-       below or above the 16 bits boundary.  */
     *(.init0)  /* Start here after reset.  */
     KEEP (*(.init0))
     *(.init1)
@@ -144,9 +149,37 @@ SECTIONS
     KEEP (*(.fini1))
     *(.fini0)  /* Infinite loop after program termination.  */
     KEEP (*(.fini0))
+
+     __progmemx_start = . ;
+    *(.progmemx)
+    *(.progmemx.*)
+     __progmemx_end = . ;
+
+     . = MAX (DEFINED(__need_.progmem1.data) ? 1 << 16 : 0, ABSOLUTE(.)) ;
+     __progmem1_start = . ;
+    *(.progmem1)
+    *(.progmem1.*)
+     __progmem1_end = . ;
+
+     . = MAX (DEFINED(__need_.progmem2.data) ? 2 << 16 : 0, ABSOLUTE(.)) ;
+     __progmem2_start = . ;
+    *(.progmem2)
+    *(.progmem2.*)
+     __progmem2_end = . ;
+
+    . = ALIGN(2);
      _etext = . ;
   }  > text
-  .data          : AT (ADDR (.text) + SIZEOF (.text))
+  
+  .flash3 MAX (DEFINED(__need_.progmem3.data) ? 3 << 16 : 0, ABSOLUTE(.)) :
+  {
+     __progmem3_start = . ;
+    *(.progmem3)
+    *(.progmem3.*)
+     __progmem3_end = . ;
+  } > text
+
+  .data        : AT (ADDR (.flash3) + SIZEOF (.flash3))
   {
      PROVIDE (__data_start = .) ;
     /* --gc-sections will delete empty .data. This leads to wrong start
@@ -234,3 +267,48 @@ SECTIONS
   /* DWARF Extension.  */
   .debug_macro    0 : { *(.debug_macro) }
 }
+
+
+/* Some sanity checking: .trampolines, .lowtext and .jumptables must be
+   reachable with EIND = 0, i.e. must be located withing the first
+   64Ki word chunk of flash.  */
+
+__assert_jumptables
+  = ASSERT (__jumptables_start == __jumptables_end
+            || __jumptables_end <= 1 << 17,
+            "section overflow: .jumptables must be located below 0x20000");
+
+__assert_lowtext
+  = ASSERT (__lowtext_start == __lowtext_end
+            || __lowtext_end <= 1 << 17,
+            "section overflow: .lowtext must be located below 0x20000");
+
+/* Startup code from avr-libc initialized EIND with hh8(pm(.vectors))
+   thus the trampolines will work if they are located in such a way that
+   EIND = hh8(pm(.trampolines))  */
+
+__assert_stubs
+  = ASSERT (__trampolines_start == __trampolines_end
+            || (ADDR (.text) >> 17 == (__trampolines_end - 1) >> 17
+                && ADDR (.text) >> 17 == __trampolines_start >> 17),
+            "section overflow: .trampolines (linker stubs) must be located 
below 0x20000");
+
+/* Sanity check the progmem stuff: .progmemN must be located within the
+   N-th 64Ki byte chunk.  The low end needs no checking because the MAX
+   with .progmemN sets the right start address.  */
+
+__assert_flash1
+  = ASSERT (__progmem1_start == __progmem1_end
+            || __progmem1_end <= 2 << 16,
+            "section overflow: .progmem1 (__flash1) must be located below 
0x20000");
+
+__assert_flash2
+  = ASSERT (__progmem2_start == __progmem2_end
+            || __progmem2_end <= 3 << 16,
+            "section overflow: .progmem2 (__flash2) must be located below 
0x30000");
+
+__assert_flash3
+  = ASSERT (__progmem3_start == __progmem3_end
+            || __progmem3_end <= 4 << 16,
+            "section overflow: .progmem3 (__flash3) must be located below 
0x40000");
+
#ifndef TEXT
#define TEXT 0
#endif

#ifndef LOWTEXT
#define LOWTEXT 0
#endif

#ifndef STUBS
#define STUBS 0
#endif

#ifndef CTORS
#define CTORS 0
#endif

#ifndef P0
#define P0 0
#endif

#ifndef P1
#define P1 0
#endif

#ifndef P2
#define P2 0
#endif

#ifndef P3
#define P3 0
#endif

#ifndef PX
#define PX 0
#endif

#ifndef BOOT
#define BOOT 0
#endif

#ifndef DATA
#define DATA 0
#endif

.macro Flash n num
.if \num > 0
    .section .progmem\n\().data.foo\n\(),"a",@progbits
        .fill \num
 
    .global __need_.progmem\n\().data
    .section .progmem\n\().data,"a",@progbits
    .global __need_.progmem\n\().data
    .weak   __need_.progmem\n\().data
    .type   __need_.progmem\n\().data,@notype
__need_.progmem\n\().data:
.endif
.endm


Flash  , P0
Flash 1, P1
Flash 2, P2
Flash 3, P3
Flash x, PX

.text
.global main
main:
.rept TEXT / 2
    nop
.endr
    
.rept STUBS
    0:
    ldi r16, lo8(gs(0b))
    ldi r17, hi8(gs(0b))
.endr
.size main, .-main

.data
    .fill DATA

.section .lowtext,"ax",@progbits
.global lowfunc
lowfunc:
.rept LOWTEXT / 2
    nop
.endr
.size lowfunc, .-lowfunc

#if CTORS > 0
.global __do_global_ctors
.section .ctors,"a",@progbits
    .p2align 1
    .rept CTORS / 2
    .word       gs(main+16)
    .endr
#endif /* CTORS */

#if BOOT > 0
.section .bootloader,"ax",@progbits
.global bootloader
.type bootloader,@function
bootloader:
    .rept BOOT / 2
    nop
    .endr
#endif /* BOOT */
Index: gcc/config/avr/avr.h
===================================================================
--- gcc/config/avr/avr.h        (revision 194505)
+++ gcc/config/avr/avr.h        (working copy)
@@ -37,6 +37,9 @@ typedef struct
 
   /* Segment (i.e. 64k memory chunk) number.  */
   int segment;
+
+  /* Section prefix, e.g. "progmem1.data".  */
+  const char *section_name;
 } avr_addrspace_t;
 
 extern const avr_addrspace_t avr_addrspace[];
@@ -45,14 +48,16 @@ extern const avr_addrspace_t avr_addrspa
 
 enum
   {
-    ADDR_SPACE_RAM,
+    ADDR_SPACE_RAM, /* ADDR_SPACE_GENERIC */
     ADDR_SPACE_FLASH,
     ADDR_SPACE_FLASH1,
     ADDR_SPACE_FLASH2,
     ADDR_SPACE_FLASH3,
     ADDR_SPACE_FLASH4,
     ADDR_SPACE_FLASH5,
-    ADDR_SPACE_MEMX
+    ADDR_SPACE_MEMX,
+    /* Sentinel */
+    ADDR_SPACE_COUNT
   };
 
 #define TARGET_CPU_CPP_BUILTINS()      avr_cpu_cpp_builtins (pfile)
Index: gcc/config/avr/avr.c
===================================================================
--- gcc/config/avr/avr.c        (revision 194505)
+++ gcc/config/avr/avr.c        (working copy)
@@ -80,29 +80,18 @@
 
 /* Known address spaces.  The order must be the same as in the respective
    enum from avr.h (or designated initialized must be used).  */
-const avr_addrspace_t avr_addrspace[] =
+const avr_addrspace_t avr_addrspace[ADDR_SPACE_COUNT] =
 {
-    { ADDR_SPACE_RAM,  0, 2, ""     ,   0 },
-    { ADDR_SPACE_FLASH,  1, 2, "__flash",   0 },
-    { ADDR_SPACE_FLASH1, 1, 2, "__flash1",  1 },
-    { ADDR_SPACE_FLASH2, 1, 2, "__flash2",  2 },
-    { ADDR_SPACE_FLASH3, 1, 2, "__flash3",  3 },
-    { ADDR_SPACE_FLASH4, 1, 2, "__flash4",  4 },
-    { ADDR_SPACE_FLASH5, 1, 2, "__flash5",  5 },
-    { ADDR_SPACE_MEMX, 1, 3, "__memx",  0 },
-    { 0              , 0, 0, NULL,      0 }
+  { ADDR_SPACE_RAM,  0, 2, "", 0, NULL },
+  { ADDR_SPACE_FLASH,  1, 2, "__flash",   0, ".progmem.data" },
+  { ADDR_SPACE_FLASH1, 1, 2, "__flash1",  1, ".progmem1.data" },
+  { ADDR_SPACE_FLASH2, 1, 2, "__flash2",  2, ".progmem2.data" },
+  { ADDR_SPACE_FLASH3, 1, 2, "__flash3",  3, ".progmem3.data" },
+  { ADDR_SPACE_FLASH4, 1, 2, "__flash4",  4, ".progmem4.data" },
+  { ADDR_SPACE_FLASH5, 1, 2, "__flash5",  5, ".progmem5.data" },
+  { ADDR_SPACE_MEMX, 1, 3, "__memx",  0, ".progmemx.data" },
 };
 
-/* Map 64-k Flash segment to section prefix.  */
-static const char* const progmem_section_prefix[6] =
-  {
-    ".progmem.data",
-    ".progmem1.data",
-    ".progmem2.data",
-    ".progmem3.data",
-    ".progmem4.data",
-    ".progmem5.data"
-  };
 
 /* Holding RAM addresses of some SFRs used by the compiler and that
    are unique over all devices in an architecture like 'avr4'.  */
@@ -205,8 +194,9 @@ const struct mcu_type_s *avr_current_dev
 static GTY(()) section *progmem_swtable_section;
 
 /* Unnamed sections associated to __attribute__((progmem)) aka. PROGMEM
-   or to address space __flash*.  */
-static GTY(()) section *progmem_section[6];
+   or to address space __flash*.  Only used as singletons inside
+   avr_asm_select_section, but it must not be local because of GTY.  */
+static GTY(()) section *progmem_section[ADDR_SPACE_COUNT];
 
 /* Condition for insns/expanders from avr-dimode.md.  */
 bool avr_have_dimode = true;
@@ -215,6 +205,10 @@ bool avr_have_dimode = true;
 bool avr_need_clear_bss_p = false;
 bool avr_need_copy_data_p = false;
 
+/* Track need for the non-generic address spaces, similar to
+   avr_need_copy_data_p.  */
+static bool avr_need_addrspace_p[ADDR_SPACE_COUNT];
+
 
 
 /* Custom function to count number of set bits.  */
@@ -8107,8 +8101,6 @@ avr_output_progmem_section_asm_op (const
 static void
 avr_asm_init_sections (void)
 {
-  unsigned int n;
-  
   /* Set up a section for jump tables.  Alignment is handled by
      ASM_OUTPUT_BEFORE_CASE_LABEL.  */
   
@@ -8127,13 +8119,6 @@ avr_asm_init_sections (void)
                                ",\"ax\",@progbits");
     }
 
-  for (n = 0; n < sizeof (progmem_section) / sizeof (*progmem_section); n++)
-    {
-      progmem_section[n]
-        = get_unnamed_section (0, avr_output_progmem_section_asm_op,
-                               progmem_section_prefix[n]);
-    }
-  
   /* Override section callbacks to keep track of `avr_need_clear_bss_p'
      resp. `avr_need_copy_data_p'.  */
   
@@ -8167,6 +8152,9 @@ avr_asm_function_rodata_section (tree de
     flags = frodata->common.flags;
   }
 
+  /* Just for the record... */
+  avr_need_addrspace_p[ADDR_SPACE_FLASH] = true;
+
   if (frodata != readonly_data_section
       && flags & SECTION_NAMED)
     {
@@ -8211,9 +8199,10 @@ avr_asm_named_section (const char *name,
   if (flags & AVR_SECTION_PROGMEM)
     {
       addr_space_t as = (flags & AVR_SECTION_PROGMEM) / SECTION_MACH_DEP;
-      int segment = avr_addrspace[as].segment;
       const char *old_prefix = ".rodata";
-      const char *new_prefix = progmem_section_prefix[segment];
+      const char *new_prefix = avr_addrspace[as].section_name;
+
+      avr_need_addrspace_p[as] = true;
       
       if (STR_PREFIX_P (name, old_prefix))
         {
@@ -8326,13 +8315,20 @@ avr_asm_select_section (tree decl, int r
       && avr_progmem_p (decl, DECL_ATTRIBUTES (decl)))
     {
       addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
-      int segment = avr_addrspace[as].segment;
+
+      /* __progmem__ goes in generic space but shall be allocated to
+         .progmem.data  */
+
+      if (ADDR_SPACE_GENERIC_P (as))
+        as = ADDR_SPACE_FLASH;
       
+      avr_need_addrspace_p[as] = true;
+
       if (sect->common.flags & SECTION_NAMED)
         {
           const char * name = sect->named.name;
           const char * old_prefix = ".rodata";
-          const char * new_prefix = progmem_section_prefix[segment];
+          const char * new_prefix = avr_addrspace[as].section_name;
 
           if (STR_PREFIX_P (name, old_prefix))
             {
@@ -8341,8 +8337,15 @@ avr_asm_select_section (tree decl, int r
               return get_section (sname, sect->common.flags, sect->named.decl);
             }
         }
-          
-      return progmem_section[segment];
+
+      if (!progmem_section[as])
+        {
+          progmem_section[as]
+            = get_unnamed_section (0, avr_output_progmem_section_asm_op,
+                                   avr_addrspace[as].section_name);
+        }
+
+      return progmem_section[as];
     }
 
   return sect;
@@ -8401,6 +8404,27 @@ avr_file_end (void)
 
   if (avr_need_clear_bss_p)
     fputs (".global __do_clear_bss\n", asm_out_file);
+
+  for (size_t n = 0; n < ADDR_SPACE_COUNT; n++)
+    {
+      addr_space_t as = (addr_space_t) n;
+
+      if (avr_need_addrspace_p[as]
+          /* We only need the __need_ symbols in the linker script for
+             the paged sections that move the location counter forward.
+             For example, bumping the location counter to 0x10000
+             for __flash1 / .progmem1.data is only needed if that input
+             section is non-empty.  The linker script language is not generic
+             enough to express this.  Thus, we trigger the definition of a 
+             symbol that can be used as predicate via DEFINED(symbol).  */
+          && !ADDR_SPACE_GENERIC_P (as)
+          && ADDR_SPACE_FLASH != as
+          && ADDR_SPACE_MEMX != as)
+        {
+          fprintf (asm_out_file, ".global __need_%s\n",
+                   avr_addrspace[as].section_name);
+        }
+    }
 }
 
 /* Choose the order in which to allocate hard registers for
Index: gcc/config/avr/avr-c.c
===================================================================
--- gcc/config/avr/avr-c.c      (revision 194505)
+++ gcc/config/avr/avr-c.c      (working copy)
@@ -43,7 +43,7 @@ avr_register_target_pragmas (void)
   /* Register address spaces.  The order must be the same as in the respective
      enum from avr.h (or designated initialized must be used in avr.c).  */
 
-  for (i = 0; avr_addrspace[i].name; i++)
+  for (i = 0; i < ADDR_SPACE_COUNT; i++)
     {
       gcc_assert (i == avr_addrspace[i].id);
 
@@ -160,7 +160,7 @@ avr_cpu_cpp_builtins (struct cpp_reader
   
   if (!strcmp (lang_hooks.name, "GNU C"))
     {
-      for (i = 0; avr_addrspace[i].name; i++)
+      for (i = 0; i < ADDR_SPACE_COUNT; i++)
         if (!ADDR_SPACE_GENERIC_P (i)
             /* Only supply __FLASH<n> macro if the address space is reasonable
                for this target.  The address space qualifier itself is still
Index: libgcc/config/avr/lib1funcs.S
===================================================================
--- libgcc/config/avr/lib1funcs.S       (revision 194505)
+++ libgcc/config/avr/lib1funcs.S       (working copy)
@@ -2935,4 +2935,36 @@ ENDF __fmul
 #undef C0
 #undef C1
 
+;; Marker Symbols to be used in the Linker Script.
+
+#if defined L_progmem1
+.section .progmem1.data, "a", @progbits
+.global __need_.progmem1.data
+__need_.progmem1.data:
+#endif /* L_progmem1 */
+
+#if defined L_progmem2
+.section .progmem2.data, "a", @progbits
+.global __need_.progmem2.data
+__need_.progmem2.data:
+#endif /* L_progmem2 */
+
+#if defined L_progmem3
+.section .progmem3.data, "a", @progbits
+.global __need_.progmem3.data
+__need_.progmem3.data:
+#endif /* L_progmem3 */
+
+#if defined L_progmem4
+.section .progmem4.data, "a", @progbits
+.global __need_.progmem4.data
+__need_.progmem4.data:
+#endif /* L_progmem4 */
+
+#if defined L_progmem5
+.section .progmem5.data, "a", @progbits
+.global __need_.progmem5.data
+__need_.progmem5.data:
+#endif /* L_progmem5 */
+
 #include "lib1funcs-fixed.S"
Index: libgcc/config/avr/t-avr
===================================================================
--- libgcc/config/avr/t-avr     (revision 194505)
+++ libgcc/config/avr/t-avr     (working copy)
@@ -77,7 +77,9 @@ LIB1ASMFUNCS += \
        _ssneg_2 _ssneg_4 _ssneg_8 \
        _ssabs_2 _ssabs_4 _ssabs_8 \
        _ssadd_8 _sssub_8 \
-       _usadd_8 _ussub_8
+       _usadd_8 _ussub_8 \
+       \
+       _progmem1 _progmem2 _progmem3 _progmem4 _progmem5
 
 LIB2FUNCS_EXCLUDE = \
        _moddi3 _umoddi3 \

reply via email to

[Prev in Thread] Current Thread [Next in Thread]