开发者

Extern variable at specific address

开发者 https://www.devze.com 2023-01-03 19:06 出处:网络
Using C++ and GCC, can I declare an extern variable that uses a specific address in memory? Something like

Using C++ and GCC, can I declare an extern variable that uses a specific address in memory? Something like

int key __attribute__((__at(0x9000)));

AFAIK this specific option only works on embedded systems. If there is such an op开发者_StackOverflow中文版tion for use on the x86 platform, how can I use it?


Easy option:

Define

int * const key = (int *)0x9000;

and refer to *key elsewhere (or use a reference).

Pointerless option:

All externs have specific addresses! These addresses may not be known until link time, but they must get resolved eventually. If you declare extern int key; then you must supply an address for the symbol key at link time. This can be done using a linker script (see Using ld) or at the linker command line, using the --defsym option.

If running gcc, you could use the -Xlinker flag to pass the option on to the linker. In your example,

gcc -o outfile -Xlinker --defsym -Xlinker key=0x9000 sourcefile.c

The following program, thus compiled, outputs 0x9000.

#include <stdio.h>
extern int key;
int main(void) {
    printf("%p\n", &key);
    return 0;
}

If you have a collection of variables you want to be in some region of memory, a more appropriate method might be to use output sections as suggested by Nikolai, perhaps in conjunction with a custom ld script.


I can't find this attribute in GCC docs. It doesn't make sense for general-purpose programs because many modern systems provide address space layout randomization. The best you can ask for, I guess, is to put a variable into a specific section, as in

int init_data __attribute__ ((section ("INITDATA")));

Also, if you know [virtual] address of a variable, why not just access via pointer:

int* pkey = ( int* )0x9000;
*pkey = 0xdeadbeef;


You could just use a macro:

#define KEY (*(int*)0x9000)

so that any writes to KEY write to that memory location, and any reads to KEY read from that memory location.

If that memory location could change outside of your control (e.g. if it represents a hardware register or some sort of memory-mapped I/O), then you should declare it volatile:

#define KEY (*(volatile int *)0x9000)

This will force the compiler to re-read the value from memory each time you read it and rewrite it back to memory every time you write it, instead of possibly caching it in a register.


Since you tagged this with c++, you could easily use placement new. Which is nice and portable:

// an object type T at address 0x9000
T* t = new(reinterpret_cast<void*>(0x9000)) T;

Obviously this won't be a global since new can be used outside of a function. But you could easily have a function you call as early as possible to initialize some globals this way.


It won't work for desktop applications (for memory mapped I/O in device drives it can make sense) because the memory is virtualized over the MMU on x86 platforms. So you will not know what physical address will be located somewhere in virtual space.

What would be the use case beside testing memory I/O or some other hack? On x86 in user space each memory cell is equivalent... To access variables use their name dlsym() is your friend under Linux, GetProcAddr() under Windows. Specifying the address yourself is not foreseen AFAIK.

Even providing a so called preferred load address for a shared lib or dll will not help, because it can be relocated to another place in case of overlap with other shared libs. The address randomization feature in modern OS'es makes it nearly unpredictable (what is the goal to avoid reproducible buffer overflow attacks)


I think that IAR's C compiler uses a non-standard extension that looks like

char foo @ 0x9000;

for this, at least for their MSP430 compiler. I never used GCC for the MSP430 much, but I think that it may have supported this as well so that it could achieve source compatibility with IAR's compiler.

If you want to do something that will work on all compilers without messing around with the linker you have to work a little harder up front.

#define CONST_ADDR_VAR( type, name, address ) type *const name##_addr =(type *)address

After calling that for each variable you want to specify you will also need to do #define var (*var_addr)

It would be nice if this could have been combined with the previous macro, but defining a macro within a macro isn't standard. I think there is a way to do it with GCC's preprocessor, though.

If you want to monkey around with your linker then you could probably find a way to tell it where these variables lived and just use them as extern in your C programs.

You could also use GCC's __attribute__((section( ... ) )) to do this, but you may end up needing a different section for each variable that you want to specify the address of. There were some other things that seemed a little confusing about this, and it would require you to tell the linker where these sections were anyway.

http://www.ohse.de/uwe/articles/gcc-attributes.html#var-section


No. Modern desktop operating systems use virtual memory, meaning that whatever address you have is meaningless until you give it to the OS, making a specific memory address worthless. There is no way and no advantage to this on desktop/x86.

0

精彩评论

暂无评论...
验证码 换一张
取 消