Hello!
I use arm-none-eabi to compile my STM32 project. I want to link my project files to an archive, e.g. libexample.a, to allow link with other objects, e.g. example.o. The libexample.a contains weak symbol replaced by example.o and example.o uses functions from libexample.a.
Now I face the following problem: When I create libexample.a and then link libexample.a with example.o, the resulting elf/bin is malfunction.
When I take example.o and link it directly with .o files used to crate libexample.a, the resulting elf/bin is OK.
Compile flags are equal.
The further investigation showed, that:
The Makefile snippet is below:
libexample.a: $(OBJS) @echo Creating static library $@ $(AR) rcs $@ $(OBJS) ofiles: @echo Compiling @arm-none-eabi-gcc -c $(CFLAGS) $(INCLUDE) example.c -o example.o @echo "Linking (creating .elf)" @arm-none-eabi-gcc $(OBJS) example.o $(LDFLAGS) -o example.elf @echo "Creating .hex file" @arm-none-eabi-objcopy -O ihex example.elf example.hex @echo "Creating .bin file" @arm-none-eabi-objcopy -O binary -S example.elf example.bin afile: libexample.a @echo Compiling @arm-none-eabi-gcc -c $(CFLAGS) $(INCLUDE) example.c -o example.o @echo "Linking (creating .elf)" @arm-none-eabi-gcc -L. -lexample example.o $(LDFLAGS) -o example2.elf @echo "Creating .hex file" @arm-none-eabi-objcopy -O ihex example2.elf example2.hex @echo "Creating .bin file" @arm-none-eabi-objcopy -O binary -S example2.elf example2.bin
example.bin size is 172Kexample2.bin size is 144K
It may be beneficial to investigate the dependencies between the object files and then decide how to setup the archive. Splitting the archive into multiple smaller archives may also help.
It seems that the archive contains multiple implementations (i.e. definitions/code) of a single function-name, with each implementation in its own .o file. These .o files do not conflict with each other during the ofiles-build, because all instances of that name, except possibly one, are declared as weak functions. Is that correct?
But these weakly-declared instances of the function aren't necessary, since in the ofiles-build they are anyways ignored and overridden. Would it not, therefore, be proper to remove their code from the source altogether?
If the end-goal is to provide multiple, compiled implementations of a single functionality (for e.g. 5 different implementations of malloc), then each implementation can be separated out in its own archive file, and then linked, with the single, large, original archive, in proper order. The choice of the implementation (and hence, the choice of the corresponding archive) can become a configurable parameter, which the user must set when linking their application with your library.
You are absolutely right!
To clarify: we use stm32 HAL libraries, which contain a number of weak functions to allow user-code minimization. In the user code, only required functions are implemented, the undefined parts are taken from the HAL library.
Our project is a modular firmware and in fact "example.a" contains complete and operational embedded code: we provide "symbol-identical" .bin and .a files. The .a file is provided to allow external module creation and incorporation (again by using weak function calls in the.a file).
To respect the hierarchy of the libraries, it would be probably better to compile HAL libraries into separate .a file and our "application" code into the second .a file. But in our use-case, both libraries would be used always together. It would be better - to prevent user confusion - to provide a single .a file. I decided to create the static library with a single symbol table (-r linker parameter), thus weak functions inside .a file are resolved and the user has access to a static library with no built-in conflicts.
For now, there is just one possible configuration of the static library. If there would be more configurations, separate .a files will be provided.
Thank you! You were really helpful!