Defining Variables at Absolute Addresses with gcc

Many compilers offer a way to allocate a variable at an absolute address. For example for the Freescale S08 compiler, I can place my variable at a given address:

unsigned char buf[128]@0x2000;

This is very useful (and needed) e.g. if the hardware (like USB) needs a buffer at given address. The advantage of the above (non-ANSI and thus not portable) syntax is that I can define a variable at an absolute address, without the need to allocate it in the linker.

I wanted to do something similar with gcc for Kinetis/ARM, and searched many forums on the internet. Obviously, I’m not alone with this question. The solution I have found comes close to what I use e.g. for the S08 compiler.

How can I place a variable say at address 0x2000’0000 with gcc for ARM/Kinetis?

The idea I use here is to put the variable with a special section name, and then place it in the linker file at an absolute address.

💡 I have not found a way to place a variable at an absolute address *without* to modify the linker file? Post a comment if you know a better solution!

__attribute__

Gcc uses the __attribute__ keyword as a way to ‘mark’ variables with special attributes. It allows me put my variable into a special section, which I name here ‘.myBufSection’:

unsigned char __attribute__((section (".myBufSection"))) buf[128];

Another useful thing is: I can specify the alignment of that variable with an __attribute__ too:

unsigned char __attribute__((section (".myBufSection"))) buf[128] __attribute__ ((aligned (512)));

With this, my variable will be put into a section named ‘.myBufSection’, and it will be aligned on a 512 address boundary.

Absolute Section Placing in Linker File

The next step is to place that section at an address in the linker file. E.g. for the KL25Z of my Freedom board, I have this memory mapping in my linker file:

MEMORY
{
  m_interrupts  (rx) : ORIGIN = 0x00000000, LENGTH = 0xC0
  m_cfmprotrom  (rx) : ORIGIN = 0x00000400, LENGTH = 0x10
  m_text        (rx) : ORIGIN = 0x00000800, LENGTH = 128K - 0x800
  m_data       (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K
}

I could split my m_data block and create my memory block for my variable to place at 0x2000’0000. An easier way is to simply place my section from above into the SECTIONS block like this:

SECTIONS
{
  /* placing my named section at given address: */
  .myBufBlock 0x20000000 :
  {
    KEEP(*(.myBufSection)) /* keep my variable even if not referenced */
  } > m_data

  /* other placements follow here... */
}

With above linker statement, I define an absolute start address for all my variables in the section named .myBufSection, and place it into the m_data memory block. Additionally I need to use the KEEP keyword to tell the linker *not* to dead-strip my variable, in case I do not reference it from my code.

Checking the Allocation

After linking, now my object should be at the given address. While looking at the linker map is always a good idea, I have found another nice tool which comes with the GNU suite: nm. With nm I can examine binary files like the ELF file produced by the linker. In CodeWarrior for MCU10.3, that command line utility can be found in

<CW installation path>\Cross_Tools\arm-none-eabi-gcc-4_6_2\bin\arm-none-eabi-nm.exe

I could configure to run it as post-link step in CodeWarrior, or simply use it from the DOS command line prompt:

nm shows my variable at the absolute address

nm shows my variable at the absolute address

Summary

For gcc, placing a variable at an absolute address requires two steps: marking it with a section name in the source, and then placing it in the linker file at an absolute address.

It would be good if there would be a way to avoid the linker file change, but I have not found another or better solution.

Happy Absoluting 🙂

Advertisements

52 thoughts on “Defining Variables at Absolute Addresses with gcc

    • Hello Erich,
      first of all thanks for the good solution!
      I would like to ask this: if I need to create more than one variables ( I need few arrays..), have I to declare a section for each array? Or there is easier way, using code instead of adding more sections?

      Thanks!

      Like

    • Hi Barrie,
      yes, using a casted pointer is the preferred way to access peripherals. The problem with this is that it is only accessing an object, but not defining it. In my case I want to reserve memory for it, not only accessing it. and if it is just such a pointer access, that will not work.
      Erich

      Like

  1. Is there any way of doing this while allowing Processor Expert to generate the linker file itself? I’ve had to disable “Generate Linker File” in order to maintain the modification to the linker file. Not a big deal, just curious if it’s possible. I didn’t see anything while looking through PE.

    Like

  2. Pingback: GNU Linker, can you NOT Initialize my Variable? | MCU on Eclipse

  3. Hi Erich, I’m looking for a DoOnStack equivalent for Kinetis and Google redirects here. Do you know if a DoOnStack equivalent routine exist? Thank you

    Like

  4. Eric,

    i am using your post for embedding a version inside the output file.
    i did as you have described:
    in the linker script:
    .myBufBlock 0x00000000 : {
    KEEP(*(.myBufSection))
    } > DDR2_SDRAM_MEM_BASEADDR

    in the code:
    int __attribute__((section (“.myBufSection”))) SWVersionInFile = 0x0306060A; // 3.6.6.10

    the problem that in the output file itself, the data is placed as ASCII and not as its value.
    meaning that the values looks like that:
    30 33 30 36 30 36 30 41
    instead of::
    03 06 06 0A

    Where is the problem?
    Thanks.

    Like

    • Hi shurik,
      hmm, that’s really strange. I tried to replicate this, and added this to my .text section:
      .text :
      {
      . = ALIGN(4);
      *(.text) /* .text sections (code) */
      *(.text*) /* .text* sections (code) */
      *(.rodata) /* .rodata sections (constants, strings, etc.) */
      *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
      *(.glue_7) /* glue arm to thumb code */
      *(.glue_7t) /* glue thumb to arm code */
      *(.eh_frame)
      KEEP(*(.myBufSection))
      KEEP (*(.init))
      KEEP (*(.fini))
      . = ALIGN(4);
      } > m_text
      but for me the result was as expected (0x306060a). Could it be that you look at the wrong variable? Can you verifiy in the linker map file that your variable has indeed be linked (and not be removed by the linker as not used?).

      Like

  5. Hello Erich,
    first of all thanks for the good solution!
    I would like to ask this: if I need to create more than one variables ( I need few arrays..), have I to declare a section for each array? Or there is easier way, using code instead of adding more sections?

    Thanks!

    Like

    • Found it 🙂
      u simple declare the second array just after the first one, with the same __attribute__((section (“.myBufSection”))).
      The linker will put the second array in the location just after the first one.

      Like

      • I do not believe that there’s any guarantee that they will end up in memory in source-order. See however my (simpler) alternative method in the comments above; you can just do
        buf = 0x20000000;
        buf2 = buf + 0x1000;
        or whatever. BTW, I put them in a SECTIONS { } block above, but that actually turns out to be optional. You can just put assignments like those in a text file named “whatever.ld” and provide it to ld or even to gcc as a source file (or rather, it is treated as an object file of a slightly strange sort).

        Like

  6. I wonder if I can use this technique so I can make use of the 832-byte memory area in the KL05 that occupies the space between the end of the m_interrupt area at address 0xc0 and the 16-byte “Flash Configuration Field” – fixed at address 0x400. This appears to be wasted. Can I set m_text start address to 0xc0 simply tell the linker to place the Flash Configuration Field (defined as _cfm[] in Cpu.c) at 0x400?

    I tried to copy your example and ended up with _cfm correctly at 0x400, but none of the space between 0xc0 and 0x400 was used.

    Like

  7. An example for ARM:

    asm (“.set mivar, 0x1234”);
    extern int mivar;

    main(int argc, char **argv)
    {
    mivar=0x4567;
    }

    This is the code generated:

    00008018 :
    8018: e59f2008 ldr r2, [pc, #8] ; 8028
    801c: e59f3008 ldr r3, [pc, #8] ; 802c
    8020: e5832000 str r2, [r3]
    8024: e12fff1e bx lr
    8028: 00004567 .word 0x00004567
    802c: 00001234 .word 0x00001234

    Like

      • You’re welcome.
        BTW, you may also consider to include the following asm line if you’re going to reference the absolute variable from a different source file:

        asm (“.global mivar”);

        The main problem I’m seeing with this solution is the lack of portability due to the different assembler directives for other architectures.

        Like

  8. Thanks for the information. I tried both methods above and my variable is indeed at the location I want, however the linker also put another variable at the same location. This is verified by seeing the other variables address in both the map file as well as in the watch window. Any suggestions?

    Like

  9. Hey Erich
    Awesome Solution. Now We know how to place a variable in a specific location. But If I want to place a piece of code in a specific memory address. What should I do ?

    unsigned int i;
    for(;;){
    Bit1_ClrVal(); // passing ‘0’ to CR1 LED port

    for(i=0;i<=1000000;i++); //software delay

    Bit1_SetVal(); // passing '1' to CR1 LED port

    for(i=0;i<=1000000;i++); //software delay

    }
    I want to put this code into the flash memory area of my KINETIS E series controller (MKE02Z64VLD2). Flash region is 0X0000_0000 to 0X07FF_FFFF. Can u say how it is done ?
    Thanks
    Regards
    Ganesh R

    Like

  10. Thanks a ton for this post! I need to be able to reprogram data in non-volatile memory, and my chip can only do that 4kB at a time. I can’t mess with the execution instructions that the data used to be mixed in with, so I can’t just use an absolute pointer as others suggested. I need a section of ROM that I know I can mess with without interrupting operation of the device.

    Like

  11. Erich, is there a way to get the base address for a section that is defined in the linker script (like the .myBufSection you created in your example above), if for example, you wanted to read a few bytes starting from the beginning of this section ?

    Like

  12. Pingback: Accessing GNU Linker Script Symbols from C/C++ | MCU on Eclipse

  13. Pingback: Flash-based Configuration Data Using The ld Linker – vilimblog

  14. I have two comments to add:

    1. Given this code:

    unsigned char __attribute__((section (“.myBufSection”))) buf[128] __attribute__ ((aligned (512)));

    I think it can be written in a shorter manner by separating the attributes with a comma:

    unsigned char __attribute__((section (“.myBufSection”), aligned (512))) buf[128];

    2. By using the “used” attribute, GCC is explicitly told not to dead-strip the variable when not referenced. I think it’s similar to the KEEP() directive of link scripts:

    void __attribute__ ((used, section (“.init3”), naked)) move_sp(void) {…}

    Like

    • Yes, __attribute__ settings can be combined, but sometimes they have be before or after a declaration. I have not checked in that particular case if both can be before the declaration.
      The used attribute is something too, but to my knowledge it is working for functions only, but not for variables. That way the KEEP inside the linker script is very useful.

      Like

      • Thanks for the correction on both accounts, Erich! It’s always great to learn new stuff from you. 🙂

        Like

  15. Thank you very much Erich! This is a great thing and helps a lot! I’ve tested it with success in debug mode. If I switch to Release it doesn’t work any more. I found out the reason: Debug Setting -> Optimization Level: None, Release Setting -> Optimization Level: Optimize for size. If I change this in Release mode it works well again. But I have bigger code-size. I thought the KEEP instruction in the linker script would prevent this? Or am I doing something wrong?
    Regards, Dirk

    Like

      • Hello Erich, thank you for your reply. I have already looked into your source code, but have not yet come across something that helped. The development environment is Infineon DAVE 4.3.2 (ARM-GCC-49). The Device: XMC4500. I will continue looking for a solution. If I have it, set it here as well. Thanks, Erich! Regards, Dirk

        Like

  16. Pingback: Getting Started: ROM Bootloader on the NXP FRDM-KL03Z Board | MCU on Eclipse

  17. Pingback: Using Multiple Memory Regions with the FreeRTOS Heap | MCU on Eclipse

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s