0

With GNU Arm embedded toolchain, is it possible to change the default sections for symbols for a whole file?

I've previously worked with Rowley Crossworks, which has a parameter you can set for any source file or folder to change various default sections, for instance the default section for zeroed variables: enter image description here (from the Crossworks manual)

This is very useful to make sure a big application fit in flash on and RAM resource constrained microcontrollers. However, I'm unable to find any way to do this with the regular GNU Arm toolchain.

I'm aware that I can use __attribute__((section(".sectionname"))), but this requires code modifications, which is problematic when compiling the same code for different targets, some of which may not have more than one section.

The ideal solution would be a GCC command-line parameter to put for instance zeroed data in a custom section for a specific compilation unit. I could then apply this to specific files, folders or projects from CMake, without making any changes to the actual source code. Does something like this exist?

hlnd
  • 286
  • 2
  • 9
  • So you dont want to do this in the linker script? call out the whole file and change where it goes? Has to be on the gcc command line? – old_timer Sep 08 '20 at 06:54
  • its easy to use the gnu tools to keep the application size within the resources for a microcontroller. What is the actual problem you are trying to solve here? – old_timer Sep 08 '20 at 06:55
  • @old_timer Ideally, I'd like to use command line arguments, but a linker script solution would be appreciated too. When investigating Lundin's comment below, I saw that it should perhaps be possible to do from the linker script, but weren't immediately able to get it work as expected, and haven't been able to really dig into the details again yet. – hlnd Sep 10 '20 at 13:43

3 Answers3

1

I was not able to find a command line parameter or similar for this functionality, but the comment from Lundin made me look into linker scripts in some more detail, and ended up with this:

.bss :
{
    . = ALIGN(4);
    __bss_start__ = .;
    *main.cpp.obj*(.bss*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

.ethram (NOLOAD):
{
    __ethram_start__ = .;
    *(.ethram)
    *(.bss*)
    __ethram_end__ = .;
} >ETHRAM

In the above I explicitly state that in the output section .bss only main.cpp's .bss section should be included, and that it should be placed in regular RAM. By then having an unconstrained .bss in ETHRAM, the linker places other files' .bss sections there, and this was sufficient for my use.

It is also possible to explicitly exclude files from an output section, like this, but my application didn't need it:

.bss :
{
    . = ALIGN(4);
    __bss_start__ = .;
    EXCLUDE_FILE(*main.cpp.obj*)*(.bss*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM
hlnd
  • 286
  • 2
  • 9
0

It is possible with __attribute__, but to simply type out a section for the variable isn't sufficient. There must be such a section present in the linker script, which means you you have to manually modify that one (often called .ld/.lcf or some such, depending on target). Various dialects seem to exist depending on target, see the GCC linker manual for details.

Crossworks does that part for you - from what I recall they let you modify a more easy to use XML format so that you don't have to meddle with the the linker script directly. You can look at the output files from Crossworks and you'll find one with extension .ld or equivalent. And that's likely how your linker file for gcc for the given target platform should look like.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Sorry, perhaps I wasn't clear, but I'm aware of `__attribute__` and how it works together with the linker script. The problem is that the source code I'm working with is built for multiple targets, so setting an attribute in source code fixes one target, but breaks another. It's probably possible to work around this with some kind of macro kludge, but I was instead hoping there would be some GCC command line parameter, so that I can solve this purely from CMake. I've tried expanding the question a bit. – hlnd Aug 31 '20 at 18:44
  • @hlnd Ok. These things simply aren't portable. Some compilers uses a non-standard `@` operator for this, others use a specific `#pragma` and so on. You'll need a bunch of `#ifdef` somewhere. – Lundin Sep 01 '20 at 06:22
  • I'm actually not too concerned with portability between compilers. The upside of a command-line parameter solution would primarily be supporting different CPUs from the same codebase, e.g. one with multiple, different RAM blocks at different addresses and another with just one, big contiguous block. I could perhaps do it by adding fake sections to the second CPUs linker script, but it's a bit odd, and I'd rather avoid it, if at all possible. – hlnd Sep 01 '20 at 07:08
  • @hlnd Some linker scripts support adding the same section to multiple memory locations (I don't remember if/how gcc does that). Long as you have multiple variables etc, the linker will add them to a memory location where there's room, then move on to the next when the previous one is full. Fairly common when working with low end MCUs with fragmented memory maps ("banking"). – Lundin Sep 01 '20 at 07:56
  • That sounds very interesting. Do you happen to have any references on how that works, and what syntax is required? My initial naive attempt, just putting `*(.bss*)` in both `.bss` and in `.ethram` didn't seem to have any effect. – hlnd Sep 02 '20 at 07:42
  • @hlnd I'm a novice at gcc linker scripts, so I'd have to look it up. But other tool chains support this, so I don't see why gcc wouldn't. – Lundin Sep 02 '20 at 09:35
0

Could you change the compilation recipe to generate the .s file, apply awk / sed / etc... to adjust the sections to your liking, then assemble the result. It is kind of an old way of doing it, but is quite portable and reliable.

mevets
  • 10,070
  • 1
  • 21
  • 33