Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to link C++ object files with ld

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?

like image 635
gsingh2011 Avatar asked Jan 04 '13 19:01

gsingh2011


People also ask

How are object files linked?

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.

Can you link C and C++ object files?

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.

What does ld do in C?

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.

What is ld in command line?

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.


1 Answers

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.

like image 123
Carl Norum Avatar answered Sep 20 '22 09:09

Carl Norum