How to reserve a fixed flash section for data? - c

I need to store some large chunks of data in flash memory, where it will be read often and occasionally be rewritten using SPM. I already figured out how to use pointers to __flash and pgm_read_byte to access it, how not to omit the const (despite my writing to it), how to actually access the array in a loop so that it doesn't get completely optimised away (after inlining), but I don't really understand how to declare my array.
const uint8_t persistent_data[1024] __attribute__(( aligned(SPM_PAGESIZE),
section("mycustomdata") )) = {};
works about fine, except that I do not want to initialise it. When programming my device (an Arduino ATmega328P), I want this section to be keept so that it retains the data previously written by the application. The above does zero-initialise it, and my hex file contains zeroes that the programmer happily uses to overwrite my data.
Using the __flash modifier instead of __attribute__(( section("…") )) does about the same here, except that it places the array elsewhere and I don't have any control about where it is put. It still does this when I use __flash and omit the initialisation (though I get a "uninitialized variable 'persistent_data' put into program memory area [-Wuninitialized]" warning).
Now I am trying to omit the initialiser:
const uint8_t persistent_data[1024] __attribute__(( aligned(SPM_PAGESIZE),
section("mycustomdata") ));
and get rather unexpected results. The sections data from the .lss output shows
Idx Name Size VMA LMA File off Algn
…
1 mycustomdata 00000480 00800480 000055e2 00005700 2**7
CONTENTS, ALLOC, LOAD, DATA
2 .text 00005280 00000000 00000000 000000d4 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
This does put all the initialisation zeroes in the hex file at the load memory address 55E2 (instead of omitting them), while the virtual memory address (which the variable persistent_data points to) refers to 0480 - in the middle of the code from the text section!
(I also tried to omit the const, and to omit the const and the initialiser, which both had the same effect as omitting only the initialiser).
I am at a loss. Do I need to use extern maybe? (Any attempt at doing so ended up with a "undefined reference to persistent_data" error). Do I need to use a linker script?
How do I make persistent_data refer to a location is program memory that is not used by any other data, and have the compiler not emit any initialisation data for that location in the hex file?

You don't seem to realize that you actually need two versions of your hex file - one that is suitable for a "new" installation on a new (or worse: re-used, thus with random flash content) chip that initializes the flash section to make sure there is no arbitrary data in there that might be interpreted, and another one used to update a pre-programmed chip that misses this section in order to keep data already modified by your users. So, you are going to need the version that initializes this section anyhow.
The simplest way to achieve this is like your first example, initialize the data to build the "naked chip" version of your code, and produce the "update" version by simply removing this initialized section from the object file with objcopy (assumed you use a GNU toolchain). See the -R option of this tool.
Also, make sure this data section is located at a fixed address - you don't want it to move every time you change something in your code.
I would rather try and use EEPROM if available than go through the hassle of reprogramming.

Related

Why is there no content for the .bss section in an object (ELF) file?

This question confused me a lot. As far as I know, .bss section is for saving data that initialized but not used yet. But I don't understand what 'content' here mean and why there is no content here?
Thanks for any helps!
The quick response is: Well, there's no content to fill the .bss with, so there's no sense in putting any data on the executable in relation to that section. Only the positions of the variables are stored, but that belongs to another ELF section.
.bss section is where your program has all the uninitialized variables (by default all initialized to zero) The linker only needs to know the actual size of this region and the actual variable positions, but not the values, because its contents are obvious, independently of the nature or the distribution of the variables put there.
When your program is loaded, the kernel normally assigns a read-only segment for the unmodifiable text of the program (.text section) and also puts in that segment the contents of the initialized const variables (.rodata section) so in case yo attempt to modify something there, you get an exception. Then comes the initialized data section with the initial values of all the initialized variables of your program (.data section) and the uninitialized ones (.bss section)
The data segment (look how I call different a section and a load segment) is given more space, the sum of .data and .bss sections, to hold all the variables (both are included, so that's the reason it uses its length) but while the contents of the .data section have to be filled from the file, the contents of the .bss section don't, because all are zeroed by the operating system, before allowing the user process to access the allocated segment. That's not true for small systems, where the operating system doesn't fill the data with zeros... but there, the compiler adds some code to zero all the .bss segment, so again, there's no need to copy any data from the executable file.
The historic (and main) reason for this behaviour is that the pages the kernel assigns that have to be loaded with your program, are cleared to zero for security reasons (so you cannot luckily get a page full of other users' passwords, or other sensible information) so there's no reason to fill it with zeros again and nothing has to be copied there, there's no reason to put anything on the executable file. The pages the kernel maintains normally are zeroed only when they are going to be given to a user, but maintain (as they are designed for that purpose) the information until they are overwritten.
There's no content in the BSS (Block started By Symbol) section because it would be wasted storage. The contents of the BSS is all zeros and it is cleared by the startup code before main is called. Think of the BSS as a run-length compressed block of bytes. All you need to know to uncompress that block is the value (0) and the length, which is stored in the ELF entry for the BSS.
Your notion of "data that [is] initialized but not used yet" is a bit off. Consider that all sections in an ELF file are somehow "not used yet". The text segment may or may not become used (it may contain dead/unreachable code). The data segment may or may not be used at all (you can define objects never used by code).

IAR EWARM 6.5 Storing a const variable in a certain address BUG?

I want to save an area of flash memory in stm32 to store my own config information.
To make this i want to save the second sector of the flash memory on STM32F2/STM32F4 (16kb stored at 0x08004000-0x08007FFF)
Checking internet and stackoverflow you have 4 ways to do this
1)
#pragma location=0x08004000
__no_init const char ReservedArea[16*1024];
2)
__no_init const char ReservedArea[16*1024] #0x08004000;
3) creating a section + #pragma location=
project icf:
place at address mem: 0x08004000 { readonly section ConfigSection };
c file:
#pragma location="ConfigSection"
__no_init const char ReservedArea[16*1024];
4)
Defining a section in project .icf file IAR define memory region for custom data
Bug or problem found
Method 1 to 3 works ok. Linker include a space area for my variable. You can check the .bin file generated with a hex editor or just debug and see that variable is # 0x08004000.
The problem found with these methods are that iar linker leave unused more than 12kbytes of flash memory between 0x08000800 - 0x08003FFF. The best way to verify this is to remove the var, compile, write in a note the size of the bin file and then add the variable. If you do this you will notice that new bin file size is greater than 16kb when it must be exact 16kb.
If you move the address from 0x08004000 to 0x0800C000 without any other change the file size will increase in another 32kbytes and all the previous area is set to 0x00 and unused in the bin file. This is a big problem for our project because i use the rest of the unused area out of the bin file to allow firmware update.
Checking the map file you will see that the area previous to the reserved zone is unused too.
I tried several ways to fix this with no luck, for example defining 2 variables with address, playing for hours, checking linker options, optimizations, playing with other #pragma options, etc.
About the 4th method, it stores the variable in the system but it dont get the address that i wanted. Probably the problem was that both areas shared the address space.
icf file
define region LANGUAGE_region = mem:[from 0x08004000 to 0x08007FFF];
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
"LANGUAGE_PLACE":place at start of LANGUAGE_region { section .LANGUAGE_PLACE.noinit };
c code
extern const char ReservedArea[16*1024] #".LANGUAGE_PLACE.noinit";
const char ReservedArea[16*1024];
Is it my problem? is it a bug? Any tip is welcomed.
Thanks in advance.
This does not sound like a bug to me but rather an issue that you'll need to deal with. The .bin file is a raw memory file where each byte of the file maps to a byte in memory. How do you expect the .bin file to represent a byte located at offset 0x4000 or 0xC0000 without also representing all the bytes that come before that? The .bin file must include all the unused bytes between two memory sections in order to maintain the relative offset of the subsequent section.
Is your concern that the unused bytes are 0x00, and therefore they cannot be programmed without first being erased? If so then you can probably configure the linker (or whatever program you're using to create the .bin file) to use 0xFF instead of 0x00 for all unused bytes. Check the linker (or command line) options.
Or is your concern that the .bin file contains a lot of unused memory which will take longer to download and reprogram? Or is the .bin file now too large to fit in the memory region you've reserved for firmware updates? In either case, the solution is to divide the firmware update into two separate portions. For example, the first portion contains just the code starting at 0x08000000 and ending wherever the code ends. The second portion contains the data starting at 0x08004000. The size of the two portioned .bin files will be much less than the combined .bin file because they don't need to include all the unused memory in between. Your firmware update routines will need to be smart enough to recognize each portion and program them to the proper memory address.
If you don't want to deal with separate .bin files then you could consider downloading a .hex file as opposed to a .bin file. A .hex file is not a one-to-one mapping of memory bytes and contains coded information that allows unused memory regions to be skipped. However, your embedded firmware update routines will have to be smart enough to decode the hex file before programming the flash.
I am trying to place some constants into a know FLASH address, but using those methods dealt above I don't get the result. I tried with pragma location and I get no result a all, and also with the # but IAR complain about this. The variable I want to store is the version of the FW so it has a 12 bytes value and I declare it like this as a global value (outside the functions I want to mean, so it is accessible from all the functions of the .c):
#pragma location=0x00001FF0
__no_init const uint8_t version[12] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B};
I have also checked IAR documentation such as:
Technical Note 27498
I am using IAR 6.5 if it helps (because I noticed some methods require 6.70 newer!
EDITED:
Well, now it works doing the following:
In the .icf file:
/* Now I have a read only section in the ROM address 0x00001FF4 */
"ROM":
place at address mem:0x00001FF4 { readonly section .version };
In the .c source file:
#pragma location=".version"
__root const uint8_t version[12] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B};
Best regards,
Iván
Ok finally i understood how it works. The linker searchs the longest unused space to include the code there.
Personally I think that this is not the best way, i would prefer that the linker would use the first unused area if the function or the const variable has enough space to fit in.
To limit this I just added the next code (Example for stm32F4)
const char unusedarea[128*3*1024] #0x08020000 ;
#pragma required=unusedarea
This use the space between 0x08020000 and 0x0807FFFF and force the linker to use the other areas. And effectively it worked.
This allow me to reserve space but leaving the needed space free and unused. I can even remove the last 384 kb from the bin file, and upload only the first 128kbytes.
Edited. Setting those vars to __no_init bin file is still small and reserves áreas are not overwritted when using jtag

Make ARM Fromelf Output Binary With Zero Initialized Data

I have some data that are zero initialized.
I have allocated an execution region for them in the scatter file.
Some_Execution_Region +0
{
stuff.o (+RO, +RW, +RI)
}
But I don't see any segments of zero initialized data in the resulting binary after using fromelf to convert it from the axf file.
The binary file stops right before where the zero initialized data should start.
So the question is how I can make fromelf generate empty region for the zero initialized data in the binary file.
I've looked up on the ARM site and have had no luck. I only found out some option to disable zero initialized data. (Doesn't this mean since I'm not using that option, I should get my zero initialized data in my binary?)
I currently just run fromelf.exe --bin --output=binary.bin elffile.axf, which doesnt generate the zero data.
There's no need to actually store all of the zeros in the binary. If you are using C then the default is to zero-initialize static variables that are not explicitly initialized to some other value. The C runtime code doesn't copy zeros from the executable to RAM, it just gets the beginning and ending addresses of the part of RAM that needs to be zeroed. The typical way of telling the linker that variables must be zeroed at startup is to put them in the .bss (blanked static storage) segment, but you shouldn't need to do this explicitly unless you are writing assembly code.

why .bss explicitly initialize global variable to zero?

I am generating mips disassembly in order to simulating it. I need to have big data to work on it but I don't want to have big assembly files so I wanted to work on a big uninitialized array (and then possibly initialize it in my simulator...). So I need this array to be global. And global variables seem to be put on the .bss section to be initialized when the page is actually accessed.
The problem is in my binary the array is in the .bss section, but is explicitly filled with zero...This is not the behaviour expected if I understood correctly what I have found on internet...Is there a way for saying to the compiler (or linker, or loader...I don't understand well which one do what for that) to not really put zero in this array ?
Or alternatively, can we have an option while compiling, or a C instruction for saying we don't want this array for being initialized with 0 ? (I tried to change the array section with attribute but it is still initialized with 0).
By the way, I am generating my disassembly file with objdump, and it normally skip blocks of zeroes, but I really need the other blocks of zeroes to be disassembled, so I using the "-z" option.
What I really don't understand is that everywhere I looked, it was said that .bss section didn't really put zero in the binary file...
The data for the .bss section isn't stored in the compiled object files because, well, there is no data—the compiler puts variables in that segment precisely because they should be zero-initialized.
When the OS loads the executable, it just looks at the size of the .bss segment, allocates that much memory, and zero-initializes it for you. By not storing that data in the executable file, it reduces loading times.
If you want data to be initialized with certain data, then give it an initializer in your code. The compiler will then put it in the .data segment (initialized data) instead of .bss (uninitialized data). When the OS then loads the executable, it will allocate the memory for the data and then copy it in from the executable. This takes extra I/O, but your data is explicitly initialized how you want it.
Alternatively, you could leave the data stay in the .bss segment and then initialize it yourself at runtime. If the data is quick and easy to generate at runtime, it might be faster to recompute it at startup rather then read it off of disk. But those situations are probably rare.
I suspect that using the -z option is causing objdump to show you zeroes for the .bss, even though the zeroes are not actually in your binary. Try using od -t x4 to get a simple hexadecimal dump of what is really in the binary. If od shows you blocks of zeroes, then they really are in the binary.

Is there a way to know where global and static variables reside inside the data segment (.data + .bss)?

I want to dump all global and static variables to a file and load them back on the next program invocation. A solution I thought of is to dump the .data segment to a file. But .data segment on a 32bit machine spans over 2^32 address space (4GB). In which part of this address space the variables reside? How do I know which part of the .data segment I should dump?
And when loading the dumped file, I guess that since the variables are referenced by offset in the data segment, it will be safe to just memcpy the whole dump to the alleged starting point of the "variables area". Please correct me if I am wrong.
EDIT
A good start is this question.
Your problem is how to find the beginning and the end of the data segment. I am not sure how to do this, but I could give you a couple of ideas.
If all your data are relatively self-contained, (they are declared within the same module, not in separate modules,) you might be able to declare them within some kind of structure, so the beginning will be the address of the structure, and the end will be some variable that you will declare right after the structure. If I remember well, MASM had a "RECORD" directive or something like that which you could use to group variables together.
Alternatively, you may be able to declare two additional modules, one with a variable called "beginning" and another with a variable called "end", and make sure that the first gets linked before anything else, and the second gets linked after everything else. This way, these variables might actually end up marking the beginning and the end of the data segment. But I am not sure about this, I am just giving you a pointer.
One thing to remember is that your data will inevitably contain pointers, so saving and loading all your data will only work if the OS under which you are running can guarantee that your program will always be loaded in the same address. If not, forget it. But if you can have this guarantee, then yes, loading the data should work. You should not even need a memcpy, just set the buffer for the read operation to be the beginning of the data segment.
The state of an entire program can be very complicated, and will not only involve variables but values in registers. You'll almost certainly be better off keeping track of what data you want to store and then storing it to a file yourself. This can be relatively painless with the right setup and encapsulation. Then when you resume the application, read in the program state and resume.
Assuming you are using gnu tools (gcc, binutils) if you look at the linker scripts the embedded folks use like the gba developers and microcontroller developers using roms (yagarto or devkit-arm for example). In the linker script they surround the segments of interest with variables that they can use elsewhere in their code. For rom based software for example you specify the data segment with a ram AT rom or rom AT ram in the linker script meaning link as if the data segment is in ram at this address space, but also link the data itself into rom at this address space, the boot code then copies the .data segment from the rom to the ram using these variables. I dont see why you couldnt do the same thing to have the compiler/linker tools tell you where stuff is then runtime use those variables to grab the data from memory and save it somewhere to hybernate or shut down and then restore that data from wherever. The variables you use to perform the restore of course should not be part of the .data segment or you trash the variables you are using to restore the segment.
In response to your header question, on Windows, the location and size of the data and bss segments can be obtained from the in-memory PE header. How that is laid out and how to parse it is documented in this specification:
http://msdn.microsoft.com/en-us/windows/hardware/gg463119
I do not believe that there is a guarantee that with every execution you will have the sam sequence of variables, hence the offsets may point to the wrong content.

Resources