13

As i am relatively new to C , i have to use for one of my projects the following: i must declare some global variables which have to be stored every time the program runs at the same memory address. I did some read and i found that is i declare it "static" it will be stored at the same memory location.

But my question is: can i indicate the program where to store that variable or not. For example : int a to be stored at 0xff520000. Can this thing be done or not? i have searched here but did not found any relevant example. If their is some old post regarding this, please be so kind to share the link .

Thank you all in advance. Laurentiu

Update: I am using a 32uC

Laurentiu
  • 143
  • 1
  • 2
  • 8
  • 1
    It's common on embedded systems to have hardware registers at specific addresses. However, on a normal PC it's impossible to to predict where your variables will end up, and you can similarly not place variables on specific memory locations as the memory map of a program is not fixed. Is this for an embedded system or for a normal PC? – Some programmer dude Mar 07 '13 at 09:11
  • 1
    Why does the address matter? It is **virtual** memory anyway. – UmNyobe Mar 07 '13 at 09:11
  • Hello, i have to do the following. Do a kind of test platform for an 32 bit uC, but after flashing via OCD, the platform should have (run) on UART communication. And let's say i have a counter which counts how many time the program has run, or a counter storing how many time the program run without errors, then my professor what to give as input via Hyper Terminal the address where that variable counter is located, in order to get it's value. That is what i need.. any ideas : – Laurentiu Mar 07 '13 at 09:16
  • http://www.keil.com/support/man/docs/armcc/armcc_chr1359124981140.htm – AlphaGoku Nov 09 '16 at 05:15
  • related: https://stackoverflow.com/questions/9372936/can-we-assign-a-value-to-a-given-memory-location – Ciro Santilli OurBigBook.com Sep 19 '17 at 08:53

8 Answers8

15

In your IDE there will be a memory map available through some linker file. It will contain all addresses in the program. Read the MCU manual to see at which addresses there is valid memory for your purpose, then reserve some of that memory for your variable. You have to read the documentation of your specific development platform.

Next, please note that it doesn't make much sense to map variables at specific addresses unless they are either hardware registers or non-volatile variables residing in flash or EEPROM.

If the contents of such a memory location will change during execution, because it is a register, or because your program contains a bootloader/NVM programming algorithm changing NVM memory cells, then the variables must be declared as volatile. Otherwise the compiler will break your code completely upon optimization.

The particular compiler most likely has a non-standard way to allocate variables at specific addresses, such as a #pragma or sometimes the weird, non-standard @ operator. The only sensible way you can allocate a variable at a fixed location in standard C, is this:

#define MY_REGISTER (*(volatile uint8_t*)0x12345678u)

where 0x12345678 is the address where 1 byte of that is located. Once you have a macro declaration like this, you can use it as if it was a variable:

void func (void)
{
  MY_REGISTER = 1;  // write
  int var = MY_REGISTER;  // read
}

Most often you want these kind of variables to reside in the global namespace, hence the macro. But if you for some reason want the scope of the variable to be reduced, then skip the macro and access the address manually inside the code:

void func (void)
{
  *(volatile uint8_t*)0x12345678u = 1; // write
  int var = *(volatile uint8_t*)0x12345678u; // read
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Thank you. This is what i wanted. I took your advice and found the following:MEMORY iROM : ORIGIN = 0x00000000, LENGTH = 3072k iRAM : ORIGIN = 0xFEDC0000, LENGTH = 256k BURAM : ORIGIN = 0xFF760000, LENGTH = 16k
    I suppose i have to selec some range from the RAM from what i need right ?
    – Laurentiu Mar 07 '13 at 12:26
  • 1
    By the way : I why you used address like 0x12345678u ? what the u from the end represent ? – Laurentiu Mar 07 '13 at 12:35
  • 2
    @Laurentiu An `u` (or `U`) suffix means that the integer literal is of type `unsigned`. It is there to guarantee that the indented type is used, I wrote it mainly out of old habit. An integer literal in C source is of type (signed) `int` by default, but since an address can never be negative, it doesn't make sense to use a signed variable to store it. In general, you never want to use the default `int` type in embedded systems. In some cases when doing plain arithmetic, you may want to the use `sintN_t` types, where N=8, 16 etc. But most of the time, you only use unsigned variables. – Lundin Mar 07 '13 at 12:43
  • 1
    Thanks again. I still have you question, regarding a problem i just saw: i did the following :#define counter (*(volatile unsigned int*)0xfedc0010).And then in my function i did some operations on the variable. But when i checked the memory map in debug mode i saw that at that particular address the compiler has also assign another variable ? so from my point of view this is a real problem because then both are stored at the same memory location meaning one will overwrite each other value. So any ideas ? – Laurentiu Mar 07 '13 at 13:14
  • 2
    @Laurentiu You need to know what you are doing. Unless the linker knows that an object is stored at that location, nothing will work. `"You have to read the documentation of your specific development platform"` wasn't just an advisory statement, if you don't do this and understand it, your program will not work. – Lundin Mar 07 '13 at 13:16
8

You can do this kind of thing with linker scripts, which is quite common in embedded programming.

On a Linux system you might never get the same virtual address due to address space randomization (a security feature to avoid exploits that would rely on knowing the exact location of a variable like you describe).

If it's just a repeatable pointer you want, you may be able to map a specific address with mmap, but that's not guaranteed.

Ben Jackson
  • 90,079
  • 9
  • 98
  • 150
  • True. As i think using mmap, to map address-space to file could solve problem. Its just that care will have to be taken so that mmap(CONST_ADDR, ....., fd, CONST_FILE_OFFSET); will not fail ever(or map at diff-addr than COSNT_ADDR). Then CONST_ADDR becomes the address of global variable, and changes to made to this global counter will reflect in file, which could be used further in next program. – rahul.deshmukhpatil Mar 07 '13 at 09:49
2

Like was mentioned in other answers - you can't. But, you can have a workaround. If it's ok for the globals to be initialized in the main(), you can do something of this kind:

int addr = 0xff520000;

int main()
{
    *((int*)addr) = 42;
    ...
    return 0;
}

Note, however, that this is very dependent on your system and if running in protected environment, you'll most likely get a runtime crash. If you're in embedded/non-protected environment, this can work.

SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
  • This one works. But can you please tell me how i can find a location where to store actually my variable ? Because i suppose i cannot use some ramdom memory areas of the uC? – Laurentiu Mar 07 '13 at 09:38
  • @Laurentiu In your IDE there will be a memory map available through some linker file. It will contain all addresses in the program. Read the MCU manual to see at which addresses there is valid memory for your purpose, then reserve some of that memory for your variable. You have to read the documentation of your specific development platform. – Lundin Mar 07 '13 at 10:21
1

No you cannot tell it explicitly where to store a variable in memory. Mostly because on modern systems you have many things done by the system in regards to memory, that is out of your control. Address Layout Randomization is one thing that comes to mind that would make this very hard.

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
1

according your compiler if you use XC8 Compiler. Simply you can write int x @ 0x12 ;

in this line you set x in the memory location 0x12

0

Not at the C level. If you work with assembly language, you can directly control the memory layout. But the C compiler does this for you. You can't really mess with it.

Even with assembly, this only controls the relative layout. Virtual memory may place this at any (in)convenient physical location.

luser droog
  • 18,988
  • 3
  • 53
  • 105
0

You can do this with some compiler extensions, but it's probably not what you want to do. The operating system handles your memory and will put things where it wants. How do you even know that the memory address you want will be mapped in your program? Ignore everything in this paragraph if you're on an embedded platform, then you should read the manual for that platform/compiler or at least mention it here so that people can give a more specific answer.

Also, static variables don't necessarily have the same address when the program runs. Many operating systems use position independent executables and randomize the address space on every execution.

Art
  • 19,807
  • 1
  • 34
  • 60
0

You can declare a pointer to a specific memory address, and use the contents of that pointer as a variable I suppose:

int* myIntPointer = 0xff520000;
SteveP
  • 18,840
  • 9
  • 47
  • 60