Linker script- FILL command question

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I want to fill unused program flash memory with a couple of instructions (cli,wdr). I don't think there is a way to do it without getting into the linker script(at least I haven't figured one out if there is). So, I tried to get the FILL command to work, but am unable to get ld to do anything with the FILL command. I am using a mega88, and the linker script is 'avr4.x'.

This is what I think should work according to the ld docs-

...
    *(.fini0)  /* Infinite loop after program termination.  */
     _etext = . ;
     FILL(0x55)
  }  > text
  .data	  : AT (ADDR (.text) + SIZEOF (.text))
  {
     PROVIDE (__data_start = .) ;
...

with the FILL(0x55) added by me (not showing the whole script obviously, just the little parts around what I added).

I have also tried =fillexpr at the end of the .text section ('} > text =0x55'), but am unable to make that work either.

I do see that it could be a problem with where I am placing the fill command, which brings up another question- how do the initialized variables get placed at the end of the text section, when the data section is directed to the ram location? Which means my FILL command has to be after the variable data, but not in the data section. I'm lost.

If anyone can enlighten me as to how to use the FILL command in the linker script, would be much appreciated. Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK. Put your pencils down. It's break time.

I have entered the dark, mysterious world of the 'LiNkEr', and I'm still alive to tell about it, although I'm still recovering.

First, anyone who says 'yeah, I knew that. What's the big deal', I would have liked to have heard from you before I got battered and tossed around in the 'LiNkEr' mystery world :)

Here's what worked (don't know if its correct/wise/dumb/etc, but it works)-

  .fill  LOADADDR(.data) + (__data_end - __data_start) :
  {
    __fill_start = ABSOLUTE(.) ;
    FILL(0xA895F894);
    . = . + LENGTH(text) - 512 - __fill_start - 2;
  } > text

This is added in the linker script (avr4.x in my case).

The section name is '.fill', it starts at the end of the .data LMA (load memory address). The .data section has an AT command, which changes the LMA of the data to the end of the text section (and the VMA still stays in the ram addresses). So we (I) need the fill data to start after the end of the .data (LMA address). The fill section starts at the load address of the data section (LMA address) + the size of the initialized data (__data_end - __data_start). To use the value later, the absolute address is 'defined' as __fill_start. Then the FILL command is used to 'fill' any unused space with 0xA895F894 (wdr,cli). So we need some unused space. Advancing the current location counter does the trick. The length of the memory 'text' is the same as FLASHEND+1, 512 is the size of my bootloader, __fill_start is the size of app used flash, and -2 is for my rjmp instruction (below).

Then I have this in my 4AvrBugTrapper.S file-

    .section    .fill
        rjmp __vectors

which places the rjmp to 0 just before the bootloader.

Here's a hex listing-

:06012000DEBFCDBFFFCFE2
...
:040126009A7856006D //0x5678,0x9A=globals 0x00 is alignment
:10012A00A895F894A895F894A895F894A895F894A1 //fill
:10013A00A895F894A895F894A895F894A895F89491
...
:101DDA00A895F894A895F894A895F894A895F894D5
:101DEA00A895F894A895F894A895F894A895F894C5
:061DFA00A895F89400C159 //0x1DFE=rjmp(C100)
:00000001FF
//1E00= start of bootloader

The '} > text =0xA895F894' option also works.

But, you cannot advance the location counter in the S file with a '.org', or assigning an address to the current location '.', as these will override the fill value with their own fill value (defaults to 0x00). The '.align' statement will end up filling the unused data with the fill value, though.

I have not tried it in C yet, but have no reason to think using the section attribute won't work. I am using gcc 3.4.6, so it could also be that later versions won't work as described here.

Next on my list, is to get the little portion of script into its own linker script, so I don't have to touch the 'real' linker scripts. 'Implicit linker scripts' is what I'm after (I think), but not sure how to get it 'called' (linker script name) with all the other options.

Everybody back to work now.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Next on my list, is to get the little portion of script into its own linker script, so I don't have to touch the 'real' linker scripts. 'Implicit linker scripts' is what I'm after (I think), but not sure how to get it 'called' (linker script name) with all the other options.
Not needed. If the .fill section is not referenced, it does not do anything. So I will just leave it in the avr4.x and avr5.x linker scripts, and if I want to use it, I just need to reference the .fill section.

If I totally mess things up somehow, I can easily get the 'originals' back. Plus there is this thing called the Internet, where I can get the original original copies, unless they run out of them, of course.

I can see linker scripts are a hot topic, and should probably get their own forum.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Curt,

Maybe not a lot of response - but some of us are very interested nevertheless. ;-)

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From a linker script for NIOS II:

 .text :
    {
        /*
         * All code sections are merged into the text output section, along with
         * the read only data sections.
         *
         */

        PROVIDE (stext = ABSOLUTE(.));

        *(.interp)
        *(.hash)
        *(.dynsym)
        *(.dynstr)
        *(.gnu.version)
        *(.gnu.version_d)
        *(.gnu.version_r)
        *(.rel.init)
        *(.rela.init)
        *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
        *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
        *(.rel.fini)
        *(.rela.fini)
        *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
        *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
        *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
        *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
        *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
        *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
        *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
        *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
        *(.rel.ctors)
        *(.rela.ctors)
        *(.rel.dtors)
        *(.rela.dtors)
        *(.rel.got)
        *(.rela.got)
        *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
        *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
        *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
        *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
        *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
        *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
        *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
        *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
        *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
        *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
        *(.rel.plt)
        *(.rela.plt)

        KEEP (*(.init))
        *(.plt)
        *(.text .stub .text.* .gnu.linkonce.t.*)

        /* .gnu.warning sections are handled specially by elf32.em.  */

        *(.gnu.warning.*)
        KEEP (*(.fini))
        PROVIDE (__etext = ABSOLUTE(.));
        PROVIDE (_etext = ABSOLUTE(.));
        PROVIDE (etext = ABSOLUTE(.));

        *(.eh_frame_hdr)
        /* Ensure the __preinit_array_start label is properly aligned.  We
           could instead move the label definition inside the section, but
           the linker would then create the section even if it turns out to
           be empty, which isn't pretty.  */
        . = ALIGN(32 / 8);
        PROVIDE (__preinit_array_start = ABSOLUTE(.));
        *(.preinit_array)
        PROVIDE (__preinit_array_end = ABSOLUTE(.));
        PROVIDE (__init_array_start = ABSOLUTE(.));
        *(.init_array)
        PROVIDE (__init_array_end = ABSOLUTE(.));
        PROVIDE (__fini_array_start = ABSOLUTE(.));
        *(.fini_array)
        PROVIDE (__fini_array_end = ABSOLUTE(.));
        SORT(CONSTRUCTORS)
        KEEP (*(.eh_frame))
        *(.gcc_except_table)
        *(.dynamic)
        PROVIDE (__CTOR_LIST__ = ABSOLUTE(.));
        KEEP (*(.ctors))
        KEEP (*(SORT(.ctors.*)))
        PROVIDE (__CTOR_END__ = ABSOLUTE(.));
        PROVIDE (__DTOR_LIST__ = ABSOLUTE(.));
        KEEP (*(.dtors))
        KEEP (*(SORT(.dtors.*)))
        PROVIDE (__DTOR_END__ = ABSOLUTE(.));
        KEEP (*(.jcr))
        . = ALIGN(32 / 8);
    } >  sram =0x3a880100 /* NOP on Nios2 (big endian) */

So all that's needed to fill up the unused portion of sram segment is to append "=0x3a880100".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff, then I will keep talking to myself here in case it helps someone else.

Last episode- curtvm was discussing how he could just leave the linker script modified, and if unused it would harmlessly sit on the sidelines, but as we see in this episode, he ran into something unforeseen....

(scene: deep underground in LiNkErTown, middle of the night, just a faint glow of a laptop screen lighting up the silhouette of a man, furiously typing away..)

BLIMEY! (I think that's the right word), the bootloader! The new linker script is harmless unless I do stuff like moving the .text section up to the bootloader section!

announcer: "Stay tuned for the next episode, where the 'laptop man' tries to figure out his next move. Will he try to use a combination of passing a symbol to the linker and using DEFINE? or will he just live with a simple manual edit when needed? or will LinkErTown claim another victim that dared to enter?

curtvm (who plays curtvm): "that was a tough episode, emotionally draining. The writers have done an outstanding job, I just hope I can do justice to the quality material I have been given. By the way, what's a linker script?"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
So all that's needed to fill up the unused portion of sram segment is to append "=0x3a880100".
That would be nice. But not so. (I don't know what NIOS is, but it appears to be something related to FPGA's or something, which may do things a little weird when linking, I'm guessing, depending on how the FPGA is emulating a cpu, or something, I don't know).

Here's the summary- 3 memory sections for the avr, text/data/eeprom. At the end of the text section, the initialized data needs to go there for loading into ram (LMA, load memory address for that data is now different than the VMA virtual memory address- sram). Since there is no room between the end of text and the LMA of the data, we have nothing to fill up (and any fill command or >filloutput does nothing). So we need a way to 'fill' up the program memory AFTER the LMA data. The .fill section I created above does that.

I guess the alternative would be to move the LMA data somewhere else in the text section, like somewhere early in the section, but I'm guessing there is probably a reason its put at the end of text. But any way you slice it, you need to edit a linker script, so the simple .fill thing works fine (just needs a little tweaking to make me really happy).

There still may be a better/simpler way.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe the complete linker script is useful to you :D

/* generated.x
 *
 * Machine generated for a CPU named "cpu" as defined in:
 * vhdl\main_controller\software\main_syslib\..\..\main_controller.ptf
 *
 * Generated: 2006-01-31 16:04:08.375
 *
 */

/*

DO NOT MODIFY THIS FILE

   Changing this file will have subtle consequences
   which will almost certainly lead to a nonfunctioning
   system. If you do modify this file, be aware that your
   changes will be overwritten and lost when this file
   is generated again.

DO NOT MODIFY THIS FILE

*/

MEMORY
{
    reset : ORIGIN = 0x00108000, LENGTH = 32
/*    sram_UNUSED : ORIGIN = 0x00000000, LENGTH = 32*/
    sram : ORIGIN = 0x00000000, LENGTH = 1048544
    nvram : ORIGIN = 0x00100000, LENGTH = 32768
    boot_rom1 : ORIGIN = 0x00108020, LENGTH = 4064
    boot_rom2 : ORIGIN = 0x00109000, LENGTH = 2048
    boot_rom3 : ORIGIN = 0x0010A000, LENGTH = 1024
}

    /* Define symbols for each memory base-address */
 __alt_mem_sram = 0x00000000 ;
 __alt_mem_nvram = 0x00100000 ;
 __alt_mem_boot_rom1 = 0x00108000 ;
 __alt_mem_boot_rom2 = 0x00109000 ;
 __alt_mem_boot_rom3 = 0x0010A000 ;



OUTPUT_FORMAT( "elf32-littlenios2",
               "elf32-littlenios2",
               "elf32-littlenios2" )
OUTPUT_ARCH( nios2 )
ENTRY( _start )

/* Do we need any of these for elf?
   __DYNAMIC = 0;
 */

SECTIONS
{
    .entry :
    {
        KEEP (*(.entry))
    } > sram

    .exceptions :
    {
        PROVIDE (__ram_exceptions_start = ABSOLUTE(.));
        . = ALIGN(0x20);
        *(.irq)
        KEEP (*(.exceptions.entry.label));
        KEEP (*(.exceptions.entry.user));
        KEEP (*(.exceptions.entry));
        KEEP (*(.exceptions.irqtest.user));
        KEEP (*(.exceptions.irqtest));
        KEEP (*(.exceptions.irqhandler.user));
        KEEP (*(.exceptions.irqhandler));
        KEEP (*(.exceptions.irqreturn.user));
        KEEP (*(.exceptions.irqreturn));
        KEEP (*(.exceptions.notirq.label));
        KEEP (*(.exceptions.notirq.user));
        KEEP (*(.exceptions.notirq));
        KEEP (*(.exceptions.soft.user));
        KEEP (*(.exceptions.soft));
        KEEP (*(.exceptions.unknown.user));
        KEEP (*(.exceptions.unknown));
        KEEP (*(.exceptions.exit.label));
        KEEP (*(.exceptions.exit.user));
        KEEP (*(.exceptions.exit));
        KEEP (*(.exceptions));
        PROVIDE (__ram_exceptions_end = ABSOLUTE(.));
    } > sram

    PROVIDE (__flash_exceptions_start = LOADADDR(.exceptions));

    .text :
    {
        /*
         * All code sections are merged into the text output section, along with
         * the read only data sections.
         *
         */

        PROVIDE (stext = ABSOLUTE(.));

        *(.interp)
        *(.hash)
        *(.dynsym)
        *(.dynstr)
        *(.gnu.version)
        *(.gnu.version_d)
        *(.gnu.version_r)
        *(.rel.init)
        *(.rela.init)
        *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
        *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
        *(.rel.fini)
        *(.rela.fini)
        *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
        *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
        *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
        *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
        *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
        *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
        *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
        *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
        *(.rel.ctors)
        *(.rela.ctors)
        *(.rel.dtors)
        *(.rela.dtors)
        *(.rel.got)
        *(.rela.got)
        *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
        *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
        *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
        *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
        *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
        *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
        *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
        *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
        *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
        *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
        *(.rel.plt)
        *(.rela.plt)

        KEEP (*(.init))
        *(.plt)
        *(.text .stub .text.* .gnu.linkonce.t.*)

        /* .gnu.warning sections are handled specially by elf32.em.  */

        *(.gnu.warning.*)
        KEEP (*(.fini))
        PROVIDE (__etext = ABSOLUTE(.));
        PROVIDE (_etext = ABSOLUTE(.));
        PROVIDE (etext = ABSOLUTE(.));

        *(.eh_frame_hdr)
        /* Ensure the __preinit_array_start label is properly aligned.  We
           could instead move the label definition inside the section, but
           the linker would then create the section even if it turns out to
           be empty, which isn't pretty.  */
        . = ALIGN(32 / 8);
        PROVIDE (__preinit_array_start = ABSOLUTE(.));
        *(.preinit_array)
        PROVIDE (__preinit_array_end = ABSOLUTE(.));
        PROVIDE (__init_array_start = ABSOLUTE(.));
        *(.init_array)
        PROVIDE (__init_array_end = ABSOLUTE(.));
        PROVIDE (__fini_array_start = ABSOLUTE(.));
        *(.fini_array)
        PROVIDE (__fini_array_end = ABSOLUTE(.));
        SORT(CONSTRUCTORS)
        KEEP (*(.eh_frame))
        *(.gcc_except_table)
        *(.dynamic)
        PROVIDE (__CTOR_LIST__ = ABSOLUTE(.));
        KEEP (*(.ctors))
        KEEP (*(SORT(.ctors.*)))
        PROVIDE (__CTOR_END__ = ABSOLUTE(.));
        PROVIDE (__DTOR_LIST__ = ABSOLUTE(.));
        KEEP (*(.dtors))
        KEEP (*(SORT(.dtors.*)))
        PROVIDE (__DTOR_END__ = ABSOLUTE(.));
        KEEP (*(.jcr))
        . = ALIGN(32 / 8);
    } >  sram =0x3a880100 /* NOP on Nios2 (big endian) */

    .rodata :
    {
        PROVIDE (__ram_rodata_start = ABSOLUTE(.));
        . = ALIGN(32 / 8);
        *(.rodata .rodata.* .gnu.linkonce.r.*)
        *(.rodata1)
        . = ALIGN(32 / 8);
        PROVIDE (__ram_rodata_end = ABSOLUTE(.));
    } > sram

    PROVIDE (__flash_rodata_start = LOADADDR(.rodata));

    .rwdata  :
    {
        PROVIDE (__ram_rwdata_start = ABSOLUTE(.));
        . = ALIGN(32 / 8);
        *(.got.plt) *(.got)
        *(.data1)
        *(.data .data.* .gnu.linkonce.d.*)

        _gp = ABSOLUTE(. + 0x8000);
        PROVIDE(gp = _gp);

        *(.sdata .sdata.* .gnu.linkonce.s.*)
        *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)

        . = ALIGN(32 / 8);
        _edata = ABSOLUTE(.);
        PROVIDE (edata = ABSOLUTE(.));
        PROVIDE (__ram_rwdata_end = ABSOLUTE(.));
    } > sram

    PROVIDE (__flash_rwdata_start = LOADADDR(.rwdata));

    .bss :
    {
        __bss_start = ABSOLUTE(.);
        PROVIDE (__sbss_start = ABSOLUTE(.));
        PROVIDE (___sbss_start = ABSOLUTE(.));

        *(.dynsbss)
        *(.sbss .sbss.* .gnu.linkonce.sb.*)
        *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
        *(.scommon)

        PROVIDE (__sbss_end = ABSOLUTE(.));
        PROVIDE (___sbss_end = ABSOLUTE(.));

        *(.dynbss)
        *(.bss .bss.* .gnu.linkonce.b.*)
        *(COMMON)

        . = ALIGN(32 / 8);
        __bss_end = ABSOLUTE(.);
    } > sram

    /*
     * One output section for each of the available partitions. These are not
     * used by default, but can be used by users applications using the .section
     * directive.
     *
     * The memory partition used for the heap is treated in  special way, i.e. a
     * symbol is added to point to the heap start.
     *
     * Note that when running from flash, these sections are not loaded by the
     * HAL.
     *
     */

    .sram :
    {
        PROVIDE (_alt_partition_sram_start = ABSOLUTE(.));
        *(.sram .sram.*)
        . = ALIGN(32 / 8);
        PROVIDE (_alt_partition_sram_end = ABSOLUTE(.));
        _end = ABSOLUTE(.);
        end = ABSOLUTE(.);
    } > sram

    PROVIDE (_alt_partition_sram_load_addr = LOADADDR(.sram));

    .nvram :
    {
        PROVIDE (_alt_partition_nvram_start = ABSOLUTE(.));
        *(.nvram .nvram.*)
        . = ALIGN(32 / 8);
        PROVIDE (_alt_partition_nvram_end = ABSOLUTE(.));
    } > nvram

    PROVIDE (_alt_partition_nvram_load_addr = LOADADDR(.nvram));

    .boot_rom1 :
    {
        PROVIDE (_alt_partition_boot_rom1_start = ABSOLUTE(.));
        *(.boot_rom1 .boot_rom1.*)
        . = ALIGN(32 / 8);
        PROVIDE (_alt_partition_boot_rom1_end = ABSOLUTE(.));
    } > boot_rom1

    PROVIDE (_alt_partition_boot_rom1_load_addr = LOADADDR(.boot_rom1));

    .boot_rom2 :
    {
        PROVIDE (_alt_partition_boot_rom2_start = ABSOLUTE(.));
        *(.boot_rom2 .boot_rom2.*)
        . = ALIGN(32 / 8);
        PROVIDE (_alt_partition_boot_rom2_end = ABSOLUTE(.));
    } > boot_rom2

    PROVIDE (_alt_partition_boot_rom2_load_addr = LOADADDR(.boot_rom2));

    .boot_rom3 :
    {
        PROVIDE (_alt_partition_boot_rom3_start = ABSOLUTE(.));
        *(.boot_rom3 .boot_rom3.*)
        . = ALIGN(32 / 8);
        PROVIDE (_alt_partition_boot_rom3_end = ABSOLUTE(.));
    } > boot_rom3

    PROVIDE (_alt_partition_boot_rom3_load_addr = LOADADDR(.boot_rom3));

    /*
     * Stabs debugging sections.
     *
     */

    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /* DWARF debug sections.
       Symbols in the DWARF debugging sections are relative to the beginning
       of the section so we begin them at 0.  */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }

    /* Altera debug extensions */
    .debug_alt_sim_info 0 : { *(.debug_alt_sim_info) }
}
/* provide a pointer for the stack */

/*
 * Don't override this, override the __alt_stack_* symbols instead.
 */
__alt_data_end = 0x00100000;

/*
 * The next two symbols define the location of the default stack.  You can
 * override them to move the stack to a different memory.
 */
PROVIDE( __alt_stack_pointer = __alt_data_end );
PROVIDE( __alt_stack_limit   = _end );

/*
 * This symbol controls where the start of the heap is.  If the stack is
 * contiguous with the heap then the stack will contract as memory is
 * allocated to the heap.
 * Override this symbol to put the heap in a different memory.
 */
PROVIDE( __alt_heap_start    = end );
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, Curt, why didn't you think about post-processing the .hex file with the Srec utilities? I'm pretty sure you can get them to fill any section of unused memory with whatever you'd like. Once you get the hang of them, they're pretty powerful.

Although, I admit, I stand in awe of your linker scripting!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Man, now I have to lookup srec utilities. Information overload.

I did think originally, that it would be easier to just make a little program to take a hex file and 'fill in' the unused space. But, since I'm at the 'trailing edge' and not the 'leading edge', I figured someone already beat me to it (by decades). I just needed to figure out where that info was hiding.

I concluded the linker script was where I needed to be. For some reason. My 'awesome' 4 line script seems to do the job, although I'm probably at my script line limit.

Now, if I could pass a symbol or something to the linker, which would INCLUDE or not include my little script (separate from avrN.x), that would be nice. But I can't seem to get --defsym to work (I'm not using a 'real' make file, only avr studio produced- yes, I know, Cliff).

The INCLUDE isn't going to work, though, I think. It seems I will have to do something with the . thing, like-

. = DEFINED(my_symbol) ? somethingsomething - my_symbol + somethingorsomething  : . + LENGTH(text) - 512 - __fill_start - 2;

or something.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, I agree. Linker scripting needs its own forum. The topic is just burnin' down the house.
Props for impressive link skills. ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One step forward (which usually precedes two steps back)-

For my bootloader-

-Wl,--defsym=turn_.fill_off=1

still using avr studio, custom linker options, the value is not important for the symbol (yet).

With this modified script from above (not THAT above)-

 .fill
   DEFINED(turn_.fill_off)
   ? 0
   : LOADADDR(.data) + (__data_end - __data_start)
   :
 {
   __fill_start = ABSOLUTE(.) ;
   FILL(0xA895F894);
   . = 
   DEFINED(turn_.fill_off)
   ? 0
   : . + LENGTH(text) - 512 - __fill_start - 2;
 } > text

which just turns that section into nothingness. So it seems. Anyway it works when moving the .text section up to the bootloader area (at least no complaints from the LiNkEr), and it works as planned when no symbol is passed.

Now just waiting for shoes to drop (not the 'other' shoe, BOTH shoes).

Looking forward to the day when I can get myself out of LiNkErTown.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok. Slight mod to previous plan.

Fill is off by default now, and will harmlessly stay out of the way if no linker symbol passed. But if fill wanted, the symbol passed will also contain the value of the bootloader size (or any amount previous to end of flash+1 where the fill is no longer wanted).

If fill wanted-

-Wl,--defsym=_.fill_on=512

and this new mod to the linker script-

  .fill
    DEFINED(_.fill_on)
    ? LOADADDR(.data) + (__data_end - __data_start)
    : 0
  :
  {
    __fill_start = ABSOLUTE(.) ;
    FILL(0xA895F894);
    . = 
    DEFINED(_.fill_on)
    ? . + LENGTH(text) - _.fill_on - __fill_start - 2
    : 0 ;
  } > text

the -2 still there to leave room for a 'nop' or 'rjmp' (gotta have something in that section to make the fill happen).