5

I'm creating a bare-metal application for the stm32f407 microcontroller, which has an ARM Cortex M4 core. As such, I'm delivering the implementation of functions like _sbrk myself. I now find that when I try to create a static library containing _sbrk, and link it with my main.c into an application, the linker says

"c:/progra~2/gnutoo~1/4947e~1.920/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7e-m/softfp\libg_nano.a(lib_a-sbrkr.o): In function _sbrk_r: sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'".

If I take that same function out of the static library, and put it into main.c, everything compiles/links/runs just fine.

I am almost certain that this has something to do with the order in which the linker reads in all libraries, and that when my own static library is read, no definition of _sbrk is required yet, and is therefore thrown out, only to find that it was needed anyway when later one of the standard libraries is linked in. However, I do not specify any standard libraries myself, and can therefore not change the order of linking those libraries. I also tried to declare the _sbrk function as __attribute __ ((__ used__ )), thinking that the linker would not throw away that function, but alas, this has not solved my problem.

So my question is, how can I put _sbrk into a static library, without running into unresolved references?

Update: The command to link the final application is:

C:\PROGRA~2\GNUTOO~1\4947E~1.920\bin\AR10B2~1.EXE -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -ffunction-sections -fno-rtti -fno-exceptions -std=c++11 -fno-use-cxa-atexit -fno-threadsafe-statics -g -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -Wl,--gc-sections -nostartfiles -Wl,-T"C:/Users/Richard Peters/Documents/Projects/Embedded/http_server/ldscripts/mem.ld" -Wl,-T"C:/Users/Richard Peters/Documents/Projects/Embedded/http_server/ldscripts/sections.ld" "CMakeFiles\http_server.http_server.dir\src\main.cpp.obj" "CMakeFiles\http_server.http_server.dir\src\vectors_stm32f4xx.c.obj" "CMakeFiles\http_server.http_server.dir\http_server.http_server_linker_script_dummy.c.obj" -o "c:\Users\Richard Peters\Documents\Projects\Embedded-install\targets\http_server.http_server\Generic-stm32f4xx\bin\http_server.http_server.elf" "c:\Users\Richard Peters\Documents\Projects\Embedded-install\targets\cmsis_stm.cmsis_stm\Generic-stm32f4xx\lib\libcmsis_stm.cmsis_stm.a"

Where AR10B2~.EXE resolves to arm-none-eabi-g++.exe.

Adding the following makes the thing link:

-lc -lg "c:\Users\Richard Peters\Documents\Projects\Embedded-install\targets\cmsis_stm.cmsis_stm\Generic-stm32f4xx\lib\libcmsis_stm.cmsis_stm.a"

Th libcmsis_stm.cmsis_stm.a library is built with the following command:

C:\PROGRA~2\GNUTOO~1\4947E~1.920\bin\ARM-NO~2.EXE cq "c:\Users\Richard Peters\Documents\Projects\Embedded-install\targets\cmsis_stm.cmsis_stm\Generic-stm32f4xx\lib\libcmsis_stm.cmsis_stm.a" CMakeFiles/cmsis_stm.cmsis_stm.dir/src/cmsis/system_stm32f4xx.c.obj

Where ARM-NO~2.EXE resolves to arm-none-eabi-ar.exe

So one question remains: I would like to place the interrupt vector table, which is a variable, into the static library, but the linker throws that variable away because no source file needs that variable. Is there a mechanism to keep that variable until the linker processes the output sections in the linker file?

Richard
  • 212
  • 3
  • 8
  • You don't need to define it it main. It should be enough to _refer_ to it in your main module, from an unused function `dummy_sbrk_caller`, say, which you declare with `__attribute__((__used__))`. – TonyK Mar 06 '15 at 09:35
  • 2
    Have you tried to link in your application library *after* the standard C library? Like `-o out main.o -lc -lm -lapp`? – Beryllium Mar 06 '15 at 09:55
  • How does the command line you use at the linking stage look like ? Order of the libraries matter. Also see https://stackoverflow.com/questions/13235748/linker-error-on-a-c-project-using-eclipse – nos Mar 06 '15 at 11:29
  • 1
    Yes, I have tried that, or at least, I have tried main.o -lc . I now see that the offending library is libg, not libc. Adding -lg in the above sentence indeed fixes the problem. Which makes me wonder, what would the total list of implicitly linked libraries be? – Richard Mar 06 '15 at 12:18
  • Can I up the stakes a little bit? While re-ordering the list of libraries and duplicating a few of them enables the linker to find _sbrk, I've got a related problem with the interrupt vector table. I'd like to put that table (named __isr_vectors) into the separate static library as well, but since it is only used by the linker script itself, and not by any code, it is not linked. The "dummy_sbrk_caller" trick works, but I'd like to know if there is a nicer way to keep the __isr_vectors table all the way through linking – Richard Mar 06 '15 at 12:45
  • Please add all commands to the question: Those to compile and to generate the library, and the ones to compile and link the app. And add the version which works as well. Do you use `-g` anywhere? – Beryllium Mar 06 '15 at 20:00
  • OK, so your question is answered. As for the __isr_vectors I suggest posting a separate question. There is no limit on the number of questions on this site, but here is a limit on the number of questions *in* a question :-) – Beryllium Mar 08 '15 at 17:07
  • OK, I'll do that, thanks for the advice and thanks for the answer! – Richard Mar 09 '15 at 18:05

1 Answers1

5

When ld links against a library, it will only pick those functions which are required at that time (because of references to functions from translation units which have been linked in before). The linker will forget all other functions (and the library won't be considered later).

Therefore the linking order does matter. Normally you would link in your application object file (which references malloc), then the standard library (which provides malloc and in turn references _sbrk), and then your (application) library which provides _sbrk.

So linking should look like

arm-none-eabi-gcc ... -o out.elf startup.o main.o -lc -lm -lapp

with the _sbrk function being provided by libapp.

So the order of the objects to be linked does matter.

Update

As stated in one of the comments: If you add debug symbols using -g during compilation, then you have to link against libg as well (-lg).

arm-none-eabi-gcc ... -o out.elf startup.o main.o -lc -g -lm -lapp

Beryllium
  • 12,808
  • 10
  • 56
  • 86