Symbol not found but was included during linking - linker

I've just built magic VLSI software on MacOs Sierra 10.12.2. This includes building tclmagic.dylib library. Now when testing Magic Exec I get:
magic
dyld: lazy symbol binding failed: Symbol not found: _HashInit
Referenced from: /usr/local/lib/magic/tcl/tclmagic.dylib
Expected in: flat namespace`
I searched and found the HashInit function inside an utility library which is included during linking:
gcc -g -I/usr/X11/include -I/Library/Frameworks/Tk.framework/Versions/8.6/Headers -I/Library/Frameworks/Tcl.framework/Versions/8.6/Headers -fno-common -Wimplicit-int -fPIC -I/Library/Frameworks/Tk.framework/Versions/8.6/Headers -I/Library/Frameworks/Tcl.framework/Versions/8.6/Headers -I. -I.. -o tclmagic.dylib -dynamiclib -flat_namespace -undefined suppress -noprebind \
../cmwind/libcmwind.o ../commands/libcommands.o ../database/libdatabase.o ../dbwind/libdbwind.o ../drc/libdrc.o ../debug/libdebug.o ../extract/libextract.o ../graphics/libgraphics.o ../select/libselect.o ../textio/libtextio.o ../tiles/libtiles.o ../windows/libwindows.o ../wiring/libwiring.o ../resis/libresis.o ../sim/libsim.o ../netmenu/libnetmenu.o ../plow/libplow.o ../utils/libutils.o ../ext2sim/libext2sim.o ../ext2spice/libext2spice.o ../calma/libcalma.o ../cif/libcif.o ../plot/libplot.o ../lef/liblef.o ../extflat/libextflat.o ../garouter/libgarouter.o ../mzrouter/libmzrouter.o ../router/librouter.o ../irouter/libirouter.o ../grouter/libgrouter.o ../gcr/libgcr.o ../tcltk/libtcltk.o -lc -lX11 -lGL -lGLU -lm -L/usr/X11/lib -lm
The HashInit function resides inside ../utils/libutils.o.
I've also used nm -gU on the two binaries and the symbol is found:
nm -gU utils/libutils.o | grep HashInit
0000000000002880 T _HashInit
00000000000028c0 T _HashInitClient
nm -gU magic/tclmagic.dylib| grep HashInit
000000000011ec70 T _HashInit
000000000011ecb0 T _HashInitClient
I've now tried a separate linking command and dump out a symbol mapping file:
ld -o tclmagic.dylib -dylib -flat_namespace -undefined suppress -noprebind ../cmwind/libcmwind.o ../commands/libcommands.o ../database/libdatabase.o ../dbwind/libdbwind.o ../drc/libdrc.o ../debug/libdebug.o ../extract/libextract.o ../graphics/libgraphics.o ../select/libselect.o ../textio/libtextio.o ../tiles/libtiles.o ../windows/libwindows.o ../wiring/libwiring.o ../resis/libresis.o ../sim/libsim.o ../netmenu/libnetmenu.o ../plow/libplow.o ../utils/libutils.o ../ext2sim/libext2sim.o ../ext2spice/libext2spice.o ../calma/libcalma.o ../cif/libcif.o ../plot/libplot.o ../lef/liblef.o ../extflat/libextflat.o ../garouter/libgarouter.o ../mzrouter/libmzrouter.o ../router/librouter.o ../irouter/libirouter.o ../grouter/libgrouter.o ../gcr/libgcr.o ../tcltk/libtcltk.o -lc -lX11 -lGL -lGLU -lm -L/usr/X11/lib -lm -macosx_version_min 10.12 -all_load -why_load -map debug_map
ld: warning: option -noprebind is obsolete and being ignored
Again, I see the symbol is available:
cat debug_map | grep HashInit
0x0011F390 0x00000040 [ 18] _HashInit
0x0011F3D0 0x00000150 [ 18] _HashInitClient
0x001DADFE 0x00000006 [ 18] _HashInit
0x001DAE04 0x00000006 [ 18] _HashInitClient
0x001DF2B8 0x0000000A [ 18] _HashInit
0x001DF2C2 0x0000000A [ 18] _HashInitClient
0x0020C1D8 0x00000008 [ 18] _HashInit
0x0020C1E0 0x00000008 [ 18] _HashInitClient`
Btw, I've seen similar questions here and here, but I believe their scenario may be slightly different as one was cause by cmake mistake and the other was worked around by using DYLD_INSERT_LIBRARIES, which doesn't have an impact on my case.
Thanks in advance,
Ronald

It seems that adding -exported_symbol_list symbol.list to the linking command will get me pass the issue (symbol.list contains 1 exported symbol each line). However, I'm still getting the following (below command runs in tclsh):
(magic) 1 % load -lazy ./tclmagic.dylib
cannot find symbol "Tclmagic_Init": dlsym(0x10061e9f0, Tclmagic_Init): symbol not found

I believe that the answer is that the magic Makefile is not using the Tcl "stubs" libraries. I successfully converted netgen to use stubs, just need to do the same for magic. Using "-lazy" was, indeed, the lazy way to get around the issue, but using the stubs libraries are the correct way.
As a general procedure, file defs.mak needs to define LIB_SPECS with "-ltkstub8.6" and "-ltclstub8.6" instead of "-ltk8.6" and "-ltcl8.6". The fix is more complicated for use with "configure" since defs.mak is derived from defs.mak.in. But I think that a quick change to LIB_SPECS in defs.mak and a rebuild (without running configure) will work (probably have to do "make clean" first).
---Tim

Related

Undefined reference issue while creating executable

I am trying to create executable using some libraries.
My GCC command is :-
gcc -fPIC -DLINUX testdenpli /verilog/libdenpli.so -L/local/test/dir/ testpli.c
I have my library with symbols at path '/local/test/dir/'
Error:-
libdenpli.so: undefined reference to `ktlTcl_InitStubs'
libdenpli.so: undefined reference to `ktlitclStubsPtr'
I have the libraries with above symbols at path "'/local/test/dir/" .. But still seeing the issue.
Any one please help.
The error message says that libdenpli.so requires linking another shared library that provides symbols ktlTcl_InitStubs and ktlitclStubsPtr.
Find the shared library that provides those symbols using the following command:
for so in $(find /local/test/dir -name "*.so" -o -name "*.so.*"); do
nm --defined-only --dynamic $so 2>/dev/null | grep -q 'ktlTcl_InitStubs|ktlitclStubsPtr' && echo $so;
done
Then add that library into your linker command line:
gcc -Wall -Wextra -fPIC -DLINUX -o testdenpli testpli.c /verilog/libdenpli.so <full-path-to-found-library>
What is the name of the library containing the symbols? You need to include -lNAME to your compilation.
In general,
gcc file.c -o file -L/path/to/libs -lNAME
Note, the prefix "lib" and the suffix ".so" needn't be mentioned.

Build of guile-2.0.11 on macOS Sierra fails: Undefined symbols for architecture x86_64

I am not an experienced programmer/developer/software engineer, but I need to get this older version of guile-2.0.11 built "by hand" rather than using home-brew (which installs the latest version of guile). I downloaded the tarball for guile-2.0.11 from the GitHub repository, extracted it and ran the shell script autogen.sh. This produced a configure executable which ran to completion and generated a Makefile. When I run make, the build continues until I get the this error:
Undefined symbols for architecture x86_64:
"_clock_getcpuclockid", referenced from:
_scm_init_stime in libguile_2.0_la-stime.o
"_ffi_call", referenced from:
_scm_i_foreign_call in libguile_2.0_la-foreign.o
and 16 more "ffi" similar messages. Then the error messages finishes
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [libguile-2.0.la] Error 1
make[2]: *** [all] Error 2
make[1]: *** [all-recursive] Error 1
The linker apparently can't find these symbols. The explicit link command is quite extensive..it shows all the options, include and library paths if I use "make V=1". Here is the beginning, showing the options and paths:
Applications/Xcode.app/Contents/Developer/usr/bin/make all-am
/bin/sh ../libtool --tag=CC --mode=link gcc - I/usr/local/opt/gettext/include -I/usr/local/include - I/usr/local/opt/readline/include - I/usr/local/Cellar/gettext/0.19.8.1/include -D_THREAD_SAFE -Wall - Wmissing-prototypes -Wdeclaration-after-statement -Wpointer-arith -Wswitch- enum -fno-strict-aliasing -fwrapv -fvisibility=hidden - I/usr/local/Cellar/bdw-gc/7.6.0/include -g -O2 -L/usr/local/Cellar/bdw- gc/7.6.0/lib -lgc -L/usr/local/opt/libffi/lib -liconv - L/usr/local/opt/gettext/lib -lintl -R/usr/local/opt/gettext/lib -Wl,- framework -Wl,CoreFoundation -L/usr/local/lib -lunistring -R/usr/local/lib -version-info 29:2:7 -export-dynamic -no-undefined -L/usr/local/opt/gettext/lib -L/usr/local/lib -L/usr/local/opt/readline/lib -L/usr/local/Cellar/gettext/0.19.8.1/lib -o libguile-2.0.la -rpath /usr/local/lib
Then there is libtool.
libtool: link: gcc -dynamiclib -o .libs/libguile-2.0.22.dylib .libs/libguile_2.0_la-alist.o .libs/libguile_2.0_la-arbiters.o .libs/libguile_2.0_la-array-handle.o
and many many more xxxx.o
then
-Wl,-force_load,../lib/.libs/libgnu.a -L/usr/local/Cellar/bdw- gc/7.6.0/lib -lgc -L/usr/local/opt/libffi/lib -L/usr/local/opt/gettext/lib -L/usr/local/lib -L/usr/local/opt/readline/lib - L/usr/local/Cellar/gettext/0.19.8.1/lib -lintl -lunistring -liconv -lgmp - lltdl -lm -g -O2 -Wl,-framework -Wl,CoreFoundation -install_name /usr/local/lib/libguile-2.0.22.dylib -compatibility_version 30 - current_version 30.2 -Wl,-single_module
The up-to-date version of ffilib is in the symlink /usr/local/opt/libffi/lib which is in the ld path, so I would think that the linker could find it. Any help would be greatly appreciated.
This problem is really two problems: (1) the undefined symbol "_clock_getcpuclockid" and (2) all the "ffi" undefined symbols. The answer to the second problem is here and the answer to the first problem is here. There may be other solutions but these resulted in the installation of guile-2.0.11 on my macOS Sierra (10.12.5),

When using the GCC driver, what makes a static lib "incompatible"?

So what I am trying to do is on Ubuntu 14.04 (x86_64) I want to set up musl-libc based on the latest released 1.1.11 version which is available at this moment.
What I did was to:
Install multilib support for GCC: sudo apt-get --no-install-recommends install gcc-multilib
Configure the libraries for 32-bit and 64-bit respectively and install them into separate folders:
CFLAGS=-m32 ./configure --prefix=$HOME/bin/musl-32-bit --disable-shared --target=i386-linux-gnu && make && make install
CFLAGS=-m64 ./configure --prefix=$HOME/bin/musl-64-bit --disable-shared --target=x86_64-linux-gnu
Then in order to build a statically linked premake4, I invoke GNU make like this on the Makefile generated by premake4:
make -j 8 CC=$HOME/bin/musl-32-bit/bin/musl-gcc ARCH=-m32 LDFLAGS="-v -static" verbose=1
This appears to work up to the linking step, which bombs with:
Linking Premake4
$HOME/bin/musl-32-bit/bin/musl-gcc -o bin/release/premake4 intermediate/gmake__/premake.o intermediate/gmake__/os_uuid.o intermediate/gmake__/os_pathsearch.o intermediate/gmake__/os_match.o intermediate/gmake__/os_chdir.o intermediate/gmake__/os_mkdir.o intermediate/gmake__/os_stat.o intermediate/gmake__/os_getversion.o intermediate/gmake__/premake_main.o intermediate/gmake__/os_isdir.o intermediate/gmake__/string_endswith.o intermediate/gmake__/os_isfile.o intermediate/gmake__/scripts.o intermediate/gmake__/path_isabsolute.o intermediate/gmake__/os_rmdir.o intermediate/gmake__/os_getcwd.o intermediate/gmake__/os_is64bit.o intermediate/gmake__/os_copyfile.o intermediate/gmake__/lstate.o intermediate/gmake__/ltable.o intermediate/gmake__/lgc.o intermediate/gmake__/lobject.o intermediate/gmake__/lcode.o intermediate/gmake__/lmathlib.o intermediate/gmake__/lbaselib.o intermediate/gmake__/lmem.o intermediate/gmake__/lfunc.o intermediate/gmake__/lparser.o intermediate/gmake__/ldblib.o intermediate/gmake__/lzio.o intermediate/gmake__/lstrlib.o intermediate/gmake__/lvm.o intermediate/gmake__/lauxlib.o intermediate/gmake__/llex.o intermediate/gmake__/lstring.o intermediate/gmake__/ldump.o intermediate/gmake__/ldebug.o intermediate/gmake__/loadlib.o intermediate/gmake__/lopcodes.o intermediate/gmake__/linit.o intermediate/gmake__/ldo.o intermediate/gmake__/lapi.o intermediate/gmake__/liolib.o intermediate/gmake__/loslib.o intermediate/gmake__/lundump.o intermediate/gmake__/ltm.o intermediate/gmake__/ltablib.o -v -static -L. -s -rdynamic -lm -ldl
Using built-in specs.
Reading specs from $HOME/bin/musl-32-bit/lib/musl-gcc.specs
rename spec cpp_options to old_cpp_options
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-m32' '-o' 'bin/release/premake4' '-v' '-static' '-L.' '-s' '-rdynamic' '-specs=$HOME/bin/musl-32-bit/lib/musl-gcc.specs' '-mtune=generic' '-march=i686'
/usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 -dynamic-linker /lib/ld-musl-i386.so.1 -nostdlib -static -export-dynamic -z relro -o bin/release/premake4 -s $HOME/bin/musl-32-bit/lib/crt1.o $HOME/bin/musl-32-bit/lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o -L. -L$HOME/bin/musl-32-bit/lib -L /usr/lib/gcc/x86_64-linux-gnu/4.8/. intermediate/gmake__/premake.o intermediate/gmake__/os_uuid.o intermediate/gmake__/os_pathsearch.o intermediate/gmake__/os_match.o intermediate/gmake__/os_chdir.o intermediate/gmake__/os_mkdir.o intermediate/gmake__/os_stat.o intermediate/gmake__/os_getversion.o intermediate/gmake__/premake_main.o intermediate/gmake__/os_isdir.o intermediate/gmake__/string_endswith.o intermediate/gmake__/os_isfile.o intermediate/gmake__/scripts.o intermediate/gmake__/path_isabsolute.o intermediate/gmake__/os_rmdir.o intermediate/gmake__/os_getcwd.o intermediate/gmake__/os_is64bit.o intermediate/gmake__/os_copyfile.o intermediate/gmake__/lstate.o intermediate/gmake__/ltable.o intermediate/gmake__/lgc.o intermediate/gmake__/lobject.o intermediate/gmake__/lcode.o intermediate/gmake__/lmathlib.o intermediate/gmake__/lbaselib.o intermediate/gmake__/lmem.o intermediate/gmake__/lfunc.o intermediate/gmake__/lparser.o intermediate/gmake__/ldblib.o intermediate/gmake__/lzio.o intermediate/gmake__/lstrlib.o intermediate/gmake__/lvm.o intermediate/gmake__/lauxlib.o intermediate/gmake__/llex.o intermediate/gmake__/lstring.o intermediate/gmake__/ldump.o intermediate/gmake__/ldebug.o intermediate/gmake__/loadlib.o intermediate/gmake__/lopcodes.o intermediate/gmake__/linit.o intermediate/gmake__/ldo.o intermediate/gmake__/lapi.o intermediate/gmake__/liolib.o intermediate/gmake__/loslib.o intermediate/gmake__/lundump.o intermediate/gmake__/ltm.o intermediate/gmake__/ltablib.o -lm -ldl --start-group /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc_eh.a -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o $HOME/bin/musl-32-bit/lib/crtn.o
/usr/bin/ld: skipping incompatible $HOME/bin/musl-32-bit/lib/libc.a when searching for -lc
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
make[1]: *** [bin/release/premake4] Error 1
make: *** [Premake4] Error 2
The relevant line is:
/usr/bin/ld: skipping incompatible $HOME/bin/musl-32-bit/lib/libc.a when searching for -lc
Now the part I don't understand about this is, that when I ar x the libc.a (into a folder $HOME/bin/musl-32-bit/lib/libc) generated during the build step of musl-libc (see above), it proves that all of the objects included seem to be of the correct target architecture (all show ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped) as I can prove from coming up empty when issuing the following command:
find $HOME/bin/musl-32-bit/lib -name '*.o' -exec file {} +|grep -v 'ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped'
And in fact this gives no output. Similarly when looking inside the build directory using the same method, I cannot find any object file that doesn't match my expectation.
For good measure I decided to also task objdump to tell me more about the libc.a in question and came up with the same result:
objdump -a $HOME/bin/musl-32-bit/lib/libc.a|grep 'file format'|grep -v 'file format elf32-i386'
So my question is twofold:
what disqualifies a static library as "incompatible" when GCC is asked to link it?
what could be the particular issue I am seeing?
The first is what I am really interested in, but with the second I am asking to share your experience with trouble-shooting like this. Which verification steps have I missed, for example?
Please note that the "native" premake4 builds just fine with:
make -j 8 CC=$HOME/bin/musl-64-bit/bin/musl-gcc ARCH=-m64 LDFLAGS=-static verbose=1
From the output when adding the -v flag to LDFLAGS it appears as if the target always stays at x86_64-linux-gnu. I have yet to come up with a method to fix this, though.
In short, the musl-gcc wrapper script setup is not well-suited to use with -m32. I think what's happening is that the actual compiler is getting invoked in the default (64-bit) mode by musl-gcc, then the resulting object files are not compatible with the (intended, 32-bit) libc.
It may work if you put -m32 in the generated wrapper script. This will happen automatically with recent versions if you put the -m32 in $CC (i.e. CC="gcc -m32") rather than putting it in $CFLAGS.
Update: As noted in the discussion that was moved to chat, adding -Wl,-melf_i386 is probably also needed (due to flaws in the spec file used by the musl-gcc wrapper that don't account for -m32 support) but still does not seem to be sufficient.
The solution
It turns out the solution is rather simple.
We need to tell both the linker and the driver to use -m32 ... I was that far before. However, it turns out that the missing piece was to pass the linker option to the driver via CFLAGS like this -Wl,-melf_i386.
I am finally able to build and link the 32-bit executable on a multilib-enabled 64-bit host.
NB: Below information is left in place for those who want to learn how I investigated the issue.
Alright, so I investigated the issue a little further and the output gets more enlightening once you extract the object files. To reproduce what I am doing you may have to use Bash or a similar shell that allows for $(...) or you need to adjust the command lines accordingly.
First off it's important to have gcc-multilib and friends installed in order to target -m32 (i386-linux-gnu which happens to be an alias for i686-linux-gnu here).
The code and the make file
I had the following make file:
CC?=$(HOME)/bin/musl/bin64/musl-gcc
BLDARCH?=-m64
CFLAGS+=-v $(BLDARCH)
LDFLAGS+=-v -static $(BLDARCH)
all: helloworld
helloworld: helloworld.c
clean:
rm -f helloworld
rebuild: clean all
.PHONY: clean rebuild
.NOTPARALLEL: rebuild
and the following small helloworld.c:
#include <stdio.h>
int main(int argc, char** argv)
{
printf("Hello world!\n");
return 0;
}
and my 32-bit musl-libc was installed to $HOME/bin/musl/{bin,include,lib}32 respectively. The 64-bit one was installed to $HOME/bin/musl/{bin,include,lib}64 respectively.
Attempting to build with:
make CC=$HOME/bin/musl/bin32/musl-gcc BLDARCH=-m32 rebuild
always failed with the same meaningless lines:
/usr/bin/ld: skipping incompatible ~/bin/musl/lib32/libc.a when searching for -lc
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
make: *** [helloworld] Error 1
Digging into the details
So after some contemplation I decided to re-do the steps done by the gcc driver manually.
This meant to run roughly (I replaced all occurrences of my home folder with a ~):
Compile: /usr/lib/gcc/x86_64-linux-gnu/4.8/cc1 -quiet -imultilib 32 -imultiarch i386-linux-gnu helloworld.c -nostdinc -isystem ~/bin/musl/include32 -isystem /usr/lib/gcc/x86_64-linux-gnu/4.8/include -quiet -dumpbase helloworld.c -m32 -mtune=generic -march=i686 -auxbase helloworld -version -fstack-protector -Wformat -Wformat-security -o /tmp/ccGmMuR1.s
Assemble: as -v -v --32 -o /tmp/ccgRGlqf.o /tmp/ccGmMuR1.s
Link: env COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS="-v -v -static -m32 -o helloworld -specs=~/bin/musl/lib32/musl-gcc.specs -mtune=generic -march=i686" /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 -dynamic-linker /lib/ld-musl-i386.so.1 -nostdlib -static -z relro -o helloworld ~/bin/musl/lib32/crt1.o ~/bin/musl/lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtbegin.o -L~/bin/musl/lib32 -L /usr/lib/gcc/x86_64-linux-gnu/4.8/32/. /tmp/ccpL09mJ.o --start-group /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc_eh.a -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtend.o ~/bin/musl/lib32/crtn.o
Obviously this didn't change the error message a bit just yet:
/usr/bin/ld: skipping incompatible ~/bin/musl/lib32/libc.a when searching for -lc
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
So I took out the -lc from the command line for collect2 and created a folder ~/bin/musl/lib32/archive into which I extracted the whole libc.a generated by my musl-libc build attempt. I then instructed collect2 where to find the object files like this:
Link: env COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gc
c/x86_64-linux-gnu/4.8/32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS="-v -v -
static -m32 -o helloworld -specs=~/bin/musl/lib32/musl-gcc.specs -mtune=generic -march=i686" /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 -dynamic-linker /lib/ld-musl-i386.so.1 -nostdlib -static -z relro -o helloworld $HOME/bin/musl/lib32/crt1.o ~/bin/musl/lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtbegin.o -L~/bin/musl/lib32 -L /usr/lib/gcc/x86_64-linux-gnu/4.8/32/. /tmp/ccpL09mJ.o --start-group /usr/lib/gcc/x86_64-linux-g
nu/4.8/32/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc_eh.a --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/32/crtend.o ~/bin/musl/lib32/crtn.o $(find ~/bin/musl/lib32/archive -type f -name '*.o')
This gist is taking out -lc and appending $(find ~/bin/musl/lib32/archive -type f -name '*.o').
Which gave me a whole bunch of new, but more meaningful errors similar to the following ones:
/usr/bin/ld: Warning: size of symbol `__init_ssp' changed from 1 in ~/bin/musl/lib32/archive/__libc_start_main.o to 65 in ~/bin/musl/lib32/archive/__stack_chk_fail.o
/usr/bin/ld: Warning: size of symbol `__funcs_on_exit' changed from 126 in ~/bin/musl/lib32/archive/atexit.o to 1 in ~/bin/musl/lib32/archive/exit.o
# more of those
/usr/bin/ld: i386 architecture of input file `~/bin/musl/lib32/crt1.o' is incompatible with i386:x86-64 output
/usr/bin/ld: i386 architecture of input file `~/bin/musl/lib32/crti.o' is incompatible with i386:x86-64 output
# more of those
The plot thickens. Apparently the collect2 command gets the wrong idea about what to build. Which is odd considering the output for the governing environment variables:
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-v' '-static' '-m32' '-o' 'helloworld' '-specs=~/bin/musl/lib32/musl-gcc.specs' '-mtune=generic' '-march=i686'
... which I passed using env in my attempt to reproduce the conditions encountered by the collect2 wrapper when linking the libc.a.
In order to find out more about the internals of the GNU compilers one needs to read https://gcc.gnu.org/onlinedocs/gccint/
Unfortunately the part about collect2 doesn't help us here. But the lengthy output of /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 --help looks promising.
Just how could we smuggle our command line option to collect2?
For now I was going to settle for whatever I could run manually. So I attempted to tell the linker which output format I expected. Based on the list of supported targets I was interested in elf_i386.
Passing -melf_386 at the end of the previous line gave an interesting error output. Numerous referenced functions such as __vsyscall, __moddi3 and __divdi3 were undefined. That indicated they simply didn't exist in the object files from the static lib or in any of the startup .o files for that matter:
~/bin/musl/lib32/archive/aio.o: In function `cleanup':
aio.c:(.text+0x5ad): undefined reference to `__vsyscall'
aio.c:(.text+0x5bb): undefined reference to `__vsyscall'
aio.c:(.text+0x5e8): undefined reference to `__vsyscall'
aio.c:(.text+0x5f6): undefined reference to `__vsyscall'
aio.c:(.text+0x61d): undefined reference to `__vsyscall'
~/bin/musl/lib32/archive/aio.o:aio.c:(.text+0x62b): more undefined references to `__vsyscall' follow
~/bin/musl/lib32/archive/cpow.o: In function `cpow':
cpow.c:(.text+0x4f): undefined reference to `__mulxc3'
~/bin/musl/lib32/archive/cpowf.o: In function `cpowf':
cpowf.c:(.text+0x47): undefined reference to `__mulxc3'
~/bin/musl/lib32/archive/cpowl.o: In function `cpowl':
cpowl.c:(.text+0x4c): undefined reference to `__mulxc3'
~/bin/musl/lib32/archive/sysconf.o: In function `sysconf':
sysconf.c:(.text+0xcc): undefined reference to `__vsyscall'
~/bin/musl/lib32/archive/__getdents.o: In function `__getdents':
__getdents.c:(.text+0x13): undefined reference to `__vsyscall'
~/bin/musl/lib32/archive/opendir.o: In function `opendir':
opendir.c:(.text+0x37): undefined reference to `__vsyscall'
~/bin/musl/lib32/archive/readdir.o: In function `readdir':
readdir.c:(.text+0x1f): undefined reference to `__vsyscall'
~/bin/musl/lib32/archive/__init_tls.o: In function `__init_tls':
__init_tls.c:(.text+0x136): undefined reference to `__vsyscall6'
__init_tls.c:(.text+0x16e): undefined reference to `__vsyscall'
As I had already clarified in my question, the object files from the archive all stated that they were elf32-i386.
The functions __vsyscall and __vsyscall6 should end up in a file called syscall.o given the source file for i386 in musl-libc: src/internal/i386/syscall.s. Let's verify that first. Since there is also a file src/misc/syscall.c the name might be different though. Four files have syscall in the file name:
__syscall_cp.o
syscall_cp.o
syscall.o
syscall_ret.o
Querying those files using nm gave:
$ nm -s $(ls |grep syscall)
__syscall_cp.o:
00000000 t sccp
U __syscall
00000005 T __syscall_cp
00000000 W __syscall_cp_c
syscall_cp.o:
U __cancel
00000008 T __cp_begin
00000035 T __cp_cancel
00000030 T __cp_end
00000000 T __syscall_cp_asm
syscall.o:
00000000 T syscall
U __syscall_ret
U __vsyscall6
syscall_ret.o:
U __errno_location
00000000 T __syscall_ret
Symbols with the symbol type U are undefined and therefore expected by the linker to come from outside (external to each object file).
A final $ nm --defined-only *.o ../*.o|grep vsyscall was what was needed to verify that those symbols were indeed missing from the libc.a.
So the cross-built libc.a what was faulty after all. Back to the drawing board.
I hope this description helps others to figure out similar issues and look behind the scenes in GCC.
The saga continues
I was really surprised to see:
$ nm --defined-only ../libc.a |grep -B 2 vsyscall
syscall.o:
0000004b T __syscall
00000000 T __vsyscall
00000031 T __vsyscall6
but for the extracted object files the corresponding command (nm --defined-only *.o ../*.o|grep -B 2 vsyscall) would yield no output.
So inside the libc.a somehow nm sees the two symbols, but after extracting them they disappear? Odd.
Let's look for syscall.o in the libc.a:
$ nm ../libc.a |grep ^syscall
syscall.o:
syscall_ret.o:
syscall.o:
syscall_cp.o:
Whoa? So syscall.o exists twice inside the static library? Well that looks like it may just be the error cause we're looking for. And it certainly does explain why the symbols disappear. Likely the latter syscall.o overwrites the one first extracted when running ar x ....
Confirming:
$ nm ../libc.a |grep -A 4 ^syscall\.o
syscall.o:
0000004b T __syscall
U __sysinfo
00000000 T __vsyscall
00000031 T __vsyscall6
--
syscall.o:
00000000 T syscall
U __syscall_ret
U __vsyscall6
and looking into the musl-libc source tree after doing the 32-bit build:
$ find . -type f -name 'syscall.o' -exec nm {} +
./src/internal/syscall.o:
0000004b T __syscall
U __sysinfo
00000000 T __vsyscall
00000031 T __vsyscall6
./src/misc/syscall.o:
00000000 T syscall
U __syscall_ret
U __vsyscall6
Copying the former into the lib32/archive directory under a name that doesn't collide with existing names gives more errors on other functions, suggesting other object files may also exist as duplicates inside the generated libc.a.
Which ones are duplicates?
$ diff <(nm libc.a|grep ':$'|cut -f 1 -d :|sort) <(nm libc.a|grep ':$'|cut -f 1 -d :|sort -u)
--- /dev/fd/63 2015-10-05 23:58:53.683804823 +0000
+++ /dev/fd/62 2015-10-05 23:58:53.683804823 +0000
## -131,7 +131,6 ##
clogl.o
clog.o
clone.o
-clone.o
closedir.o
close.o
cnd_broadcast.o
## -1115,7 +1114,6 ##
__syscall_cp.o
syscall_cp.o
syscall.o
-syscall.o
syscall_ret.o
sysconf.o
sysinfo.o
This way we see clone.o and syscall.o are affected as duplicates. Which indicates that some object files are missing altogether from the libc.a given undefined references to the following symbols:
__divdi3
__moddi3
__mulxc3
__tls_get_new
__udivdi3
__umoddi3
These names happen to coincide with the ones from the Integer library routines listed for GCC. Which makes me think I am missing one library provided by GCC which to link. Like libgcc?! ...
I have package lib32gcc-4.8-dev which means I should have the required file:
$ apt-file list lib32gcc-4.8-dev|grep -E 'libgcc.*\.a'
lib32gcc-4.8-dev: /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc.a
lib32gcc-4.8-dev: /usr/lib/gcc/x86_64-linux-gnu/4.8/32/libgcc_eh.a
After the previous step I decided to set up a x86_32 version on Ubuntu 14.04 that was essentially at the same patch level.
I then compared the libgcc.a from the x86_32 machine with that from the x86_64 machine. They turned out to be almost identical except for the "symbol value" (in nm lingo) of a handful of functions.
Also, since the symbols were in the static library I attempted to link against the static library again. This worked only with -melf_i386 on the linker (collect2) command line.
After trying to use LDFLAGS and noticing that those were also passed to cc1, I set appended -Wl,-melf_i386 to the CFLAGS and now it worked. Brilliant.
As a side-note: I also swapped the /usr/lib/gcc/x86_64-linux-gnu/4.8/collect2 in the command line for ld of which collect2 is supposed to be a wrapper. The error output was identical.

arm-gcc unresolved reference 'sinf'

I'm getting this error when trying to compile:
error: undefined reference to `sinf'
I have included math.h, and verified that it is defined in there:
#include <math.h>
However, I get an error while trying to link to the math library:
arm-none-eabi-ld -L/usr/lib -lm --gc-sections -T ../standalone.ld -o "main.elf" ./main.o ./startup_gcc.o
error: cannot find -lm
However, the library is obviously there:
Kens-MacBook-Pro:lib Ken$ pwd
/usr/lib
Kens-MacBook-Pro:lib Ken$ ls | grep libm
libm.dylib
libmecab.1.0.0.dylib
libmecab.dylib
libmecabra.dylib
libmenu.5.4.dylib
libmenu.dylib
libmx.A.dylib
libmx.dylib
Kens-MacBook-Pro:lib Ken$
What am I doing wrong? I'm using Eclipse.
Judging by your arm-none-eabi-ld command, I'm assuming you're cross compiling. You need to install some sort of math library into the toolchain for whatever your platform is.
The ls output you posted contains a list of libraries available for your host, not your target. On my machine, the libraries for my ARM cross-compiler resides in /opt/local/arm-none-eabi/lib/ for example.
danieltang ~$ ls /opt/local/arm-none-eabi/lib/
crt0.o ldscripts libm.a libssp_nonshared.a libstdc++.a-gdb.py libsupc++.la
elf2flt.ld libc.a libssp.a libssp_nonshared.la libstdc++.la thumb
fpu libg.a libssp.la libstdc++.a libsupc++.a

Underbars in symbol names when linking against an external library

I'm trying to compile a C library and then some external C code liked against it and I'm having issues with my external code finding the symbols within the library. I don't understand the big flick and am hoping someone can help. Here are the details:
1) I'm working on a Mac. I've compiled the library as a static .a library in xcode.
2) I'm attempting to compile external code calling functions from the library. I've included the header file and I'm specifying it's location and the library in the gcc call. The compilation seems to complete ok, but the linking fails stating that symbols cannot be found.
3) The missing symbols are listed as _FunctionName where FunctionName is the name of the function I called.
It is not clear to me why the compiler/linker has added underbars to my function names. But my naive guess is that is why the symbols can not be found in the library.
The external code compilation is being done through MATLAB's mex() function which is making the gcc calls below in the background.
I'd be thankful for any thoughts anyone might have.
gcc-4.2 -c -Igsf_0303/ -I/Applications/MATLAB_R2011b.app/extern/include \
-DMATLAB_MEX_FILE -fno-common -no-cpp-precomp -arch x86_64 -isysroot \
/Developer/SDKs/MacOSX10.6.sdk -mmacosx-version-min=10.5 -fexceptions \
-DMX_COMPAT_32 -O2 -DNDEBUG "gsf_tester.c"
gcc-4.2 -O -Wl,-twolevel_namespace -undefined error -arch x86_64 -Wl, \
-syslibroot,/Developer/SDKs/MacOSX10.6.sdk -mmacosx-version-min=10.5 -bundle -Wl,\
-exported_symbols_list,/Applications/MATLAB_R2011b.app/extern/lib/maci64/mexFunction.map \
-o "gsf_tester.mexmaci64" gsf_tester.o gsf_0303/libgsf.a \
-L/Applications/MATLAB_R2011b.app/bin/maci64 -lmx -lmex -lmat -lstdc++
Undefined symbols:
"_gsfOpen", referenced from:
_mexFunction in gsf_tester.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
mex: link of ' "gsf_tester.mexmaci64"' failed.
Here's a guess. Firstly, Joachim's comment is correct. C function names will always be prepended with an underscore. So that's not the issue.
So either gfsOpen() is missing from the library or it's not visible or it can't be seen when gfs_tester.o is linked.
So check that gfsOpen is in the library. This should do it
otool -t -v sgsf_0303/libgsf.a | grep gsfOpen
The above disassembles the file and then greps the symbol you are interested in from it. There's probably a better way, but I haven't bothered to research it.
Check it's not declared static.
Make sure the architecture of the library matches (otool -fv)

Resources