3

I work on the project where I copy some functions to the RAM from FLASH and call them. Everything is OK except one small problem I have - if I call function directly the compiler adds the veneer call instead (which calls the funtion in the RAM correctly).

IF I call it via the pointer all is OK. The debugger shows that resolved address of the function is correct.

#define RAMFCALL(func, ...)   {unsigned (* volatile fptr)() =  (unsigned (* volatile)())func; fptr(__VA_ARGS__);}

RAMFCALL(FLASH_EraseSector, 0, 0);
FLASH_EraseSector(0,0);

and the corresponding calls:

 311        RAMFCALL(FLASH_EraseSector, 0, 0);
0801738e:   ldr     r3, [pc, #88]   ; (0x80173e8 <flashSTMInit+140>)
08017390:   str     r3, [sp, #12]
08017392:   ldr     r3, [sp, #12]
08017394:   movs    r1, #0
08017396:   mov     r0, r1
08017398:   blx     r3
 312        FLASH_EraseSector(0,0);
0801739a:   movs    r1, #0
0801739c:   mov     r0, r1
0801739e:   bl      0x801e9f0 <__FLASH_EraseSector_veneer>

Debugger shows the correct addresses.

enter image description here

and the corresponding part of the linker script

  OVERLAY : NOCROSSREFS
  {
      .RAM_functions 
      {
        . = ALIGN(512);
        RAM_functions_load = LOADADDR(.RAM_functions);
        PROVIDE(RAM_VectorTable_start = .);
        KEEP(*(.RAM_VectorTable))
        KEEP(*(.RAM_VectorTable*))
        PROVIDE(RAM_VectorTable_end = .);

        . = ALIGN(4);
        RAM_functions_start = .;
        KEEP(*(.RAM_functions))
        KEEP(*(.RAM_functions*))
        RAM_functions_end = .;

        . = ALIGN(4);
        RAM_functionsDATA_start = .;
        KEEP(*(.RAM_functionsDATA))
        KEEP(*(.RAM_functionsDATA*))
        RAM_functionsDATA_end = .;   
        . = ALIGN(4);
        RAM_functionsBUFFER_start = .;
      } 

      /* used by the startup to initialize data */

      /* Initialized data sections goes into RAM, load LMA copy after code */
      .data   
      {
        . = ALIGN(4);
        _sdata = .;        /* create a global symbol at data start */
        *(.data)           /* .data sections */
        *(.data*)          /* .data* sections */

        . = ALIGN(4);
        _edata = .;        /* define a global symbol at data end */
      } 
  }>RAM AT> FLASH

And again the question: how to remove the veneer call

0___________
  • 60,014
  • 4
  • 34
  • 74

2 Answers2

3

I will answer myself as I have found the reason :)

The bl instruction is += 32MB relative to PC. I was calling the function in the RAM from FLASH and the actual distance was much longer than 32MB. So the linker had to place the veneer function call.

0___________
  • 60,014
  • 4
  • 34
  • 74
1

Veneers could be eliminated by giving the -mlong-calls argument to the compiler. Each call site becomes a bit longer loosing some performance, however it might still be better than loosing performance in the veneers. Individual functions can also be marked to be called through registers by applying the long_call attribute ( ARM assumed based on the assembly, decribed at https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#ARM-Function-Attributes )