Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

storing structs in ROM on ARM device

Tags:

c++

memory

arm

I have some constant data that I want to store in ROM since there is a fair amount of it and I'm working with a memory-constrained ARM7 embedded device. I'm trying to do this using structures that look something like this:

struct objdef
{
   int x;
   int y;
   bool (*function_ptr)(int);
   some_other_struct * const struct_array; // array of similar structures
   const void* vp; // previously ommittted to shorten code
}

which I then create and initialize as globals:

const objdef def_instance = { 2, 3, function, array, NULL };

However, this eats up quite a bit of RAM despite the const at the beginning. More specifically, it significantly increases the amount of RW data and eventually causes the device to lock up if enough instances are created.

I'm using uVision and the ARM compiler, along with the RTX real-time kernel.

Does anybody know why this doesn't work or know a better way to store structured heterogenous data in ROM?

Update

Thank you all for your answers and my apologies for not getting back to you guys earlier. So here is the score so far and some additional observations on my part.

Sadly, __attribute__ has zero effect on RAM vs ROM and the same goes for static const. I haven't had time to try the assembly route yet.

My coworkers and I have discovered some more unusual behavior, though.

First, I must note that for the sake of simplicity I did not mention that my objdef structure contains a const void* field. The field is sometimes assigned a value from a string table defined as

char const * const string_table [ROWS][COLS] =
{
  { "row1_1", "row1_2", "row1_3" },
  { "row2_1", "row2_2", "row2_3" },
 ...
}

const objdef def_instance = { 2, 3, function, array, NULL };//->ROM
const objdef def_instance = { 2, 3, function, array, string_table[0][0] };//->RAM

string_table is in ROM as expected. And here's the kicker: instances of objdef get put in ROM until one of the values in string_table is assigned to that const void* field. After that the struct instance is moved to RAM.

But when string_table is changed to

char const string_table [ROWS][COLS][MAX_CHARS] =
{
  { "row1_1", "row1_2", "row1_3" },
  { "row2_1", "row2_2", "row2_3" },
 ...
}

const objdef def_instance = { 2, 3,function, array, NULL };//->ROM
const objdef def_instance = { 2, 3, function, array, string_table[0][0] };//->ROM

those instances of objdef are placed in ROM despite that const void* assigment. I have no idea why this should matter.

I'm beginning to suspect that Dan is right and that our configuration is messed up somewhere.

like image 442
dandan78 Avatar asked Feb 10 '11 21:02

dandan78


4 Answers

I assume you have a scatterfile that separates your RAM and ROM sections. What you want to do is to specify your structure with an attribute for what section it will be placed, or to place this in its own object file and then specify that in the section you want it to be in the scatterfile.

__attribute__((section("ROM"))) const objdef def_instance = { 2, 3, function, array };

The C "const" keyword doesn't really cause the compiler to put something in the text or const section. It only allows the compiler to warn you of attempts to modify it. It's perfectly valid to get a pointer to a const object, cast it to a non-const, and write to it, and the compiler needs to support that.

like image 156
Variable Length Coder Avatar answered Oct 22 '22 08:10

Variable Length Coder


Your thinking is correct and reasonable. I've used Keil / uVision (this was v3, maybe 3 years ago?) and it always worked how you expected it to, i.e. it put const data in flash/ROM.

I'd suspect your linker configuration / script. I'll try to go back to my old work & see how I had it configured. I didn't have to add #pragma or __attribute__ directives, I just had it place .const & .text in flash/ROM. I set up the linker configuration / memory map quite a while ago, so unfortunately, my recall isn't very fresh.

(I'm a bit confused by people who are talking about casting & const pointers, etc... You didn't ask anything about that & you seem to understand how "const" works. You want to place the initialized data in flash/ROM to save RAM (not ROM->RAM copy at startup), not to mention a slight speedup at boot time, right? You're not asking if it's possible to change it or whatever...)

EDIT / UPDATE:

I just noticed the last field in your (const) struct is a some_other_struct * const (constant pointer to a some_other_struct). You might want to try making it a (constant) pointer to a constant some_other_struct [some_other_struct const * const] (assuming what it points to is indeed constant). In that case it might just work. I don't remember the specifics (see a theme here?), but this is starting to seem familiar. Even if your pointer target isn't a const item, and you can't eventually do this, try changing the struct definition & initializing it w/ a pointer to const and just see if that drops it into ROM. Even though you have it as a const pointer and it can't change once the structure is built, I seem to remember something where if the target isn't also const, the linker doesn't think it can be fully initialized at link time & defers the initialization to when the C runtime startup code is executed, incl. the ROM to RAM copy of initialized RW memory.

like image 28
Dan Avatar answered Oct 22 '22 06:10

Dan


You could always try using assembly language.

Put in the information using DATA statements and publish (make public) the starting addresses of the data.

In my experience, large Read-Only data was declared in a source file as static const. A simple global function inside the source file would return the address of the data.

like image 22
Thomas Matthews Avatar answered Oct 22 '22 07:10

Thomas Matthews


If you are doing stuff on ARM you are probably using the ELF binary format. ELF files contain an number of sections but constant data should find its way into .rodata or .text sections of the ELF binary. You should be able to check this with the GNU utility readelf or the RVCT utility fromelf.

Now assuming you symbols find themselves in the correct part of the elf file, you now need to find out how the RTX loader does its job. There is also no reason why the instances cannot share the same read only memory but this will depend on the loader. If the executable is stored in the rom, it may be run in-place but may still be loaded into RAM. This also depends on the loader.

like image 28
doron Avatar answered Oct 22 '22 07:10

doron