开发者

storing structs in ROM on ARM device

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 objde开发者_开发知识库f
{
   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.


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.


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.


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.


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.


A complete example would have been best. If I take something like this:

typedef struct
{
    char a;
    char b;
} some_other_struct;

struct objdef
{
   int x;
   int y;
   const some_other_struct * struct_array;
};

typedef struct
{
   int x;
   int y;
   const some_other_struct * struct_array;
} tobjdef;


const some_other_struct def_other = {4,5};
const struct objdef def_instance = { 2, 3, &def_other};
const tobjdef tdef_instance = { 2, 3, &def_other};

unsigned int read_write=7;

And compile it with the latest codesourcery lite

arm-none-linux-gnueabi-gcc -S struct.c

I get

    .arch armv5te
    .fpu softvfp
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 6
    .eabi_attribute 18, 4
    .file   "struct.c"
    .global def_other
    .section    .rodata
    .align  2
    .type   def_other, %object
    .size   def_other, 2
def_other:
    .byte   4
    .byte   5
    .global def_instance
    .align  2
    .type   def_instance, %object
    .size   def_instance, 12
def_instance:
    .word   2
    .word   3
    .word   def_other
    .global tdef_instance
    .align  2
    .type   tdef_instance, %object
    .size   tdef_instance, 12
tdef_instance:
    .word   2
    .word   3
    .word   def_other
    .global read_write
    .data
    .align  2
    .type   read_write, %object
    .size   read_write, 4
read_write:
    .word   7
    .ident  "GCC: (Sourcery G++ Lite 2010.09-50) 4.5.1"
    .section    .note.GNU-stack,"",%progbits

With the section marked as .rodata, which I would assume is desired. Then it is up to the linker script to make sure that ro data is put in rom. And note the read_write variable is after switching from .rodata to .data which is read/write.

So to make this a complete binary and see if it gets placed in rom or ram (.text or .data) then

start.s


.globl _start
_start:
    b   reset
    b   hang
    b   hang
    b   hang

    b   hang
    b   hang
    b   hang
    b   hang

reset:
hang: b hang

Then

# arm-none-linux-gnueabi-gcc -c -o struct.o struct.c
# arm-none-linux-gnueabi-as -o start.o start.s
# arm-none-linux-gnueabi-ld -Ttext=0 -Tdata=0x1000 start.o struct.o -o struct.elf
# arm-none-linux-gnueabi-objdump -D struct.elf > struct.list

And we get


Disassembly of section .text:

00000000 <_start>:
   0:   ea000006    b   20 <reset>
   4:   ea000008    b   2c <hang>
   8:   ea000007    b   2c <hang>
   c:   ea000006    b   2c <hang>
  10:   ea000005    b   2c <hang>
  14:   ea000004    b   2c <hang>
  18:   ea000003    b   2c <hang>
  1c:   ea000002    b   2c <hang>

00000020 <reset>:
  20:   e59f0008    ldr r0, [pc, #8]    ; 30 <hang+0x4>
  24:   e5901000    ldr r1, [r0]
  28:   e5801000    str r1, [r0]

0000002c <hang>:
  2c:   eafffffe    b   2c <hang>
  30:   00001000    andeq   r1, r0, r0

Disassembly of section .data:

00001000 <read_write>:
    1000:   00000007    andeq   r0, r0, r7

Disassembly of section .rodata:

00000034 <def_other>:
  34:   00000504    andeq   r0, r0, r4, lsl #10

00000038 <def_instance>:
  38:   00000002    andeq   r0, r0, r2
  3c:   00000003    andeq   r0, r0, r3
  40:   00000034    andeq   r0, r0, r4, lsr r0

00000044 <tdef_instance>:
  44:   00000002    andeq   r0, r0, r2
  48:   00000003    andeq   r0, r0, r3
  4c:   00000034    andeq   r0, r0, r4, lsr r0

And that achieved the desired result. The read_write variable is in ram, the structs are in the rom. Need to make sure both the const declarations are in the right places, the compiler gives no warnings about say putting a const on some pointer to another structure that it may not determine at compile time as being a const, and even with all of that getting the linker script (if you use one) to work as desired can take some effort. for example this one seems to work:


MEMORY
{
    bob(RX)   : ORIGIN = 0x0000000, LENGTH = 0x8000
    ted(WAIL) : ORIGIN = 0x2000000, LENGTH = 0x8000
}

SECTIONS
{
    .text : { *(.text*) } > bob
    .data : { *(.data*) } > ted
}

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜