Post navigation

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:

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

54 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?

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

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.

Actually I discovered it’s even simpler: you can just put a bunch of assignment statements in a file and pass it to the linker as if it’s an object file. This works regardless of whether you also have a custom linker script, and you can pass multiple of such files if you wish.

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?

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.

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).

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.

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?

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.

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 ?

Hi Geoff,
yes, there should be a way, at least for the section name, maybe with an additional label in the linker script. I’m travelling today, but I see in the evening/tonight if I could write up something small on that topic.
Erich

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.

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

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