_sbrk function not found when placed in a static library - c

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?

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

Related

libtool changes the order of my linker flags in autotools?

I am trying to statically build the web server lighttpd (version 1.4.49) using musl (for x86) as my compiler and lighttpd's autotools build system. My configuration script is as follows:
CC=/home/musl-1.1.23/install/bin/musl-gcc CFLAGS="-g --static" LDFLAGS="-L/home/lighttpd -lwrappers -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown LIGHTTPD_STATIC=yes ./configure --prefix=/home/lighttpd/install --enable-static --disable-shared --without-zlib --disable-ipv6 --without-bzip2 --without-pcre
Where I have created my own static library "wrappers" that contains the wrapped definitions for the functions specified in my LDFLAGS argument for configure. The way everything is set up I need my wrapped library to be the first library linked (even before musl's standard c library), however libtool is changing the order of my LDFLAGS argument from above to the following:
libtool: link: /home/musl-1.1.23/install/bin/musl-gcc -g --static -Wall -W -Wshadow -pedantic -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown -o proc_open proc_open-proc_open.o proc_open-buffer.o -L/home/lighttpd-1.4.49 -lwrappers
instead of:
libtool: link: /home/musl-1.1.23/install/bin/musl-gcc -g --static -Wall -W -Wshadow -pedantic -L/home/lighttpd-1.4.49 -lwrappers -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown -o proc_open proc_open-proc_open.o proc_open-buffer.o
Which causes the following errors (I have only included the first few, but the rest are similar):
/usr/local/bin/ld: /home/musl-1.1.23/install/lib/libc.a(syslog.o): in function `__openlog':
/home/musl-1.1.23/src/misc/syslog.c:51: undefined reference to `__wrap_socket'
/usr/local/bin/ld: /home/musl-1.1.23/install/lib/libc.a(syslog.o): in function `_vsyslog':
/usr/local/bin/ld: /home/musl-1.1.23/src/misc/syslog.c:111: undefined reference to `__wrap_send'
/usr/local/bin/ld: /home/musl-1.1.23/src/misc/syslog.c:113: undefined reference to `__wrap_send'
Its weird to me why this is happening, as everywhere else the LDFLAGS appear in the right order:
/bin/bash ../libtool --tag=CC --mode=link /home/musl-1.1.23/install/bin/musl-gcc -g --static -Wall -W -Wshadow -pedantic -module -export-dynamic -avoid-version -L/home/lighttpd -lwrappers -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown -o mod_setenv.la -rpath /home/lighttpd/install/lib mod_setenv.lo
libtool: link: ranlib .libs/mod_scgi.a
Any help would be greatly appreciated! Thank you in advance.
LDFLAGS is not for libraries to add to the link. libtool notwithstanding, LDFLAGS is expanded too early in the link command, and this is not specific to the autotools.
In your case, libtool appears to be recognizing that error, and in the case where that matters, moving the -L and -l options where they need to be, after the object(s) being linked. (Or at least the -l options need to be there, especially for a static link, and if libtool is going to move those, then there are practical reasons for moving the -L options, too.)
Unfortunately, there is no other user-oriented Autotools variable appropriate to your stated purpose, either. Injecting extra libraries into the link is not a use case the Autotools are designed to support, and injecting them at the beginning of the link is unlikely to be feasible without hacking the autotooling.
On the third hand, you appear to be misinterpreting the problem. You claim that
I need my wrapped library to be the first library linked (even before musl's standard c library)
But this ...
/usr/local/bin/ld: /home/musl-1.1.23/install/lib/libc.a(syslog.o): in function `_vsyslog':
/usr/local/bin/ld: /home/musl-1.1.23/src/misc/syslog.c:111: undefined reference to `__wrap_send'
... tells me exactly the opposite: even calls from inside standard library functions in libc are being wrapped, so the wrapper needs to appear last, even after the standard library (which ordinarily is last, not first).* And since libwrap probably calls standard library functions itself, you may need to link libc twice. Of course, that assumes that you really want to be messing with the standard library that way, which does not seem advisable to me.
If you were performing a dynamic link then this would not be an issue: it would not be possible to wrap the internal calls of the C library in the first place. This suggests to me that the linker's --wrap option probably was not designed with static linking of the standard library in mind.
I'm not inclined to set up a testbed to verify the following, but if you really do want to wrap libc's own internal function calls, then this may work: ... LDFLAGS="-static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown" LIBS="-L/home/lighttpd -lc -lwrappers -lc" ./configure ...
LIBS is not really intended to be a user variable, and that's the potential weak point of this plan. But it is among Autoconf's standard output variables, and its contents should appear at the end of the link line. configure may prepend other libraries to LIBS, but it should not append any. The risk is that configure may clear any initial contents.
The -lc appearing before -lwrappersis the secret sauce. Normally, you do not need to specify -lc explicitly, but in this case you do, because you need to resolve some symbols in it against libwrappers, which otherwise would be linked too early. You also (probably) need to link some symbols in libwrappers against libc. It may be redundant, but explicitly linking libc again, after libwrappers, may be necessary to overcome unwanted cleverness by the linker.
If you want to avoid wrapping the internal libc self-calls, then you could try ... LDFLAGS="-static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown" LIBS="-L/home/lighttpd -lwrappers -Wl,--no-wrap=socket -Wl,--no-wrap=bind -Wl,--no-wrap=listen -Wl,--no-wrap=accept4 -Wl,--no-wrap=send -Wl,--no-wrap=recv -Wl,--no-wrap=shutdown" ./configure .... The idea there is to turn off wrapping for libc (only), but it's pretty speculative, because although negating long options with no- is standard GNU form, the --no-wrap option in particular is not documented.
*So libtool's reordering is not causing the issue you present. In fact, if libtool did not perform that reordering then you would have even more link errors.

Linker not able to find functions in other static libraries

I'm trying to compile fbi (Linux framebuffer imageviewer) statically, so I added -static to LDFLAGS in GNUMakefile. Without -static linking works perfectly. When enabled, I get various linking errors telling me this:
/usr/lib/gcc/arm-linux-gnueabihf/4.9/../../../arm-linux-gnueabihf/libfontconfig.a(fcxml.o): In function 'FcConfigMessage':
(.text+0x192): undefined reference to 'XML_GetCurrentLineNumber'
Now I do have the static library libfontconfig.a and the function XML_GetCurrentLineNumber it obviously doesn't find is in /usr/lib/gcc/arm-linux-gnueabihf/4.9/../../../arm-linux-gnueabihf/libxml2.a which I proofed with nm libxml2.a, according to the source code found here.
I guess I have to tell the linker in the GNUMakefile exactly what to do, but how? The object code in the ar libraries are all ARM 32-bit and I'm compiling and linking on ARM 32-bit.
GNUMakefile can be found here, I added LDFLAGS += -static --verbose -lfontconfig -lfreetype -lpng12 -ltiff.
When one builds a shared library it often links other shared libraries it needs.
Whereas static libraries cannot link other libraries, so that when linking to that static library its dependencies must also be linked explicitly.
In other words, you cannot just sprinkle in -static and expect it to still link.
Try linking in that libxml2.a and other missing libraries until it links:
LDFLAGS += -static --verbose -lfontconfig -lfreetype -lpng12 -ltiff -lxml2

Different symbol tables in different versions of gcc causing wrong linkages

I am trying to compile a piece of code that links several source files with a shared library. This is to avoid a name conflict with a function named Log in both the source code and shared library.
The signature in my source code is Log(int, char *, char *, ...) and the signature in the shared library is Log(int, int, char *, ...)).
The code needs to be built for different targets. When built using gcc-5.4.0 (Ubuntu 16.04), there is no conflict and the shared library correctly calls the Log function from the shared library. However when building on gcc-4.9.2 for armhf (BeagleBoneBlack), the shared library calls the Log function in my source code which is incorrect.
Specifically, the output of the nm command applied to the executable generated using gcc-4.9.2 shows the first entry in the dynamic symbol table as follows:
$ nm -D <filename>
00017590 T Log
.....
This entry for Log does not appear when compiling with gcc-5.4.0.
I have tried using objcopy for substituting the Log symbol name while the .so file is generated, but that doesn't work.
Is there some setting or flag in the Makefile that needs to be added so that any version of gcc should not add the Log function to the dynamic symbols of my final executable? Or is there something else that I am missing here?
Reproducing the Makefile settings:
CFLAGS=-fPIC -MMD -Wall -std=c99 -D_GNU_SOURCE -g -Werror=implicit
CPPFLAGS=-Iinclude
CFLAGS+=-Os -fdata-sections -ffunction-sections -flto
CPPFLAGS+=-Os -fdata-sections -ffunction-sections -flto
LDFLAGS=-Os -Wl,--gc-sections -flto

How to include syscalls.c from a separate library file?

My code includes indirect calls to functions like _write() and _sbrk(). Within the project I have a file called syscalls.c that defines my custom implementations of these functions, and the compiler/linker finds this file, and links to the functions correctly when I run make. The compile line make creates looks something like this:
arm-none-eabi-gcc -nostartfiles -mcpu=arm7tdmi -Wl,--gc-sections -Wl,--cref -L../hardware_drivers/lib -L../framework/lib -T../linker-script.lds -Wl,-Map,./build/bin/Mapfile.map -o build/bin/Elffile.elf ./build/obj/Main.o ./build/obj/SomeCode.o ./build/obj/syscalls.o -Wl,--start-group -lhardware_drivers -lframework -Wl,--end-group
This works perfectly. However, I want to move syscalls.c to the hardware_drivers project that I have, so they should be included in the libharware_drivers.a file that gets created when I compile hardware_drivers, and included by the gcc line above. Moving the file and recompiling all my projects does include my syscalls.c in the .a file (shown using arm-none-eabi-ar). However, when it comes to compile my top level project, I get this error:
../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0x1c): undefined reference to `_fstat'
I'm using arm-none-eabi-gcc v4.8 from code sourcery and I'm compiling it for a AT91SAM7A1 chip, if that has any relevance.
Is there something special you need to do to point the linker to syscalls when it's in a separate library file?
You use,
-nostartfiles
You create a file with _fstat in libhardware_drivers.a
You use some code with _fstat_r calling ../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o)
Here is the error message,
../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o): In function '_fstat_r':
fstatr.c:(.text._fstat_r+0x1c): undefined reference to '_fstat'
You can try to find the code which uses the _fstat_r from a map file or with -nodefaultlibs or -nostdlibs. The issue is that libraries are resolved in a first to last order. You have an implicit -lc at the end of your linker list. If you intend to use the the 'C' library, then you must alter your linker command to position libhardware_drivers.a later in the link.
For example,
arm-none-eabi-gcc -nostartfiles -mcpu=arm7tdmi -Wl,--gc-sections -Wl,--cref\
-L../hardware_drivers/lib -L../framework/lib -T../linker-script.lds \
-Wl,-Map,./build/bin/Mapfile.map -o build/bin/Elffile.elf ./build/obj/Main.o\
./build/obj/SomeCode.o ./build/obj/syscalls.o \
-Wl,--start-group -lc -lhardware_drivers -lframework -Wl,--end-group
Here, a -lc is placed before -lhardware_drivers. This will let the linker resolve the lib_a-fstatr.o reference to _fstat in your syscall.o. Another way is to force some synthetic reference earlier in another object file (like Main.o). A macro can force the link,
#define FORCE_LINK(x) void* __ ## x ## _force_link =(void*)&x
FORCE_LINK(fstat);
Most likely you have circular references in your static libraries. Ie, hardware_drivers refers to framework refers to libc (and libc refers back to hardware_drivers to make things work). Methods to overcome this are to list the libraries multiple times on the command line or restructure your code which is probably better long term.
The restructure is as simple as a separate libsyscall.a, which is listed after -lc.

gcc detect duplicate symbols/functions in static libraries

Is there any way we can get gcc to detect a duplicate symbol in static libraries vs the main code (Or another static library ?)
Here's the situation:
main.c erroneously contained a function definition, e.g. with the signature uint foohash(const char*)
foo.c also contains a function definition with the signature uint foohash(const char*)
foo.c and other source files are compiled to a static util library, which the main program links in, i.e. something like:
gcc -o main main.o util.o -L ./libs -lfooutils
So, now main.o and libs/libfooutils.a both contain a foohash function. Presumably the linker found that symbol in main.o and doesn't bother looking for it elsewhere.
Is there any way we can get gcc to detect such a situation ?
Indeed as Simon Richter stated, --whole-archive option can be useful. Try to change your command-line to:
gcc -o main main.o util.o -L ./libs -Wl,--whole-archive -lfooutils -Wl,--no-whole-archive
and you'll see a multiple definition error.
gcc calls the ld program for linking. The relevant ld options are:
--no-define-common
--traditional-format
--warn-common
See the man page for ld. These should be what you need to experiment with to get the warnings sought.
Short answer: no.
GCC does not actually do anything with libraries. It is the task of ld, the linker (called automatically by GCC) to pull in symbols from libraries, and that's really a fairly dumb tool.
The linker has lots of complex jiggery pokery for combining different types of data from different sources, and supporting different file formats, and all the evil little details of binary executables, but in the end, all it really does is look for undefined symbols and find the definitions.
What you can do is a link trace (pass -t to gcc) to see what comes from where. Or else run nm on all the object files and libraries in your system, and write a script to detect duplicates.

Resources