How to declare a C array that takes up all free space in a memory section?

832 views Asked by At

Assume I have a 128KB memory region. In my linker directives I split this region into three sections:

  • .section_text
  • .section_data
  • .section_bss

The size of each section is unknown pre-compilation, but I have constrained .section_bss to use all remaining space within the memory region after .section_text and .section_data are allocated.

Is there any way I can declare a C array that uses up all available space in .region_bss? Assume it is the only thing using .region_bss so it can safely use the entire region. For example purposes but obviously wrong:

char entire_bss[sizeof(.region_bss)];

Here are my pre-answers to some anticipated responses. First, I know sizeof() doesn't work like this. I'm just using it to get an idea across. Second, assume this must be done with an array and not with pointers (solving with pointers is possible and fairly simple). Third, I'm aware I can get the start and end addresses of .region_bss, but I'm not aware of any way to use them to size my array. At least not any way that works in C.

There very well may be no way to do this, but I'm hoping some genius out there has figured it out. Extra credit if you can make it work with the Green Hills toolset.

5

There are 5 answers

1
Dummy00001 On BEST ANSWER

Is there any way I can declare a C array that uses up all available space in .region_bss?

Short answer is "no."

If GreenHills is using GNU toolchain with binutils and allows customizing the linker script, then you can add into an application namespace a variable using PROVIDE to mark the end of the 128K block. (See an example how to access such variables here). You will not have a C array of fixed size that way, but program would be able to find the end of the array thus the size of the array what is generally sufficient for C programs.

If you want to accomplish that using pure C99, then you might be out of luck as it is highly unreliable as it is not covered by the standard.

0
Patrick Schlüter On

No you can't. It's also easy to understand why. At the compilation phase there is no concept of .bss and .data these are pure linker conventions. The compiler knows some abstract concepts (const data, static data, code), but the mapping of them to the linker section is only a convention, and depending on linker, OS and processor or even memory model options. When building position independend code, often the constants are put in the code segment for example. On embedded platforms you sometime have to struggle with these things and even have to adapt your coding style because of that (we had once a model based in 80186 processors that were built with MS-C 5.1 compiler, were we couldn't use the .data section (global, initialized variables and statics) because the toolchain put them in the ROM.

We solved once a similar problem of yours by patching the generated binary at the end of the whole build process. We extracted the used memory of the different section from the map file generated by the linker (it's an option look it up), and subtracted it from the memory size of the given model (we had 256K, 512K and 896K models) and set one of the global constants with the right value. It was thus important that all references to this size work via this global variable. This memory pool was then used by our implementation of malloc/free.

0
nategoose On

Usually the way you do this is with something like:

extern char section_bss[];

With some extra stuff thrown in so that the compiler, assembler, and linker know that section_bss is an alias for .section_bss (or similar name).

To get the size you would probably be want to do the same thing for a symbol that is at the end of bss and find the difference.

0
Quuxplusone On

What's wrong with

extern char __ghsbegin_region_bss[];
extern char __ghssize_region_bss[];
#define entire_bss __ghsbegin_region_bss
#define sizeof_entire_bss ((size_t)__ghssize_region_bss)

? I can think of at least one reason you might not be satisfied with this answer, but it involves C++ template metaprogramming magic (namely, the type of entire_bss wouldn't have the right size, so templates that depend on its size would resolve differently). As long as you don't use the size of the array for anything (and this is true, in C), this approach should be fine.

Note that __ghssize_region_bss is not a compile-time constant — it's not resolved until link-time — so there's 100% no way to get it inside the [...] of an array type at compile time.

See the chapter on "Beginning, End, and Size of Section Symbols" in the Green Hills manual.

0
supercat On

What you are seeking to do will be very platform dependent. Your best bet is probably to declare an array as extern char the_array[],end_of_array[]; within your C file, and then, perhaps in an assembly-language source file, declare a couple of data sections for the_array and end_of_array. Then arrange the linker spec so that the_array will be at the end of stuff that's allocated bottom-up, and end_of_array will be at the start of stuff that's allocated top-down, and nothing else will be between them. It's possible--I've done it on some platforms--but it's important to read the linker documentation carefully to ensure that the linker won't rearrange things when you don't expect it.