Electronics > Microcontrollers

GCC compiler optimisation

(1/71) > >>

Cube IDE, 32F417.

I've just had a funny one. I have a boot loader which transfers control to base+32k (0x08008000) and that is where the linker script places main.o. And I put main() right at the start.

However, if you used the SWV ITM / SWD debug interface, the compiler was putting ITM_SendChar() at the start of main.o! This is actually a macro doing some inline code.

It looks like the compiler is placing inline code before normal functions. This is news to me; I thought that compilers didn't change the order of functions in a .c file :) Why should they?

I fixed it initially by changing the function to a normal one

--- Code: ---static void ITM_SendChar_2 (uint32_t ch)
  if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) &&      /* ITM enabled */
      ((ITM->TER & 1UL               ) != 0UL)   )     /* ITM Port #0 enabled */
    while (ITM->PORT[0U].u32 == 0UL)
    ITM->PORT[0U].u8 = (uint8_t)ch;
--- End code ---

but the proper fix was do create main_stub.c which contains just main() which then calls real_main(), and in the linkfile you put main_stub.o first

--- Code: ---
  /* The rest of the code goes here, loaded at base+32k, starting with a stub and then the real main() */

  .main_stub.o :
    . = ALIGN(4);
    *main_stub.o (.text .text* .rodata .rodata*)
    . = ALIGN(4);
  .main.o :
    . = ALIGN(4);
    *main.o (.text .text* .rodata .rodata*)
    . = ALIGN(4);
/* This collects all other stuff, which gets loaded into FLASH after main.o above */
  .text :
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbol at end of code */

--- End code ---


--- Quote from: peter-h on August 02, 2021, 01:31:11 pm ---It looks like the compiler is placing inline code before normal functions. This is news to me; I thought that compilers didn't change the order of functions in a .c file :) Why should they?
--- End quote ---
I don't think there's generally any guarantee that object code will be in the same order as the source.

But assuming that that source order generally holds, remember that the compiler's view of a .c file contains everything that was included (the translation unit). So if the compiler emits a body for an inline function in a header included before your .c file's first function, the inline function's object code will appear before your .c file's first function's object code.

No, there is neither a guarantee for the order of functions, nor for the order of global variables.
If you want to place main() at 0x08008000, then you need to put main into a separate section, and place this section at 0x08008000 via the linker script.

A macro doesn't compile to a separate function. Most likely, your ITM_SendChar is a "static inline" function declared somewhere in some header and gets inserted near the beginning of your C file as described two posts above. A separate copy is also similarly inserted into each other C file which includes that header.

And we are back at square #1. You don't need to use tricks to solve this, spend some time on a better architecture and it will save you much more time and efforts (especially if you plan to revisit this project in 10 years, as you say). There are better approaches suggested by several people in your original thread, just pick one and ask to elaborate.

To your specific question: the only reliable way to place something at known address with GCC is to specify the placement in linker script (either by adding section attribute to main() or by the name of file containing main() - main.o(.text*)). But even if you solve this main() placement the next question will be how to place some ISR at fixed offset because your "main" part doesn't have it's own vector table and all interrupts land in your bootloader. Then you'll add another ISR and run that circle again. But a more simple solution would be to have a separate vector table for "main" placed correctly and don't bother with functions placement at all.


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod