0

I have a custom linker script for an stm32f4 chip, mostly working; the application start-up and run, global array and variable are correctly initialized BUT global object are not.

I found around some reference to ctor usage instead of __init_array but those seems to be older methodology.

In the LD I added the sections:

. = ALIGN(4);
.preinit_array     :
{
  PROVIDE_HIDDEN (__preinit_array_start = .);
  KEEP (*(.preinit_array*))
  PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
. = ALIGN(4);
.init_array :
{
  PROVIDE_HIDDEN (__init_array_start = .);
  KEEP (*(SORT(.init_array.*)))
  KEEP (*(.init_array*))
  PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
. = ALIGN(4);
.fini_array :
{
  PROVIDE_HIDDEN (__fini_array_start = .);
  KEEP (*(SORT(.fini_array.*)))
  KEEP (*(.fini_array*))
  PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH

and the full startup script:

extern unsigned long _data_flash;
extern unsigned long _data_begin;
extern unsigned long _data_end;
extern unsigned long _bss_begin;
extern unsigned long _bss_end;
extern void (**__preinit_array_start)();
extern void (**__preinit_array_end)();
extern void (**__init_array_start)();
extern void (**__init_array_end)();


inline void static_init()
{
  for (void (**p)() = __preinit_array_start; p < __preinit_array_end; ++p)
    (*p)();

  for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
    (*p)();
}

void reset_handler(void)
{
  unsigned long *source;
  unsigned long *destination;

  // default zero to undefined variables
  for (destination = &_bss_begin; destination < &_bss_end;)
  {
    *(destination++) = 0;
  }

  // Copying data from Flash to RAM
  source = &_data_flash;
  for (destination = &_data_begin; destination < &_data_end;)
  {
    *(destination++) = *(source++);
  }


  SystemInit();

  static_init();

  // starting main program
  main();

  while(1)
  {
    ; //loop forever, but we should never be there
  }
}

Could it be the official startup script from ST are doing some black (and maybe proprietary) magic to make it work properly?

I got this same code work properly when using another compiler, so I exclude an issue in the code.

edit: after some debugging i tried:

printf("preinit %32x %32x\r\n", __preinit_array_start, __preinit_array_end);
printf("init %32x %32x\r\n", __init_array_start, __init_array_end);
printf("preinit2 %32x %32x\r\n", *__preinit_array_start, *__preinit_array_end);
printf("init2 %32x %32x\r\n", *__init_array_start, *__init_array_end);

that return:

preinit 080506E9 080506E9<\r><\n>
init 080506E9 00000000<\r><\n>
preinit2 BB4FF8E9 BB4FF8E9<\r><\n>
init2 BB4FF8E9 20000418<\r><\n>

This is quite interesting, seem "__init_array_end " somehow is not keept

mauro
  • 69
  • 1
  • 5
  • you are using C to bootstrap C? – old_timer May 22 '18 at 14:47
  • it is a startup script for an embedded system, it will set up the ram and call c++ constructor. It bootstrap the environment. This of course mean you can't use stuff that have not been initialized. Not sure what you mean by "bootstrap C". – mauro May 22 '18 at 15:09
  • and what do you see in the generated code. Check the FLASH, then amend the code accordingly. Did you try to debug it? That is the first step. – 0___________ May 22 '18 at 16:19
  • right normally you write the bootstrap in assembly to avoid the chicken and egg problem (and other issues). the bootstrap is the thing that prepares you to run C/C++, zeros bss, copies .data, etc. the code that happens between reset and the C entry function (main() or whatever function name you choose). – old_timer May 22 '18 at 21:31
  • @PeterJ_01 I have no idea what i sohould look for in the compiled stuff. Should I simply put some know value and scan the binary for it? Or there is a better way? – mauro May 23 '18 at 07:13
  • 1
    @old_timer many of the startup nowadays are moving toward C; there are even official example from ST that i plan to test in the next days – mauro May 23 '18 at 07:15
  • What combination of compiler/linker/library did work for you, and what doesn't? – followed Monica to Codidact May 24 '18 at 07:09
  • 1
    @old_timer I'm using a similar approach, i.e. initializing the data segment in a C function, without issues. Of course what is working for me could be useless for someone using a different toolchain. – followed Monica to Codidact May 24 '18 at 07:18
  • @berendi IAR, that manage the compiler script itself. As for you is working, can you post your code, or the difference you see? – mauro May 24 '18 at 07:41
  • @mauro, there is a lot of bad code and solutions coming form these vendors, it is mostly dumb luck, it will fail as a general solution which is why historically it wasnt done. – old_timer May 24 '18 at 15:22
  • I would stay well within their sandbox if you use vendor supplied code, dont deviate... – old_timer May 24 '18 at 16:54
  • here is a sample of C++ startup code: https://github.com/cortexm/baremetal – vlk May 25 '18 at 06:35
  • @old_timer bad code, stay away, don't look there, don't ask that.. sorry this is not my way of doing stuff. i want to learn and understand WHY something is bad code, why it does (not) work. Also this is the stackoverflow idea, no? get to lean MORE, not to hide problem under the carpet – mauro May 25 '18 at 07:31
  • @vlk thanks for the code, made me be back up from the startup script and look deeper into the linker script, where the error was – mauro May 25 '18 at 14:51
  • @mauro, if you look deeper on print output then you can see some nonsense numbers, in real do you not printing addresses but content on these addresses, in printf just add `&` for all, like `&__init_array_end` better is to look on the memory map or symbol table what addresses are there. – vlk May 26 '18 at 11:46
  • @vlk those are "array" pointer, if you look up those "non sense " number you will find out are actual valid FLASH address. all but __init_array_end. Now that is working, those address are all valid FLASH address – mauro Jun 05 '18 at 07:43

1 Answers1

0

After finding out the __init_array_end__ address was wrong, I try to look deeper in the linker script, and decided to try the variant used by Atollic Studio for C++. (please note the previous linker script was taken from st standard peripheral example)

The differences with working Linker Script are principallythe .bss does not have NOLOAD attribute and a different way to initialize the heap, and .data set with >RAM AT> FLASH instead of only >RAM

mauro
  • 69
  • 1
  • 5