Closed Amomum closed 7 years ago
@Amomum
You should to delete -D__START=main
from compiler flags and you should to use arm-none-eabi-g++
. And you should to add --specs=nano.specs
to linker flags.
add -mthumb to linker flags (because by default it will link startfiles compiled into arm code, not thumb).
It is showed in example (see CFLAGS
).
Can you look this on Launchpad? Look at example of gcc-arm-embedded (on Linux /usr/share/gcc-arm-embedded/samples/src/cpp/). It use same startup and linker files. Give me know about your researches.
Well, now I made static ctors work with the following flags:
gcc:
-c -fmessage-length=0 -mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections -Wcast-align -Wcast-qual -Wvla -Wshadow -Wsuggest-attribute=const -Wmissing-format-attribute -Wuninitialized -Winit-self -Wdouble-promotion -Wno-unused-local-typedefs
g++:
-c -fmessage-length=0 -mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections -fno-rtti -fno-exceptions -fno-threadsafe-statics -Wcast-align -Wcast-qual -Wvla -Wshadow -Wsuggest-attribute=const -Wmissing-format-attribute -Wuninitialized -Winit-self -Wdouble-promotion -Wstrict-aliasing -Weffc++ -Wno-unused-local-typedefs
link:
-mthumb --specs=nano.specs -Wl,--gc-sections -T "${ProjDirPath}/src/Startup/STM32F100XB_FLASH.ld" -ffreestanding -Wl,-defsym,__dso_handle=0 -Wl,-Map=output.map
(not sure if dso_handle is required though)
And as you can see, I took linker script from stm32f100 since it seem to have compatible flash/ram size and origin. And I used startup file for it as well.
I'm not really familiar with gcc linker script and asm syntax so I didn't dare editing existing files but I'm not aware of any sufficient diffirencies between milandr and stm in that matter.
@Amomum I don't understand have you try to compile these mdr pack files with my suggestions.
@Amomum just add in linker script ` . = ALIGN(4); / preinit data / PROVIDE_HIDDEN (preinit_array_start = .); KEEP(*(.preinit_array)) PROVIDE_HIDDEN (preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
and place constructors call
/ Iterate over all the init routines. /
void
__libc_init_array (void)
{
size_t count;
size_t i;
count = preinit_array_end - preinit_array_start; for (i = 0; i < count; i++) __preinit_array_start[i] ();
count = init_array_end - init_array_start; for (i = 0; i < count; i++) __init_array_start[i] (); }
/ Run all the cleanup routines. / void __libc_fini_array (void) { size_t count; size_t i;
count = fini_array_end - fini_array_start; for (i = count; i > 0; i--) __fini_array_start[i-1] ();
}`
@legath
just add in linker script ` . = ALIGN(4); /* preinit data / PROVIDE_HIDDEN (preinit_array_start = .); KEEP((.preinit_array)) PROVIDE_HIDDEN (preinit_array_end = .);
. = ALIGN(4); / init data / PROVIDE_HIDDEN (__init_array_start = .); KEEP((SORT(.init_array.))) KEEP(*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4); / finit data / PROVIDE_HIDDEN (__fini_array_start = .); KEEP((SORT(.fini_array.))) KEEP(*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .);
It is exist already here.
and place constructors call
$ arm-none-eabi-objdump -tC /usr/arm-none-eabi/lib/thumb/v7-m/libg.a | less
lib_a-init.o: file format elf32-littlearm
SYMBOL TABLE:
00000000 l df *ABS* 00000000 init.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .text.__libc_init_array 00000000 .text.__libc_init_array
00000000 l d .debug_frame 00000000 .debug_frame
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g F .text.__libc_init_array 00000050 __libc_init_array <------------------------------------------
00000000 *UND* 00000000 _init
00000000 w *UND* 00000000 __preinit_array_end
00000000 w *UND* 00000000 __preinit_array_start
00000000 w *UND* 00000000 __init_array_end
00000000 w *UND* 00000000 __init_array_start
lib_a-fini.o: file format elf32-littlearm
SYMBOL TABLE:
00000000 l df *ABS* 00000000 fini.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .text.__libc_fini_array 00000000 .text.__libc_fini_array
00000000 l d .debug_frame 00000000 .debug_frame
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g F .text.__libc_fini_array 00000034 __libc_fini_array <------------------------------------------
00000000 *UND* 00000000 _fini
00000000 w *UND* 00000000 __fini_array_end
00000000 w *UND* 00000000 __fini_array_start
$ arm-none-eabi-objdump -tC /usr/arm-none-eabi/lib/thumb/v7-m/crt0.o | less
/usr/arm-none-eabi/lib/thumb/v7-m/crt0.o: file format elf32-littlearm
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .ARM.extab 00000000 .ARM.extab
00000000 l d .ARM.exidx 00000000 .ARM.exidx
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g F .text 00000000 _mainCRTStartup
00000000 g F .text 00000000 _start <--------------------------------------------------------------
00000000 *UND* 00000000 memset
00000000 w *UND* 00000000 atexit
00000000 *UND* 00000000 __libc_init_array <------------------ linked here from libg.a --------
00000000 *UND* 00000000 main
00000000 *UND* 00000000 exit
00000000 w *UND* 00000000 __stack
00000000 w *UND* 00000000 hardware_init_hook
00000000 w *UND* 00000000 software_init_hook
00000000 *UND* 00000000 __bss_start__
00000000 *UND* 00000000 __bss_end__
00000000 w *UND* 00000000 __libc_fini_array <------------------ linked here from libg.a --------
It is the same if use nano spec:
$ arm-none-eabi-objdump -tC /usr/arm-none-eabi/lib/thumb/v7-m/libg_nano.a | less
lib_a-init.o: file format elf32-littlearm
SYMBOL TABLE:
00000000 l df *ABS* 00000000 init.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .text.__libc_init_array 00000000 .text.__libc_init_array
00000000 l d .debug_frame 00000000 .debug_frame
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g F .text.__libc_init_array 00000048 __libc_init_array <--------------------------
00000000 *UND* 00000000 _init
00000000 w *UND* 00000000 __preinit_array_start
00000000 w *UND* 00000000 __preinit_array_end
00000000 w *UND* 00000000 __init_array_start
00000000 w *UND* 00000000 __init_array_end
lib_a-fini.o: file format elf32-littlearm
SYMBOL TABLE:
00000000 l df *ABS* 00000000 fini.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .text.__libc_fini_array 00000000 .text.__libc_fini_array
00000000 l d .debug_frame 00000000 .debug_frame
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g F .text.__libc_fini_array 00000028 __libc_fini_array <-----------------------------------
00000000 *UND* 00000000 _fini
00000000 w *UND* 00000000 __fini_array_start
00000000 w *UND* 00000000 __fini_array_end
$ cat /usr/arm-none-eabi/lib/thumb/v7-m/nano.specs
%rename link nano_link
%rename link_gcc_c_sequence nano_link_gcc_c_sequence
%rename cpp_unique_options nano_cpp_unique_options
*cpp_unique_options:
-isystem =/include/newlib-nano %(nano_cpp_unique_options)
*nano_libc:
-lc_nano
*nano_libgloss:
%{specs=rdimon.specs:-lrdimon_nano} %{specs=nosys.specs:-lnosys}
*link_gcc_c_sequence:
%(nano_link_gcc_c_sequence) --start-group %G %(nano_libc) %(nano_libgloss) --end-group
*link:
%(nano_link) %:replace-outfile(-lc -lc_nano) %:replace-outfile(-lg -lg_nano) %:replace-outfile(-lrdimon -lrdimon_nano) %:replace-outfile(-lstdc++ -lstdc++_nano) %:replace-outfile(-lsupc++ -lsupc++_nano)
*lib:
%{!shared:%{g*:-lg_nano} %{!p:%{!pg:-lc_nano}}%{p:-lc_p}%{pg:-lc_p}}
Right. Sorry for such a long pause. So, I had a few subtle (and stupid) problems with my settings. So, that's what I did: I created this simple main.cpp where I create a global instance of class A and inside it's constructor I turn the led on:
#include "MDR32Fx.h"
void led_on()
{
MDR_RST_CLK->PER_CLOCK |= (1<<24);
MDR_PORTD->ANALOG |= (1<<10);
MDR_PORTD->OE = 1<<10;
MDR_PORTD->PWR |= (1<<20);
MDR_PORTD->RXTX |= 1<<10;
}
class B
{};
class A : B
{
public:
A()
{
led_on();
}
virtual void foo()
{}
virtual ~A()
{}
};
A a;
int main(void)
{
while(1)
{
}
return 0;
}
Then I took your startup file and your linker script and was able to compile and link them like this:
arm-none-eabi-g++ -c -fmessage-length=0 -mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections -fno-rtti -fno-exceptions -fno-threadsafe-statics -ICMSIS main.cpp -o main.o
arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -O0 -ffunction-sections -fdata-sections -pipe -DUSE_MDR1986VE9x -D__STARTUP_CLEAR_BSS -D__NO_SYSTEM_INIT -c startup_MDR32F9Qx.S -o startup.o
..\arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -O0 -ffunction-sections -fdata-sections -pipe -T "MDR32F9Qx.ld" --specs=nosys.specs -Wl,--gc-sections -ffreestanding -Wl,-Map=example.map main.o startup.o -o example.elf
And it worked! So, I was wrong in my initial proposal for fix, because I forgot to add -mcpu=cortex-m3
to linker and despite -mthumb it kept linking the wrong version of crt0, which only by some luck still called main. And I thought the problem was in the linker script.
It turns out that even nano.specs are not necessary.
So, to make this work we should slightly change recommendations in the readme.md:
@Amomum nano.specs need if you want to use more compact (and maybe more speedy) standard library for embedded systems (with some functionally limitations). Can you create a pull request with this recomendations?
If this library is not supposed to be used with C++ at all, that's not a problem. Still, here's the problem:
If I create a global object, it's constructor should be called before main. Unfortunately, in startup_MDR32F9Qx.s there is no mention of that. Therefore global constructors are not called at all. That's bad.
If we go and look into startup files for stm32, for example (distributed with cubeMx), we will see something like this:
To make this work we should:
change startup accordingly;
remove -nostartfiles from linker flags (because libc_init_array will call init and it must come from somewhere). This will make total code size bigger; unfortunately, I don't know what can be done about that;
add -mthumb to linker flags (because by default it will link startfiles compiled into arm code, not thumb).