Linker error using gcc and clang together on macos sierra - macos

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;
}

Related

How to compile an ELF which has just one program header?

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?

lldb does not allow to set breakpoint nor list the source file

Having the following assembly source:
# hello_asm.s
# as hello_asm.s -o hello_asm.o
# ld hello_asm.o -e _main -o hello_asm
.section __DATA,__data
str:
.asciz "Hello world!\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $100, %rdx # the size of the value to print
syscall
#
# EXITING
#
movl $0, %ebx
movl $0x2000001, %eax # exit 0
syscall
by compiling and linking with the following instructions:
as sum.s -g -o sum.o
ld -arch x86_64 -e main -L /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/lib -lSystem sum.o -o sum
and by trying to debug it on LLDB, I get the following result:
❯❯❯❯ lldb sum.o ~/D/test
(lldb) target create "sum.o"
Current executable set to '/Users/mbertamini/Downloads/test/sum.o' (x86_64).
(lldb) list
(lldb) b 16
error: No selected frame to use to find the default file.
error: No file supplied and no default file available.
(lldb)
This is the dwarf:
❯❯❯❯ dwarfdump sum.o ~/D/t/summ
sum.o: file format Mach-O 64-bit x86-64
.debug_info contents:
0x00000000: Compile Unit: length = 0x00000094 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000098)
0x0000000b: DW_TAG_compile_unit
DW_AT_stmt_list (0x00000000)
DW_AT_low_pc (0x0000000000000000)
DW_AT_high_pc (0x0000000000000026)
DW_AT_name ("sum.s")
DW_AT_comp_dir ("<filepath>")
DW_AT_producer ("Apple clang version 12.0.0 (clang-1200.0.32.27)")
DW_AT_language (DW_LANG_Mips_Assembler)
0x0000007e: DW_TAG_label
DW_AT_name ("main")
DW_AT_decl_file ("<filepath-file>")
DW_AT_decl_line (10)
DW_AT_low_pc (0x0000000000000000)
DW_AT_prototyped (0x00)
0x00000095: DW_TAG_unspecified_parameters
0x00000096: NULL
0x00000097: NULL
❯❯❯❯ as -v ~/D/t/summ
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: x86_64-apple-darwin20.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1as -triple x86_64-apple-macosx11.0.0 -filetype obj -main-file-name - -target-cpu penryn -fdebug-compilation-dir /Users/mbertamini/Downloads/test/summ -dwarf-debug-producer "Apple clang version 12.0.0 (clang-1200.0.32.27)" -dwarf-version=4 -mrelocation-model pic -o a.out -
what's the problem? How am I supposed to do?
The issue is that the source file for which the debugging info is mapped should be used (sum.s):
$ as sum.s -g -o sum.o
$ ld -arch x86_64 -e _main -macosx_version_min 10.13 -lSystem sum.o -o sum
$ lldb sum
(lldb) target create "sum"
Current executable set to 'sum' (x86_64).
(lldb) b sum.s:16
Breakpoint 1: where = sum`main + 26, address = 0x0000000100000fac
(lldb)
When assembling use the -O0 optimization along the -g Code Generation Option.(This is important only when compiling with clang; this doesn't apply with as)
↳ lldb: resolving breakpoints to locations

Cannot view std::string when compiled with clang

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

GCC linker ignores symbols in a .a library that I have confirmed are present

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.

How to solve bad instruction `vadd.i16 q0,q0,q0' when attempting to check gcc for neon instruction

Checking gcc supports failed for neon instruction vadd.i16 q0,q0,q0
test.c
int main ()
{
__asm__("vadd.i16 q0, q0, q0"); return 0;
}
arm-linux-androideabi-gcc test.c
/tmp/ccfc8m0G.s: Assembler messages:
/tmp/ccfc8m0G.s:24: Error: bad instruction `vadd.i16 q0,q0,q0'
Tried with flags -mcpu=cortex-a8 -mfpu=neon but stil no success
Above code was used to test gcc support for neon instruction.
Actually i am trying to build x264 with NEON support for ARM platformAfter running configure script
x264 config log file contains
Command line options: "--cross-prefix=arm-linux-androideabi-" "--enable-pic" "--extra- cflags=-mcpu=cortex-a8" "--host=arm-linux"
checking whether arm-linux-androideabi-gcc works... yes
checking whether arm-linux-androideabi-gcc supports for( int i = 0; i < 9; i++ ); with -std=gnu99... yes
checking whether arm-linux-androideabi-gcc supports __asm__("rev ip, ip");... yes
checking whether arm-linux-androideabi-gcc supports __asm__("movt r0, #0");... yes
checking whether arm-linux-androideabi-gcc supports __asm__("vadd.i16 q0, q0, q0");... no
arm-linux-androideabi-gcc conftest.c -Wall -I. -I$(SRCPATH) -mcpu=cortex-a8 -std=gnu99 -lm -o conftest
E:\cygwin\tmp\ccVtVI1i.s: Assembler messages:
E:\cygwin\tmp\ccVtVI1i.s:24: Error: bad instruction `vadd.i16 q0,q0,q0'
--------------------------------------------------
Failed program was:
--------------------------------------------------
int main () { __asm__("vadd.i16 q0, q0, q0"); return 0; }
--------------------------------------------------
config.h contains
#define HAVE_MALLOC_H 1
#define HAVE_ARMV6 1
#define HAVE_ARMV6T2 1
#define ARCH_ARM 1
#define SYS_LINUX 1
#define HAVE_VECTOREXT 1
#define fseek fseeko
#define ftell ftello
#define HAVE_GPL 1
#define HAVE_INTERLACED 1
#define HAVE_ALTIVEC 0
#define HAVE_ALTIVEC_H 0
#define HAVE_MMX 0
#define HAVE_NEON 0
#define HAVE_BEOSTHREAD 0
#define HAVE_POSIXTHREAD 0
#define HAVE_WIN32THREAD 0
#define HAVE_THREAD 0
#define HAVE_LOG2F 0
#define HAVE_VISUALIZE 0
#define HAVE_SWSCALE 0
#define HAVE_LAVF 0
#define HAVE_FFMS 0
#define HAVE_GPAC 0
#define HAVE_GF_MALLOC 0
#define HAVE_AVS 0
#define HAVE_CPU_COUNT 0
Running make command build x264 static lib based on above config.h which contains HAVE_NEON 0
**Compiler Version**
arm-linux-androideabi-gcc -v
Using built-in specs.
Target: arm-linux-androideabi
Configured with: /tmp/ndk-digit/src/build/../gcc/gcc-4.4.3/configure --prefix=/usr/local/google/digit/repo/opensource/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows --target=arm-linux-androideabi --host=i586-mingw32msvc --build=x86_64-linux-gnu --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --with-gmp=/tmp/ndk-digit/build/toolchain/temp-install --with-mpfr=/tmp/ndk-digit/build/toolchain/temp-install --disable-libssp --enable-threads --disable-nls --disable-libmudflap --disable
-libgomp --disable-libstdc__-v3 --disable-sjlj-exceptions --disable-shared --disable-tls --with-float=soft --with-fpu=vfp --with-arch=armv5te --enable-target-optspace --enable-initfini-array --disable-nls --prefix=/usr/local/google/digit/repo/opensource/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows --with-sysroot=/usr/local/google/digit/repo/opensource/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/sysroot --with-binutils-version=2.20.1 --with-mpfr-version=2.4.1 --with
-gmp-version=4.2.4 --with-gcc-version=4.4.3 --with-gdb-version=6.6 --with-arch=armv5te --program-transform-name='s,^,arm-linux-androideabi-,'
Thread model: posix
gcc version 4.4.3 (GCC)
Goal is to utilize neon enabled ARM processor to boost x264 encoder performance...
I'm not really sure what it is you want to accomplish. Do you just want to see if gcc can compile neon instructions, or see if the CPU in question supports neon?
In any case:
I cannot get your code to work either. After googling around, it seems that gcc cannot really handle inline neon code very well. Apparantly the -mfpu=neon flag is somehow ignored (if you compile to .s with the -E flag, you will see that .fpu is set to softvfp even if -mfpu=neon was used)
Consider writing a .S or .s file instead. Something like this:
test.s
.cpu cortex-a8
.fpu neon
.text
.align 2
.global f
.type f, %function
f:
vadd.i16 q0, q0, q0
.size f, .-f
For what it's worth this instruction works fine for me with gcc 4.5.1 (CodeSourcery).
Try with these switches:
-mfpu=neon
-mfloat-abi=softfp
-mcpu=cortex-a8
-march=armv7-a
-mthumb

Resources