g++ (GCC) 5.2.0
clang version 3.7.1 (tags/RELEASE_371/final)
GNU gdb (GDB) 7.12
Gdb is unable to locate the definition of std::string when compiled with clang for some reason. I have custom compiled and build gcc and clang as Centos 6.5 comes with older version of gcc.
Example code
#include <string>
int main()
{
std::string s("This is a string");
return 0;
}
Compile with g++ and debug - works just fine
[~]$ g++ -ggdb3 -std=c++14 stl.cpp
[~]$ gdb a.out
GNU gdb (GDB) 7.12
Reading symbols from a.out...done.
(gdb) break main
Breakpoint 1 at 0x400841: file stl.cpp, line 5.
(gdb) r
Starting program: /home/vagrant/a.out
Breakpoint 1, main () at stl.cpp:5
5 std::string s("This is a string");
(gdb) n
7 return 0;
(gdb) p s
$1 = {static npos = <optimized out>,
_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x612c20 "This is a string"}, _M_string_length = 16, {
_M_local_buf = "\020\000\000\000\000\000\000\000\300\b#\000\000\000\000", _M_allocated_capacity = 16}}
(gdb)
Check that it is linking with my rpm build version of libstdc++ and not system
[~]$ ldd a.out
linux-vdso.so.1 => (0x00007ffd709e0000)
libstdc++.so.6 => /opt/spotx-gcc/lib64/libstdc++.so.6 (0x00007f29318fa000)
libm.so.6 => /lib64/libm.so.6 (0x00007f2931676000)
libgcc_s.so.1 => /opt/spotx-gcc/lib64/libgcc_s.so.1 (0x00007f293145f000)
libc.so.6 => /lib64/libc.so.6 (0x00007f29310cb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2931c93000)
[~]$ objdump -T -C a.out
a.out: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4 std::allocator<char>::~allocator()
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4 std::allocator<char>::allocator()
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_Resume
0000000000400700 DF *UND* 0000000000000000 CXXABI_1.3 __gxx_personality_v0
All looks good now if I try the same with clang
[~]$ clang++ -std=c++14 -g stl.cpp
[~]$ gdb a.out
GNU gdb (GDB) 7.12
Reading symbols from a.out...done.
(gdb) break main
Breakpoint 1 at 0x400853: file stl.cpp, line 5.
(gdb) r
Starting program: /home/vagrant/a.out
Breakpoint 1, main () at stl.cpp:5
5 std::string s("This is a string");
(gdb) n
7 return 0;
(gdb) p s
$1 = <incomplete type>
(gdb)
Now I get an incomplete type - but the same libraries are being used
[~]$ ldd a.out
linux-vdso.so.1 => (0x00007fff5352d000)
libstdc++.so.6 => /opt/spotx-gcc/lib64/libstdc++.so.6 (0x00007f76b4023000)
libm.so.6 => /lib64/libm.so.6 (0x00007f76b3d9f000)
libgcc_s.so.1 => /opt/spotx-gcc/lib64/libgcc_s.so.1 (0x00007f76b3b88000)
libc.so.6 => /lib64/libc.so.6 (0x00007f76b37f4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f76b43bc000)
[~]$ objdump -T -C a.out
a.out: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4 std::allocator<char>::~allocator()
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4 std::allocator<char>::allocator()
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_Resume
0000000000400700 DF *UND* 0000000000000000 CXXABI_1.3 __gxx_personality_v0
Does anyone have any advice on where to look or something that I've missed. Both compilers are bootstrapped when building them - everything seems fine - it just appears to be std::string is not defined when using clang.
As ks1322 mentioned, this is because clang has decided not to emit debug information for libstc++.
You can force clang to do so by providing the following flag:
-D_GLIBCXX_DEBUG
I would only provide the flag for debug builds, but if debug is the default and release builds are a special target you should remove it:
release: CXXFLAGS := $(filter-out -D_GLIBCXX_DEBUG,$(CXXFLAGS)) -O2
This has fixed the same problem for me.
The last workaround mentioned in bug 24202 as linked by ks1322 is worth having a look at:
-fno-limit-debug-info will make your debug info larger, slow link (if you're not using -gsplit-dwarf) and debugger performance. But, yes, will address this.
Using -fno-limit-debug-info forces Clang to emit debug information for e.g. std::string at the cost of a larger binary while preserving compatibility with other libraries and the rest of the system/SDK.
As ks1322 and Kevin mentioned, one can instead use -D_GLIBCXX_DEBUG to switch libstdc++ into debug mode but this comes at a heavy price: any library you link against and with which you exchange STL containers (string, vector, etc.) must also be built with -D_GLIBCXX_DEBUG. Meaning: your system/SDK must either support this with a separate set of libraries or you will have to rebuild them yourself.
I've reproduced this issue on Fedora with system clang.
It appears that clang is not emitting debug information for std::string because it was told that libstdc++ provides it. See this comment from bug 24202:
Looks like you don't have debug information for libstdc++ installed:
Missing separate debuginfos, use: dnf debuginfo-install libgcc-5.1.1-4.fc22.x86_64 libstdc++-5.1.1-4.fc22.x86_64
Clang is not emitting debug information for std::string because it was
told that libstdc++ provides it (but in your case, it's not
installed); this is a debug size optimization that GCC apparently
doesn't perform.
Does this work if you install the debug information for libstdc++?
I've installed debug info for libstdc++ with command dnf debuginfo-install libstdc++-6.2.1-2.fc25.x86_64 and that resolved the issue.
clang trusts that debugging symbols for libstd++ are available, so you have to install them. See ks1322's answer for how to do that on Fedora. On Ubuntu, run:
sudo apt-get install libstdc++6-dbgsym
After that, things will just work.
Do not define _GLIBCXX_DEBUG since that'll break libstdc++'s abi.
-fno-limit-debug-info will make clang emit debug info that's larger than necessary, so I'd advise against that too. Just install the debug info package for libstdc++.
for me:
-fno-limit-debug-info is the real solution for clang / clion.
_GLIBCXX_DEBUG cause link error with some library
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
CLion 2022.1.3
Build #CL-221.5921.27, built on June 21, 2022
Related
I'm compiling a c file in xv6 and I used their Makefile to compile. I used readelf and found out the ELF it outputs has just one program header.
ryan#ubuntu:~/Documents/xv6-OS-for-arm-v8-fixed/xv6-armv8/usr$ readelf -l _init --wide
Elf file type is EXEC (Executable file)
Entry point 0x0
There is 1 program header, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000078 0x0000000000000000 0x0000000000000000 0x0011a8 0x0011c0 RWE 0x8
Section to Segment mapping:
Segment Sections...
00 .text .rodata .data .bss
This program header has just 4 sections: .text .rodata .data .bss
I checked its CFLAGS and it's showed below:
CROSSCOMPILE := aarch64-none-elf-
# try linux eabi
# CROSSCOMPILE := arm-linux-gnueabi-
CC = $(CROSSCOMPILE)gcc
AS = $(CROSSCOMPILE)as
LD = $(CROSSCOMPILE)ld
OBJCOPY = $(CROSSCOMPILE)objcopy
OBJDUMP = $(CROSSCOMPILE)objdump
CFLAGS = -march=armv8-a -mtune=cortex-a57 -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -I. -g
LDFLAGS = -L.
ASFLAGS = -march=armv8-a
But I don't know which of these flags make it this way.
I'm build a ARM-based OS. How can I compile one of this ELF in ARM by myself?
Today I met a really interesting problem with my NixOS distro. I just wanted to create a statically compiled OCaml progam and couldn`t do that. Then I tried to do that with an ANSI C canonical toy "hello world!" application:
$> cat mytest.c
#include <stdio.h>
int
main ()
{
puts ("hello world!") ;
}
My distro:
$> uname -a
Linux cat 4.19.36 #1-NixOS SMP Sat Apr 20 07:16:05 UTC 2019 x86_64 GNU/Linux
Compiler:
$> gcc -v
Using built-in specs.
COLLECT_GCC=/nix/store/myq0x6mjbdzxr9fckqn6kgy89kz19nkp-gfortran-7.4.0/bin/gcc
COLLECT_LTO_WRAPPER=/nix/store/myq0x6mjbdzxr9fckqn6kgy89kz19nkp-gfortran-7.4.0/libexec/gcc/x86_64-unknown-linux-gnu/7.4.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with:
Thread model: posix
gcc version 7.4.0 (GCC)
Cannot produce static exec :
$> gcc -static mytest.c -o hello
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
Any ideas?
Usually a "dynamically linked" program hello is generated by gccwithout a problem.
No such issues on Lubuntu. I was advised to try a different distro and test that exec is running on NixOS. I did it - produced an exec with gcc on Lubuntu and started it on NixOS. Therefore I think that the problem is not with gcc but with NixOS.
How does NixOS treat this problem (i.e., generation of statically compiled exec files)?
And, of course, I'm also interested in the results concerning ocamlopt compiler rather then gcc but I think that the problem is common for all compilers (I tried Haskell ghc too by the way with the same results).
brgs
UPDATE: from a discussion on another thread:
1 #Ston17 You may have the .so but not the .a – norok2
2
3 yes - i have .so what the difference? can the presence of .a improve the situation? – Ston17
4
5 Yes. You typically need .a library to have the static linking work correctly – norok2
$> find /nix/store/ -name *libc.a.*
$>
can this be the reason?
UPDATE2: as concerning ocamlopt:
source file
$> cat mytest.ml
print_string "hello world!" ;;
print_newline () ;;
as you can see no special calls to anything. let try to make static exec:
$> ocamlopt -ccopt -static mytest.ml -o ocaml_test
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lm
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -ldl
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
so ld just cannot link to static version of libc. and i cannot find libc.a in the hole system
any suggetions?
here https://vaibhavsagar.com/blog/2018/01/03/static-haskell-nix/ is explained how you could obtain in NixOS statical versions of sys libraries
nix-shell config file:
let
pkgs = import <nixpkgs> {} ;
in pkgs.buildFHSUserEnv {
name = "fhs" ;
targetPkgs = pkgs: with pkgs; [
pkgs.glibc.static
pkgs.zlib.static
pkgs.libffi
pkgs.libtool
pkgs.musl
pkgs.ghc
pkgs.gcc
pkgs.ocaml
] ;
}
after that in nix-shell you start chroot FHS and copy needed sys libs into your folder and close chroot FHS
and after that compile your file staticaly
good with gcc:
$> gcc -static -L/home/.local/lib/ mytest.c -o ansiC_test
$> ldd ansiC_test
not a dynamic executable
not so good but maybe working with ocaml:
ocamlopt -ccopt -static -cclib -L/home/.local/lib mytest.ml -o ocaml_test
ocamlopt -ccopt -static -cclib -L/home/nomad/.local/lib mytest.ml -o ocaml_test
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: /nix/store/j1v6kkxq081q4m4fw7gazaf6rb3vy87p-ocaml-4.06.1/lib/ocaml/libasmrun.a(unix.o): in function `caml_dlopen':
/build/ocaml-4.06.1/asmrun/unix.c:273: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$> ldd ocaml_test
not a dynamic executable
dont work with ghc though :
ghc -static -optl-static -L/home/.local/lib/ mytest.hs -o haskell_test
[1 of 1] Compiling Main ( mytest.hs, mytest.o )
Linking haskell_test ...
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: /nix/store/wfgrz42bpcl1r635dasfk7r236hm83az-ghc-8.6.4/lib/ghc-8.6.4/rts/libHSrts.a(Linker.o): in function `internal_dlopen':
Linker.c:(.text.internal_dlopen+0x7): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lffi
collect2: error: ld returned 1 exit status
`cc' failed in phase `Linker'. (Exit code: 1)
make: *** [makefile:5: haskell] Error 1
ok. ocaml works:
lubuntu#lubuntu:~/Documents$ ./ocaml_hello_nix
hello world!
lubuntu#lubuntu:~/Documents$ readelf -l ocaml_hello_nix
Elf file type is EXEC (Executable file)
Entry point 0x4017a0
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000005d8 0x00000000000005d8 R 0x1000
LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000
0x0000000000107275 0x0000000000107275 R E 0x1000
LOAD 0x0000000000109000 0x0000000000509000 0x0000000000509000
0x00000000000db191 0x00000000000db191 R 0x1000
LOAD 0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
0x0000000000008a18 0x000000000001dfe0 RW 0x1000
NOTE 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x0000000000000020 0x0000000000000020 R 0x4
NOTE 0x0000000000000258 0x0000000000400258 0x0000000000400258
0x0000000000000020 0x0000000000000020 R 0x8
TLS 0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
0x0000000000000020 0x0000000000000060 R 0x8
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
0x0000000000002ec0 0x0000000000002ec0 R 0x1
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .note.gnu.property .rela.plt
01 .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini
02 .rodata .eh_frame .gcc_except_table
03 .tdata .init_array .fini_array .data.rel.ro .got .got.plt .data __libc_subfreeres __libc_IO_vtables __libc_atexit __libc_thread_subfreeres .bss __libc_freeres_ptrs
04 .note.ABI-tag
05 .note.gnu.property
06 .tdata .tbss
07
08 .tdata .init_array .fini_array .data.rel.ro .got
haskell works. the reason was that binary NixOS packet was built without FFI support. i installed ghc from sources and all become fine:
lubuntu#lubuntu:~/Documents$ ./haskell_hello_nix
hello world!
lubuntu#lubuntu:~/Documents$ readelf -l haskell_hello_nix
Elf file type is EXEC (Executable file)
Entry point 0x405d40
There are 6 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000188ba4 0x0000000000188ba4 R E 0x1000
LOAD 0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
0x00000000000104c0 0x000000000001ac98 RW 0x1000
NOTE 0x0000000000000190 0x0000000000400190 0x0000000000400190
0x0000000000000020 0x0000000000000020 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
TLS 0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
0x0000000000000070 0x00000000000000b8 R 0x8
GNU_RELRO 0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
0x0000000000003140 0x0000000000003140 RW 0x20
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .rela.plt .init .plt .text __libc_thread_freeres_fn .fini .rodata .gcc_except_table .eh_frame
01 .tdata .data.rel.ro.local .fini_array .init_array .data.rel.ro .preinit_array .got .got.plt .data .tm_clone_table __libc_IO_vtables __libc_atexit __libc_thread_subfreeres .bss __libc_freeres_ptrs
02 .note.ABI-tag
03
04 .tdata .tbss
05 .tdata .data.rel.ro.local .fini_array .init_array .data.rel.ro .preinit_array .got
good. tnx to all who was concerned. you save my a$$
I have to compile c++ code with g++ 6.4.0 (Homebrew g++-6) to a static lib, which is then wrapped into a C static lib (Homebrew gcc-6) and linked to a clang++ (clang 8.1.0) app on macos sierra. So the picture is:
c++ (gcc) wrapped in c (gcc) linked to clang app.
As a testcase I use shared-lib.cpp:
#include <iostream>
using namespace std;
void foo()
{
cerr << "Hi from the shared lib" << endl;
}
together with shared-lib.h
extern void foo();
and wrapper-lib.c
#include "shared-lib.h"
int wrapper()
{
foo();
return 123;
}
along with wrapper-lib.h
#ifdef __cplusplus
extern "C"
{
#endif
extern int wrapper();
#ifdef __cplusplus
}
#endif
The main.cpp that uses all the libs looks like
#include <iostream>
#include <string>
#include "shared-lib.h"
#include "wrapper-lib.h"
using namespace std;
int main()
{
auto s = "Hello world from main";
cout << s << endl;
foo(); // from c++ lib
int result = wrapper(); // from c wrapper lib
cout << "wrapper returned " << result << endl;
return 0;
}
My test built script is
g++-6 --version
echo -----------------------
echo build shared-lib .o with g++
g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp
echo build a wrapper library in C with gcc
gcc-6 -c -Wall -fpic wrapper-lib.c
echo build static libshared-lib.a
ar rcs libshared-lib.a shared-lib.o
echo build static libwrapper-lib.a
ar rcs libwrapper-lib.a wrapper-lib.o
echo build main with clang
clang++ --version
echo ----------------------
clang++ -v -L/Users/worker -Wall -std=c++11 -stdlib=libstdc++ -lwrapper-lib -lshared-lib main.cpp -o main
echo start the app
./main
If I only call the gcc c++ function foo() then everything works fine.
If I call the C wrapper function wrapper(), then clang comes up with:
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_wrapper in libwrapper-lib.a(wrapper-lib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Maybe someone can simply spot, what's wrong with my workflow?
Note, for completeness the whole build script output
Note2, since ar in the gcc#6 toolchain does not work (liblto_plugin.so missing) I use clang's ar tool...
mac-mini:~ worker$ ./build-test.sh
g++-6 (Homebrew GCC 6.4.0) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-----------------------
build shared-lib .o with g++
build a wrapper library in C with gcc
build static libshared-lib.a
build static libwrapper-lib.a
build main with clang
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
----------------------
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
clang: warning: libstdc++ is deprecated; move to libc++ [-Wdeprecated]
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu penryn -target-linker-version 278.4 -v -dwarf-column-info -debugger-tuning=lldb -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0 -stdlib=libstdc++ -Wall -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /Users/worker -ferror-limit 19 -fmessage-length 166 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extended-block-signature -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/18/m18t0kxx03d7__31kg3wrsr40000gq/T/main-337db7.o -x c++ main.cpp
clang -cc1 version 8.1.0 (clang-802.0.41) default target x86_64-apple-darwin16.7.0
ignoring nonexistent directory "/usr/include/c++/4.2.1/i686-apple-darwin10/x86_64"
ignoring nonexistent directory "/usr/include/c++/4.0.0"
ignoring nonexistent directory "/usr/include/c++/4.0.0/i686-apple-darwin8/"
ignoring nonexistent directory "/usr/include/c++/4.0.0/backward"
#include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/4.2.1
/usr/include/c++/4.2.1/backward
/usr/local/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
/usr/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)
End of search list.
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -macosx_version_min 10.12.0 -o main -L/Users/worker -lwrapper-lib -lshared-lib /var/folders/18/m18t0kxx03d7__31kg3wrsr40000gq/T/main-337db7.o -lstdc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_wrapper in libwrapper-lib.a(wrapper-lib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
You compile shared-lib.cpp with:
g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp
And you compile wrapper-lib.c with:
gcc-6 -c -Wall -fpic wrapper-lib.c
Have a look at the symbol table of shared-lib.o. It's something like:
$ readelf -s shared-lib.o
Symbol table '.symtab' contains 24 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS shared-lib.cpp
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 1 OBJECT LOCAL DEFAULT 5 _ZStL19piecewise_construc
7: 0000000000000000 1 OBJECT LOCAL DEFAULT 4 _ZStL8__ioinit
8: 0000000000000032 73 FUNC LOCAL DEFAULT 1 _Z41__static_initializati
9: 000000000000007b 21 FUNC LOCAL DEFAULT 1 _GLOBAL__sub_I_shared_lib
10: 0000000000000000 0 SECTION LOCAL DEFAULT 6
11: 0000000000000000 0 SECTION LOCAL DEFAULT 9
12: 0000000000000000 0 SECTION LOCAL DEFAULT 10
13: 0000000000000000 0 SECTION LOCAL DEFAULT 8
14: 0000000000000000 50 FUNC GLOBAL DEFAULT 1 _Z3foov
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
16: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4cerr
17: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE
18: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait
19: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E
20: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev
21: 0000000000000000 0 NOTYPE GLOBAL HIDDEN UND __dso_handle
22: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev
23: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __cxa_atexit
(I'm working on Ubuntu, not OS X.)
Note that there is only one global function defined in this object file and
its name is _Z3foov.
That's the mangled name of the C++ function called foo in shared-lib.cpp. That's
the name the linker sees.
Now the symbol table of wrapper-lib.o:
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS wrapper-lib.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 5
8: 0000000000000000 21 FUNC GLOBAL DEFAULT 1 wrapper
9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND foo
This object file makes an undefined reference to foo, because wrapper-lib.c
is a C source file and you compiled it as such. C does not mangle names. No definition
of foo is provided by any object file in your linkage, so it fails with that
symbol unresolved.
To avoid this and accomplish your linkage, you can direct the C++ compiler
not to mangle the name foo, when compiling shared-lib.cpp. You do so like:
shared-lib.cpp
#include <iostream>
using namespace std;
extern "C" {
void foo()
{
cerr << "Hi from the shared lib" << endl;
}
} //extern "C"
Enclosing the definition of foo in extern "C" {...} has no effect on
C++ compilation except the one you want: the symbol foo will be emitted
as a C symbol; not mangled.
Having done that, you must of course follow suit in shared-lib.h:
shared-lib.h
#ifndef SHARED_LIB_H
#define SHARED_LIB_H
#ifdef __cplusplus
extern "C" {
#endif
void foo();
#ifdef __cplusplus
}
#endif
#endif
With those corrections, let's try again:
$ g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp
and check the symbol table:
$ readelf -s shared-lib.o | grep foo
14: 0000000000000000 50 FUNC GLOBAL DEFAULT 1 foo
Now the one global function defined is foo, not _Z3foov, and your
linkage will succeed.
If you want to write a C++ library that exports a C++ API and not a C API to
the linker, then you cannot call its API from C except by discovering the
mangled names of the API (with readelf, nm, objdump) and explicitly
calling those mangled names from C. Thus without those extern "C" fixes,
your linkage would also succeed with:
wrapper-lib.c
extern void _Z3foov(void);
int wrapper()
{
_Z3foov();
return 123;
}
Suppose I have the following source file:
// file.c:
void f() {}
void g() {}
I compile it into object file using gcc -ffunction-sections:
$ gcc -c -ffunction-sections file.c -o file.o
# It now has at least two sections: `.text.f' (with `f'), `.text.g' (with `g').
Then I try to remove section .text.g (with g) from object file:
$ objcopy --remove-section .text.g file.o
objcopy: stQOLAU8: symbol `.text.g' required but not present
objcopy:stQOLAU8: No symbols
So, is there way to remove function-specific section from object file (compiled with -ffunction-sections)?
Extra info:
Full list of symbols in file.o is:
$ objdump -t file.o
file.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 file.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .text.f 0000000000000000 .text.f
0000000000000000 l d .text.g 0000000000000000 .text.g
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g F .text.f 0000000000000007 f
0000000000000000 g F .text.g 0000000000000007 g
My goal is to eliminate some sections from object file similarly to what ld --gc-sections does.
Or is there some theoretical reason why such task is absolutely out of the scope of objcopy and can only be performed with ld -r?
I have a really perplexing problem in GCC.
I get the following error:
gcc -Wall -Werror -L/Users/red_angel/chorebox_sys/lib -o products/chbc2c -lchorebox ofiles/main.o
Undefined symbols for architecture x86_64:
"_chbclib_flushout", referenced from:
_main in main.o
"_chorebox_argc", referenced from:
_chorebox_command_line in libchorebox.a(chorebox_command_line.o)
"_chorebox_argv", referenced from:
_chorebox_command_line in libchorebox.a(chorebox_command_line.o)
"_chorebox_env", referenced from:
_chorebox_command_line in libchorebox.a(chorebox_command_line.o)
"_mn_command_options", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [products/chbc2c] Error 1
What's wrong with this error? I have confirmed that the _chorebox_argc symbol is indeed present in "libchorebox.a".
I confirmed it by running the command:
nm /Users/red_angel/chorebox_sys/lib/libchorebox.a | cat -n | chodo -_chorebox_argc flip
As the "chodo" command is an command I wrote that you may not be familiar - I will explain what it does. It reads from Standard Input, and forward to Standard Output every line that matches the search pattern. In this case (to make a long story short) it outputs every line containing the "_chorebox_argc" string.
I get the following output:
3 0000000000000004 C _chorebox_argc
55 U _chorebox_argc
To get a closer look at the relevant part of the file, I type the same command, only this time omitting the "chodo" command at the end of the piped series of commands --- and hereby will copy/paste to you the relevant part of that file:
1
2 /Users/red_angel/chorebox_sys/lib/libchorebox.a(vars.o):
3 0000000000000004 C _chorebox_argc
4 0000000000000008 C _chorebox_argv
5 0000000000000008 C _chorebox_env
6
7 /Users/red_angel/chorebox_sys/lib/libchorebox.a(chorebox_mlc.o):
8 00000000000000c8 s EH_frame0
9 0000000000000075 s L_.str
10 U ___stderrp
11 U _chorebox_argv
12 0000000000000000 T _chorebox_mlc
13 00000000000000e0 S _chorebox_mlc.eh
14 U _exit
15 U _fflush
16 U _fprintf
17 U _malloc
18
19 /Users/red_angel/chorebox_sys/lib/libchorebox.a(chorebox_apend_string.o):
20 0000000000000078 s EH_frame0
21 0000000000000000 T _chorebox_apend_string
22 0000000000000090 S _chorebox_apend_string.eh
23 U _chorebox_join_string
24 U _free
25
Needless to say ---- the symbol is definitely present in the "libchorebox.a" file ----- so why is the GCC linker complaining that it is not found?
After some discussion in chat, we discovered that the problem lay in 'common' definitions. A simplified version of the code causing trouble follows. The system is Mac OS X (Mavericks and Yosemite).
With common definitions only
vars.h
extern int chorebox_argc;
extern char **chorebox_argv;
extern char **chorebox_envp;
vars.c
#include "vars.h"
int chorebox_argc;
char **chorebox_argv;
char **chorebox_envp;
main.c
#include "vars.h"
int main(int argc, char **argv, char **envp)
{
chorebox_argc = argc;
chorebox_argv = argv;
chorebox_envp = envp;
return argc;
}
Compilation 1
$ gcc -c vars.c
$ nm vars.o
0000000000000004 C _chorebox_argc
0000000000000008 C _chorebox_argv
0000000000000008 C _chorebox_envp
$ ar rv libvars.a vars.o
ar: creating archive libvars.a
a - vars.o
$ ranlib libvars.a
warning: ranlib: warning for library: libvars.a the table of contents is
empty (no object file members in the library define global symbols)
$ gcc -c main.c
$ gcc -o program main.o vars.o
$ gcc -o program main.o -L. -lvars
Undefined symbols for architecture x86_64:
"_chorebox_argc", referenced from:
_main in main.o
"_chorebox_argv", referenced from:
_main in main.o
"_chorebox_envp", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
$
Note the C in the output from nm. That indicates a 'common' definition of the variables. It isn't enough, on its own, to make them into variable definitions — witness the message from ranlib.
I'm not sure if this is new behaviour in Mac OS X or not. However, it seems that having a source file that only defines uninitialized variables isn't sufficient when the variables are defined in a library, though it is sufficient when the object file is linked directly.
With variable definitions
vardefs.c
#include "vars.h"
int chorebox_argc = 0;
char **chorebox_argv = 0;
char **chorebox_envp = 0;
This has explicitly initialized versions of the variables. The initializer values are the same as the default values, but the explicit initialization makes all the difference.
Compilation 2
$ rm libvars.a
$ gcc -c vardefs.c
$ ar rv libvars.a vardefs.o
ar: creating archive libvars.a
a - vardefs.o
$ gcc -o program main.o -L. -lvars
$
The explicitly initialized variables are picked up from the library without problem.
With one variable definition
vars.h
extern int chorebox_argc;
extern char **chorebox_argv;
extern char **chorebox_envp;
extern int make_believe;
vars.c
#include "vars.h"
int chorebox_argc;
char **chorebox_argv;
char **chorebox_envp;
int make_believe = 59;
main.c
#include "vars.h"
int main(int argc, char **argv, char **envp)
{
chorebox_argc = argc;
chorebox_argv = argv;
chorebox_envp = envp;
make_believe = 1;
return argc;
}
Compilation 3
$ gcc -c vars.c
$ ar rv libvars.a vars.o
ar: creating archive libvars.a
a - vars.o
$ nm vars.o
0000000000000004 C _chorebox_argc
0000000000000008 C _chorebox_argv
0000000000000008 C _chorebox_envp
0000000000000000 D _make_believe
$ gcc -c main.c
$ gcc -o program main.o -L. -lvars
$
Note that adding the initialized make_believe is sufficient to pull the object file from the library, and the common definitions for the other variables are then sufficient to satisfy the linker.
Lessons
Although the linking order was part of the problem, it was not the whole problem.
Providing uninitialized global variables in a library doesn't always work, especially if there are no other definitions in the same source file.
As I noted in the chat, it is generally not a good idea to provide direct access to global variables. It would be better to provide functional interfaces to access (get and set) the variables.
Put the -l option after the file that needs it (ofiles/main.o)
See this question for more information on link order.