I'm trying to link the output of C++ using ld and not g++. I'm only doing this to learn how to do it, not for practical purposes, so please don't suggest just to do it with g++.
Looking at this question, the person gets the same error when they run the ld command:
$ ld test.o -o test.out ld: warning: cannot find entry symbol _start; defaulting to 00000000004000e8 test.o: In function `main': test.cpp:(.text+0x1c): undefined reference to `strcasecmp' test.cpp:(.text+0x23): undefined reference to `std::cout' test.cpp:(.text+0x28): undefined reference to `std::ostream::operator<<(int)' test.cpp:(.text+0x2d): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)' test.cpp:(.text+0x35): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))' test.o: In function `__static_initialization_and_destruction_0(int, int)': test.cpp:(.text+0x75): undefined reference to `std::ios_base::Init::Init()' test.cpp:(.text+0x7a): undefined reference to `__dso_handle' test.cpp:(.text+0x84): undefined reference to `std::ios_base::Init::~Init()' test.cpp:(.text+0x89): undefined reference to `__cxa_atexit' ld: test.out: hidden symbol `__dso_handle' isn't defined ld: final link failed: Bad value
The answers in the linked post suggest that adding the C++ library as a linker argument will fix the problem, so I tried
ld test.o -o test.out -llibstd++
which is what they suggested, and I also tried a lot of other library names like libstdc++ or stdc++. But I'll always get an error that looks like
ld: cannot find -llibstd++
What am I doing wrong and how can I link my object files using ld?
A shared object file holds code and data suitable to be linked in two contexts. First, the link-editor can process it with other relocatable and shared object files to create other object files. Second, the runtime linker combines it with a dynamic executable file and other shared objects to create a process image.
Accessing C Code from Within C++ Source The default linkage for objects and functions is C++. All C++ compilers also support C linkage, for some compatible C compiler.
The %ld format specifier is implemented for representing long integer values. It is implemented with the printf() function for printing the long integer value stored in the variable.
Description. The ld command, also called the linkage editor or binder, combines object files, archives, and import files into one output object file, resolving external references. It produces an executable object file that can be run.
If you run g++
with the -v
flag, you'll see the link line it uses. Here's a simple example program:
#include <iostream> int main(void) { std::cout << "Hello, world!" << std::endl; return 0; }
And the output from running g++ -v -o example example.cpp
:
Using built-in specs. Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.4.4-14ubuntu5.1' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-werror --with-arch-32=i686 --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.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5.1) COLLECT_GCC_OPTIONS='-v' '-o' 'example' '-shared-libgcc' '-mtune=generic' /usr/lib/gcc/x86_64-linux-gnu/4.4.5/cc1plus -quiet -v -D_GNU_SOURCE example.cpp -D_FORTIFY_SOURCE=2 -quiet -dumpbase example.cpp -mtune=generic -auxbase example -version -fstack-protector -o /tmp/ccV8qjvd.s ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../x86_64-linux-gnu/include" ignoring nonexistent directory "/usr/include/x86_64-linux-gnu" #include "..." search starts here: #include <...> search starts here: /usr/include/c++/4.4 /usr/include/c++/4.4/x86_64-linux-gnu /usr/include/c++/4.4/backward /usr/local/include /usr/lib/gcc/x86_64-linux-gnu/4.4.5/include /usr/lib/gcc/x86_64-linux-gnu/4.4.5/include-fixed /usr/include End of search list. GNU C++ (Ubuntu/Linaro 4.4.4-14ubuntu5.1) version 4.4.5 (x86_64-linux-gnu) compiled by GNU C version 4.4.5, GMP version 4.3.2, MPFR version 3.0.0-p3. GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: d92fbc2d715a3b7e0f4133f0c40053e4 COLLECT_GCC_OPTIONS='-v' '-o' 'example' '-shared-libgcc' '-mtune=generic' as -V -Qy -o /tmp/ccGHR0pc.o /tmp/ccV8qjvd.s GNU assembler version 2.20.51 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.20.51-system.20100908 COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../:/lib/:/usr/lib/:/usr/lib/x86_64-linux-gnu/ COLLECT_GCC_OPTIONS='-v' '-o' 'example' '-shared-libgcc' '-mtune=generic' /usr/lib/gcc/x86_64-linux-gnu/4.4.5/collect2 --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o example -z relro /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../.. -L/usr/lib/x86_64-linux-gnu /tmp/ccGHR0pc.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o
Wow, what a mess. Conveniently the link line is the last one there, so you can see what's happening pretty easily.
As you noticed in your comment below, the front-end is using collect2
rather than ld
. Luckily, collect2
is just an alias for ld
. Here's an example using it:
First let's generate an object file:
$ ls example.cpp $ c++ -c example.cpp $ ls example.cpp example.o
Then we'll use the front-end to link it to see the link line:
$ c++ -v -o example example.o Using built-in specs. Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.4.4-14ubuntu5.1' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-werror --with-arch-32=i686 --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.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5.1) COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../:/lib/:/usr/lib/:/usr/lib/x86_64-linux-gnu/ COLLECT_GCC_OPTIONS='-v' '-o' 'example' '-shared-libgcc' '-mtune=generic' /usr/lib/gcc/x86_64-linux-gnu/4.4.5/collect2 --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o example -z relro /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../.. -L/usr/lib/x86_64-linux-gnu example.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o
Then throw away the binary, and link ourselves (normally, I would have just copy/pasted the line, but to make it easier to read I did it the multiline way with \
s):
$ ls example example.cpp example.o $ rm example $ ls example.cpp example.o $ ld \ > --build-id \ > --eh-frame-hdr \ > -m elf_x86_64 \ > --hash-style=gnu \ > -dynamic-linker \ > /lib64/ld-linux-x86-64.so.2 \ > -o example \ > -z relro \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o \ > -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 \ > -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 \ > -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib \ > -L/lib/../lib \ > -L/usr/lib/../lib \ > -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../.. \ > -L/usr/lib/x86_64-linux-gnu \ > example.o \ > -lstdc++ \ > -lm \ > -lgcc_s \ > -lgcc \ > -lc \ > -lgcc_s \ > -lgcc \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o
Finally, run it!
$ ls example example.cpp example.o $ ./example Hello, world!
You can probably significantly shorten that link line by removing some arguments. Here's the minimal set I came up with after some experimentation:
$ ld \ > -dynamic-linker \ > /lib64/ld-linux-x86-64.so.2 \ > -o example \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o \ > example.o \ > -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 \ > -lstdc++ \ > -lc \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o \ > /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o
This set of flags and libraries will of course depend on what library functions and language features your program uses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With