How to place a variable at a given absolute address in memory (with GCC)

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.


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.


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.