[Top][All Lists]

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

[avr-gcc-list] Linker script patch with __flashN size checking. [Was: Ha

From: Erik Christiansen
Subject: [avr-gcc-list] Linker script patch with __flashN size checking. [Was: Handling __flash1 and .trampolines]
Date: Sat, 15 Dec 2012 22:48:21 +1100
User-agent: Mutt/1.5.20 (2009-06-14)

Many thanks, Johann, for the clarification that your explanation has

On 14.12.12 23:00, Georg-Johann Lay wrote:
> The 64-bit ranges come from the ELPM instruction that takes the
> 16-bits of Z-reg and concatenates RAMPZ as bits 16..23 to get a
> 24-bit address.

The common computer terms "paged" and "page aligned" seem to fit
perfectly here. AIUI, the Z-reg is a page register, providing base 2^16
page addresses, and RAMPZ provides an address within the page.
It is "page aligned", because any RAMPZ == 0 will always be 2^16 aligned
in flash.

The new linker script observes that constraint by starting each __flashN
aligned to 0x10000 page boundaries, i.e. on 0xN0000.

Up to now, I'd forgotten the other edge of the page, 0xNffff. I'll
append a patch with everything including the assertions to do that.
Please note that the address limit within each output section is
relative, so they are all the same.


> This means the compiler assumes that var is located in such a way
> that all of its bytes are elements of [0x10000, 0x20000).

That is a good explanation of "page alignment"¹. ;-)

> The compiler puts var into section .progmem1.data to express this.

And these input sections are caught by the output section which contains
them, thus always matching up __flashN with .flashN.

> If var is not located appropriately, the compiler still loads RAMPZ
> with 1 and loads Z with the lower 16 bits of &var, but if var is at
> 0x23456 the compiler will access 0x13456 instead and read garbage.

There can be no risk of this happening, because the VMA specified on
each .flashN, e.g.:

  .flash2 0x20000 :

locks each __flashN to start at the beginning of a 0xN0000 page.


Many thanks for the "stubs" explanation. I hadn't caught on to its
relationship to trampolines.

>     .trampolines is subset of [EIND * 2^17, (1+EIND) * 2^17)

   .trampolines is subset of [EIND * 2^17, (1+EIND)]   ?

> EIND is set to 0 during startup.  You can also set it to 1 in the
> startup code and locate .trampolines appropriately.

That optionality doesn't seem to be supported in the linker script.

> Again, notice that the subset condition is trivially satisfied if
> there are no stubs, i.e. .trampolines is empty.  BTW: The compiler
> does not set EIND in the program, and setting EIND by hand is not
> supported.  It's likely the user shreds the code if he sets EIND by
> hand after the init stage.

Ah, it's not used yet, then.


> Maybe .trampolines needs some margin at the high end because it can
> grow as the linker generates new stubs.  I actually don't know.

A minimum allocation, eaten when the .trampolines section grows,
perhaps? That might speed up linking, but I figure it's pretty quick

> Most of the stuff I know (or believe to know) comes from
> reverse engineering when I tried to clean up EIND usage in avr-gcc
> (PR50820) and to add some notes and caveats to the docs.

Your knowledge is directly from the coalface, then - the most
hard-earned and real kind. I'll try to make the linker scripts dance, to
give us whatever you need to make that job easier.

There's also an extra ALIGN(2) in this one, to stop an odd number of
data bytes in __flashN from upsetting .text. (See, I have been doing
more testing. :-)


¹ Compare paragraph 2 at:

file: avr6.patch

--- avr6.x-2.23 2012-12-13 13:42:18.000000000 +1100
+++ avr6.x-new  2012-12-15 21:55:31.000000000 +1100
@@ -70,13 +70,12 @@
   .rel.plt       : { *(.rel.plt)               }
   .rela.plt      : { *(.rela.plt)              }
   /* Internal text space or external memory.  */
-  .text   :
+  .lowtext :
     /* For data that needs to reside in the lower 64k of progmem.  */
-    *(.progmem*)
     . = ALIGN(2);
      __trampolines_start = . ;
     /* The jump trampolines for the 16-bit limited relocs will reside here.  */
@@ -98,6 +97,28 @@
      __dtors_end = . ;
+    *(.progmem.data*)    /* Explicitly page 0 input sections */
+    _elowtext = . ;
+    x = ASSERT (. <= 0x10000, "Error: .lowtext (128KiB limit) overflow. Try 
shrinking .progmem?") ;
+  } > text
+  .flash1 0x10000 :
+  { *(.progmem1.data*)    /* Page 1 */
+    x = ASSERT (. <= 0x10000, "Error: __flash1 (64KiB limit) overflow. Need to 
shrink it.") ;
+  } > text
+  .flash2 0x20000 :
+  { *(.progmem2.data*)    /* Page 2 */
+    _eflash2 = . ;
+    x = ASSERT (_eflash2 <= 0x10000, "Error: __flash2 (64KiB limit) overflow. 
Need to shrink it.") ;
+  } > text
+  .flash3 0x30000 :
+  { *(.progmem3.data*)    /* Page 3 */
+  } > text
+  .hightext ALIGN(2) :
+  {
     /* 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.  */
@@ -146,7 +167,8 @@
     KEEP (*(.fini0))
      _etext = . ;
   }  > text
-  .data          : AT (ADDR (.text) + SIZEOF (.text))
+  .data          : AT (_etext)
      PROVIDE (__data_start = .) ;
     /* --gc-sections will delete empty .data. This leads to wrong start

Very few things happen at the right time, and the rest do not happen at all.  
The conscientious historian will correct these defects.                       
                                         - Mark Twain, in "A Horse's Tale"

reply via email to

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