41

The RealView ARM C Compiler supports placing a variable at a given memory address using the variable attribute at(address):

int var __attribute__((at(0x40001000)));
var = 4;   // changes the memory located at 0x40001000

Does GCC have a similar variable attribute?

Prof. Falken
  • 24,226
  • 19
  • 100
  • 173
Bas van Dijk
  • 833
  • 1
  • 8
  • 11
  • 4
    I wrote an [article](http://a3f.at/articles/register-syntax-sugar), where I enumerate the means to do so. Might be useful for some. – a3f May 08 '16 at 21:13

8 Answers8

33

I don't know, but you can easily create a workaround like this:

int *var = (int*)0x40001000;
*var = 4;

It's not exactly the same thing, but in most situations a perfect substitute. It will work with any compiler, not just GCC.

If you use GCC, I assume you also use GNU ld (although it is not a certainty, of course) and ld has support for placing variables wherever you want them.

I imagine letting the linker do that job is pretty common.

Inspired by answer by @rib, I'll add that if the absolute address is for some control register, I'd add volatile to the pointer definition. If it is just RAM, it doesn't matter.

Prof. Falken
  • 24,226
  • 19
  • 100
  • 173
  • +1 for creativity. Don't know if it actually works, but it sounds really plausible, as well as portable (in the sense that it should work for all compilers). – falstro Nov 01 '10 at 09:41
  • 3
    @roe: It's a fairly standard trick usable in device drivers for hardware with fixed memory mapped control registers.In a standard user application, it has no utility whatever that I can think of. – JeremyP Nov 01 '10 at 09:46
  • 2
    @JeremyP, in embedded devices, especially those with no MMU, it is all too common to let the "user applications" hit the hardware. – Prof. Falken Nov 01 '10 at 09:47
  • @Amigable Clark Kant: Agreed. By "standard user application" I really meant those that run on modern general purpose computers in the user space. – JeremyP Nov 01 '10 at 09:51
  • 3
    @JeremyP; that was more or less my point, the question doesn't state whether the memory is accessible in this manner, or if you need the compiler to take certain actions to make it happen. – falstro Nov 01 '10 at 09:59
  • @JeremyP, yes, I figured. I just can't let go of the times when a "modern general purpose computer" was an Amiga 500. :-) (But even back then, writing to absolute addresses was frowned upon.) – Prof. Falken Nov 01 '10 at 10:00
  • @Prof.Falken: I'm not sure what you mean by "all too often". In many embedded devices, if "user applications" couldn't hit the hardware, nothing ever would. While defining symbolic names for addresses is generally useful, and it would be helpful for compilers to provide an option to interpret lvalues from integer-to-pointer casts as implicitly requiring volatile access (since for whatever reason many chip vendors include header files that neglect the volatile qualifier), I'm not sure what you'd want to see different. – supercat Oct 26 '15 at 18:00
  • @supercat, I didn't mean exactly like that. I agree with you. I meant something more like "alas, we have not come as far as doing away with low-level programming". It's more like it's increasing, with evermore embedded programming in everything. But it's not like I complain, I quite like embedded and systems programming. :) But still, I think symbolic names can be useful. The Amiga OS even had "runtime" symbolic addresses. You would read from address $4, which contained a pointer to a jump table of syscalls. Even with no MMU, you did not have to rely on fixed addresses for OS calls. I digress – Prof. Falken Oct 27 '15 at 12:55
  • 1
    @Prof.Falken: I do think certain things are unfortunate; compilers used to expose underlying hardware behavior for most forms of UB, while today there's more of a tendency to do UB-based "optimizations". It used to be that `(x<>(32-n))` was the canonical way of doing a "rotate left", and it used to work on 99.999% of platforms where x could be an unsigned 32-bit type (I know of no exceptions other than those configured for exceptionally-pedantic mode) but some of today's compilers will examine that expression and infer that x cannot be zero. There were historically only... – supercat Oct 27 '15 at 14:31
  • 1
    ...two ways processors would have handled `x>>32`, and either of them would have worked equally well in that expression. Since the standard considers it UB, though, some compiler writers see no reason to expose underlying hardware behavior. – supercat Oct 27 '15 at 14:33
  • 2
    I would change the type of the pointer to `int *const`, so the compiler may optimize the dereference away. – a3f May 08 '16 at 21:17
  • 1
    The pointed-to object should be almost always declared **volatile** for this to be in any way useful, Otherwise, why would it matter where it resides in the memory. – Antti Haapala -- Слава Україні Jul 25 '17 at 13:42
  • 1
    @AnttiHaapala? Let's assume it's a global variable at a known address. It could still be cached by CPU cache with no ill effect. However, if the address represents memory mapped I/O, then the value could be changed from "under your feet" by external events. Then volatile is very useful. Or am I completely missing the point? – Prof. Falken Jul 25 '17 at 20:39
  • My point is that if it doesn't matter whether the reads and writes are optimized out, then it hardly matters where in memory the object resides - let the compiler decide. – Antti Haapala -- Слава Україні Jul 25 '17 at 21:30
  • @AnttiHaapala, generally, yes. But in Amiga Kickstart, the address was $4, whether you liked it or not. And I know embedded systems with fixed addresses for shared global variables. – Prof. Falken Jul 25 '17 at 21:40
24

You could use the section attributes and an ld linker script to define the desired address for that section. This is probably messier than your alternatives, but it is an option.

Thomas M. DuBuisson
  • 64,245
  • 7
  • 109
  • 166
  • 10
    Note that this approach will *actually reserve* space for the variable, rather than simply assuming it exists at the address specified. In many cases, this is what you want. –  Jan 29 '15 at 06:03
  • A more direct link for the section attributes: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes and ctrl+f for "section" – Ponkadoodle Jul 31 '15 at 20:56
  • 2
    Unfortunately sometimes tools try to make things simpler by hiding/auto-generating the the linker script so it is hard to modify it (I'm looking at you Arduino and ATMEL Studio). I would great to find a way to anchor a variable to a fixed address and have it allocate the space in an existing segment using only code. :/ – bigjosh Nov 11 '18 at 18:18
  • I have provided a minimal runnable linker script example at: https://stackoverflow.com/questions/4067811/how-to-place-a-variable-at-a-given-absolute-address-in-memory-with-gcc/54128613#54128613 – Ciro Santilli OurBigBook.com Jan 10 '19 at 12:21
19

Minimal runnable linker script example

The technique was mentioned at: https://stackoverflow.com/a/4081574/895245 but now I will now provide a concrete example.

main.c

#include <stdio.h>

int myvar __attribute__((section(".mySection"))) = 0x9ABCDEF0;

int main(void) {
    printf("adr %p\n", (void*)&myvar);
    printf("val 0x%x\n", myvar);
    myvar = 0;
    printf("val 0x%x\n", myvar);
    return 0;
}

link.ld

SECTIONS
{
  .mySegment 0x12345678 : {KEEP(*(.mySection))}
}

GitHub upstream.

Compile and run:

gcc -fno-pie -no-pie -o main.out -std=c99 -Wall -Wextra -pedantic link.ld main.c
./main.out

Output:

adr 0x12345678
val 0x9abcdef0
val 0x0

So we see that it was put at the desired address.

I cannot find where this is documented in the GCC manual, but the following syntax:

gcc link.ld main.c

seems to append the given linker script to the default one that would be used.

-fno-pie -no-pie is required, because the Ubuntu toolchain is now configured to generate PIE executables by default, which leads the Linux kernel to place the executable on a different address every time, which messes with our experiment. See also: What is the -fPIE option for position-independent executables in gcc and ld?

TODO: compilation produces a warning:

/usr/bin/x86_64-linux-gnu-ld: warning: link.ld contains output sections; did you forget -T?

Am I doing something wrong? How to get rid of it? See also: How to remove warning: link.res contains output sections; did you forget -T?

Tested on Ubuntu 18.10, GCC 8.2.0.

ahogen
  • 759
  • 8
  • 20
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 1
    Santilli: Just now, you cannot avoid the linker warning. See my answer to https://stackoverflow.com/questions/20185268/how-to-remove-warning-link-res-contains-output-sections-did-you-forget-t – hermannk Jan 15 '19 at 09:46
  • I don't know about gcc, but I don't get any warning with clang when using link flags `-Wl,-T link.ld`. Ok, and after reading the other comment, please note I have added the line `INSERT AFTER .data` to given link.ld file. – fuujuhi Jun 07 '23 at 17:59
12

You answered your question, In your link above it states:

With the GNU GCC Compiler you may use only pointer definitions to access absolute memory locations. For example:

#define IOPIN0         (*((volatile unsigned long *) 0xE0028000))
IOPIN0 = 0x4;

Btw http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Variable-Attributes.html#Variable%20Attributes

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
rib
  • 369
  • 1
  • 6
  • Interesting, didn't know that. – Prof. Falken Sep 07 '11 at 07:58
  • 1
    in fact, with this approach you are not limited to only one variable. You can do this also with pointers to structs, representing the entire set of registers for a particular peripheral – LoPiTaL Jan 10 '19 at 17:23
6

Here is one solution that actually reserves space at a fixed address in memory without having to edit the linker file:

    extern const uint8_t dev_serial[12];
    asm(".equ dev_serial, 0x1FFFF7E8");
/* or    asm("dev_serial = 0x1FFFF7E8"); */
    ...
        
    for (i = 0 ; i < sizeof(dev_serial); i++)
        printf((char *)"%02x ", dev_serial[i]);
fearless_fool
  • 33,645
  • 23
  • 135
  • 217
user6409471
  • 69
  • 1
  • 1
  • 1
    What does this add to the existing answers? – OrangeDog Jun 01 '16 at 12:17
  • 2
    While this code snippet may solve the question, [including an explanation](https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations! – Box Box Box Box Jun 01 '16 at 13:06
  • 2
    This does actually add something that the other answers don't. By using this approach you can position a fixed length array while still allowing `sizeof()` to get the array size. – Tom Carpenter Mar 22 '18 at 08:44
  • This asm approach works for C++ templates e.g., MySerial<&dev_serial> whereas the cast-pointer approach results in errors - see https://stackoverflow.com/questions/67037386/how-to-create-a-constexpr-pointer-to-a-register-on-embedded-system – Jim Fred Dec 07 '22 at 15:51
0

In GCC you can place variable into specific section:

__attribute__((section (".foo"))) static uint8_t * _rxBuffer;

or

static uint8_t * _rxBuffer __attribute__((section (".foo")));

and then specify address of the section in GNU Linker Memory Settings:

.foo=0x800000 
zmechanic
  • 1,842
  • 21
  • 27
0

I had a similar issue. I wanted to allocate a variable in my defined section at a special offset. In the same time I wanted the code to be portable (no explicit memory address in my C code). So I defined the RAM section in the linker script, and defined an array with the same length of my section (.noinit section is 0x0F length).

uint8_t no_init_sec[0x0f] __attribute__ ((section (".noinit")));

This array maps all locations of this section. This solution is not suitable when the section is large as the unused locations in the allocated array will be a wasted space in the data memory.

Yahya Tawil
  • 395
  • 4
  • 10
-1

The right answer to my opinion is the Minimal runnable linker script example one.

However, there was something not mentioned there: If the variable is not used in code (e.g. the variable holds read-only data such as version...), it is necessary to add the 'used' attribute.

int myvar attribute((section(".mySection")), used) = 0x9ABCDEF0;

Refer to my answer at https://stackoverflow.com/a/75468786/3887115.

Y.H.Cohen
  • 41
  • 7
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/33859562) – Raf Feb 21 '23 at 12:35