Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing data to specific address during compile time

I hope the title is descriptive enough. So here is what I want to do and what I've toyed with.

Wait, first off, this is an embedded application. Atmel SAM4L microcontroller, using the Atmel Studio IDE and GCC compiler/linker.

Right, I am writing a bootloader, but want to save the bootloader version to the program memory to the end of the allocated space for the bootloader (let's say 0x3FF0). This way the app can also check the bootloader version by just looking at the specific address. At this moment I am busy with a utility for the app to update the bootloader itself, but I don't want the app or the bootloader to update the version at 0x3FF0 with a command or in code, I want it as part of the .bin/.hex file, so when I flash the bootloader on, the version is flashed on along with it. So currently I have a #define for the bootloader type, major version and minor version which are all in a file globals.h in the project. Basically I just want to write those 3 bytes to 0x3FF0 when I hit compile.

As I understand there's quite a lot of tricks I can pull with the linker, but have never before played with linker scripts until yesterday, and have been able to do some things with it, but not what I want yet. The project also creates quite an intense linker script, so I'm also a bit wary as to where to jump in and dump my three bytes. I know you're not allowed to move the address pointer back.

Here is the linker script generated by the project

/**
 * \file
 *
 * \brief Flash Linker script for SAM.
 *
 * Copyright (c) 2013 Atmel Corporation. All rights reserved.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 *    Atmel microcontroller product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \asf_license_stop
 *
 */

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)

/*
 * NOTE: to keep binary compatibility with SAM4L4 device on SAM4L Xplained Pro,
 * we use SAM4L4 memory space here instead SAM4L8. You may change it if you are
 * using SAM4L8 device.
 */
/* Memory Spaces Definitions */
MEMORY
{
  rom (rx)  : ORIGIN = 0x00000000, LENGTH = 0x00040000 /* flash, 256K */
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 /* sram, 32K */
  /* rom (rx)  : ORIGIN = 0x00000000, LENGTH = 0x00080000 */ /* flash, 512K */
  /* ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000 */ /* sram, 64K */
}

/* The stack size used by the application. NOTE: you need to adjust according to your application. */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x1000;
__ram_end__ = ORIGIN(ram) + LENGTH(ram) - 4;

/* Section Definitions */
SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        _sfixed = .;
        KEEP(*(.vectors .vectors.*))
        *(.text .text.* .gnu.linkonce.t.*)
        *(.glue_7t) *(.glue_7)
        *(.rodata .rodata* .gnu.linkonce.r.*)
        *(.ARM.extab* .gnu.linkonce.armextab.*)

        /* Support C constructors, and C destructors in both user code
           and the C library. This also provides support for C++ code. */
        . = ALIGN(4);
        KEEP(*(.init))
        . = ALIGN(4);
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        __preinit_array_end = .;

        . = ALIGN(4);
        __init_array_start = .;
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
        __init_array_end = .;

        . = ALIGN(0x4);
        KEEP (*crtbegin.o(.ctors))
        KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
        KEEP (*(SORT(.ctors.*)))
        KEEP (*crtend.o(.ctors))

        . = ALIGN(4);
        KEEP(*(.fini))

        . = ALIGN(4);
        __fini_array_start = .;
        KEEP (*(.fini_array))
        KEEP (*(SORT(.fini_array.*)))
        __fini_array_end = .;

        KEEP (*crtbegin.o(.dtors))
        KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
        KEEP (*(SORT(.dtors.*)))
        KEEP (*crtend.o(.dtors))

        . = ALIGN(4);
        _efixed = .;            /* End of text section */
    } > rom

    /* .ARM.exidx is sorted, so has to go in its own output section.  */
    PROVIDE_HIDDEN (__exidx_start = .);
    .ARM.exidx :
    {
      *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > rom
    PROVIDE_HIDDEN (__exidx_end = .);

    . = ALIGN(4);
    _etext = .;

    .relocate : AT (_etext)
    {
        . = ALIGN(4);
        _srelocate = .;
        *(.ramfunc .ramfunc.*);
        *(.data .data.*);
        . = ALIGN(4);
        _erelocate = .;
    } > ram

    /* .bss section which is used for uninitialized data */
    .bss (NOLOAD) :
    {
        . = ALIGN(4);
        _sbss = . ;
        _szero = .;
        *(.bss .bss.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = . ;
        _ezero = .;
    } > ram

    /* stack section */
    .stack (NOLOAD):
    {
        . = ALIGN(8);
         _sstack = .;
        . = . + __stack_size__;
        . = ALIGN(8);
        _estack = .;
    } > ram

    . = ALIGN(4);
    _end = . ;
}

So as far as I understand, .ARM.exidx is the last section placed in ROM and .relocate will be placed in RAM (from 0x20000000 onward) based on the regions and MEMORY declarations, so my three bytes should be somewhere between those two.

Then, as to HOW, I've tried this example http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0803a/BABDJCAA.html but I don't see it reflected in my .bin or .hex files. I'm guessing it only allocates the memory and doesn't actually load anything as it's merely a variable. I've also found things like this gcc linker description file force symbol to be at specific address , but I don't since it's not actual code I'm trying to load to a specific address, I don't see how I can use this method.

I'm still playing around with manipulating the linker script and seeing what I can achieve, but any help would be greatly appreciated.

If any further information is required, please ask and I will provide. (Or if I need to change the title or tags for better hits.)

like image 858
kowalski5233 Avatar asked Nov 18 '14 09:11

kowalski5233


People also ask

Is the address of a local variable known at compile time?

Address of local variables are not known, because they reside on "stack" memory region.

What is difference between compile time and runtime binding?

Compile-time and Runtime are the two programming terms used in the software development. Compile-time is the time at which the source code is converted into an executable code while the run time is the time at which the executable code is started running.

What is compile time?

In computer science, compile time (or compile-time) describes the time window during which a computer program is compiled. The term is used as an adjective to describe concepts related to the context of program compilation, as opposed to concepts related to the context of program execution (runtime).


1 Answers

The address of things is determined at the linker stage and for the linker everything is just symbols. So while your gcc linker description file force symbol to be at specific address give an example for a function that equaly works for data. Define your version and put it in a seperate "version" section in the C code. Then the linker can place that section somewhere.

Now the hard part is to get it to the end of the rom, which means specifying a start address just low enough that the section will end at the end of rom. Making it a fixed size (your 3 Bytes) makes that simpler. Look how ram_end is defined in the linker script. Do the same for rom_version_start but with rom instead of ram and use that to set the start of the "version" section using '. = rom_version_start;'

like image 164
Goswin von Brederlow Avatar answered Nov 19 '22 20:11

Goswin von Brederlow