I am trying to decrease the binary size by overriding default __terminate_handler. Normally, when compiling with GCC, this piece of code:
[[noreturn]] void terminate() noexcept
{
while (true)
;
}
namespace __cxxabiv1
{
std::terminate_handler __terminate_handler = terminate;
}
Makes the default __terminate_handler overridden and the binary size decreases by 30-50 kB, depending on the release/debug build type.
When compiling with Clang I use -nostdlib linker flag, thus I have to link the standard libraries explicitly, by putting -lstdc++ -lgcc as the command line options. This means that I get an error:
ld.lld: error: duplicate symbol: __cxxabiv1::__terminate_handler
-> defined in armgnutoolchain-src/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libstdc++.a(eh_term_handler.o)
-> defined in custom_terminate.cpp.obj
Both, custom code and libstdc++ define __cxxabiv1::__terminate_handler (_ZN10__cxxabiv119__terminate_handlerE) as a symbol initialized in data section. Ideally, I would like the symbol to be defined weak in the libstdc++.
Is there a way to ignore the symbol defined in libstdc++?
Related
I have a shared library that is linked with another (third-party) shared library. My shared library is then loaded using dlopen in my application. All this works fine (assuming files are in the proper path etc).
Now, the problem is that I don't even need to specify to link against the third-party shared library when I link my library. GCC accept it without reporting errors about undefined references. So, the question; how can I force GCC to notify me about undefined references?
If I change my library to be (temporarily) an executable, I get undefined references (when not supplying the library to the linker). (Works fine if I specify it.)
I.e., the following is done:
g++ -fPIC -shared -o libb.so b.o
g++ -fPIC -shared -o liba.so a.o
g++ -o a.exe a.cpp
Where the second line does NOT give out an error and the third line complains about an undefined reference.
Sample code:
a.h:
class a
{
public:
void foobar();
};
a.cpp:
#include "a.h"
#include "b.h"
void a::foobar()
{
b myB;
myB.foobar();
}
int main()
{
a myA; myA.foobar();
}
b.h:
class b
{
public:
void foobar();
};
b.cpp:
#include "b.h"
void b::foobar()
{
}
-Wl,--no-undefined linker option can be used when building shared library, undefined symbols will be shown as linker errors.
g++ -shared -Wl,-soname,libmylib.so.5 -Wl,--no-undefined \
-o libmylib.so.1.1 mylib.o -lthirdpartylib
After more research, I realized what way the stuff works. There are two linker options to manipulate undefined symbols of shared libraries:
First one is --no-undefined. It reports the unresolved symbols that are not resolved immediately, at linking stage. Unless the symbol is found in a shared library linked against, either manually (with -l switch) or automatically (libgcc_s, C++ runtime; libc, C runtime; ld-linux-**.so, dynamic linker utils) picked, --no-undefined reports it as error. That's the key the questioner needed.
There is another key, --no-allow-shlib-undefined (whose description also suggests --no-undefined). It checks if definitions in the shared libraries which you link your shared library against are satisfied. This key is of little use in the case shown in this topic, but it can be useful. However, It has its own obstacles.
The manpage provides some rationale about why it's not default:
--allow-shlib-undefined
--no-allow-shlib-undefined
Allows (the default) or disallows undefined symbols in shared
libraries (It is meant, in shared libraries _linked_against_, not the
one we're creating!--Pavel Shved). This switch is similar to --no-un-
defined except that it determines the behaviour when the undefined
symbols are in a shared library rather than a regular object file. It
does not affect how undefined symbols in regular object files are
handled.
The reason that --allow-shlib-undefined is the default is that the
shared library being specified at link time may not be the same as
the one that is available at load time, so the symbols might actually
be resolvable at load time. Plus there are some systems, (eg BeOS)
where undefined symbols in shared libraries is normal. (The kernel
patches them at load time to select which function is most appropri-
ate for the current architecture. This is used for example to dynam-
ically select an appropriate memset function). Apparently it is also
normal for HPPA shared libraries to have undefined symbols.
The thing is that what is said above is also true, for example, for Linux systems, where some of the internal routines of the shared library is implemented in ld-linux.so, the dynamic loader (it's both executable and shared library). Unless you somehow link it, you will get something like this:
/lib64/libc.so.6: undefined reference to `_dl_argv#GLIBC_PRIVATE'
/lib64/libc.so.6: undefined reference to `_rtld_global_ro#GLIBC_PRIVATE'
/usr/lib64/gcc/x86_64-suse-linux/4.3/libstdc++.so: undefined reference to `__tls_get_addr#GLIBC_2.3'
/lib64/libc.so.6: undefined reference to `_rtld_global#GLIBC_PRIVATE'
/lib64/libc.so.6: undefined reference to `__libc_enable_secure#GLIBC_PRIVATE'
These are undefined references from the loader, ld-linux.so. It is platform-specific (for example, on my system the correct loader is /lib64/ld-linux-x86-64.so). You may link the loader with your library and check even the tricky references shown above:
g++ -fPIC -shared -o liba.so a.o -Wl,--no-allow-shlib-undefined /lib64/ld-linux-x86-64.so.2
I am trying to re-compile an existing C++ application.
Unfortunately, I must rely on a proprietary library I only have a pre-compiled static archive of.
I use g++ version 7.3.0 and ld version 2.30.
Whatever GCC version it was compiled with, it is ancient.
The header file defines the method:
class foo {
int bar(int & i);
}
As nm lib.a shows, the library archive contains the corresponding exported function:
T bar__4fooRi
nm app.o shows my recent compiler employing a different kind of name mangling:
U _ZN4foo9barERi
Hence the linker cannot resolve the symbols provided by the library.
Is there any option to chose the name mangling algorithm?
Can I introduce a map or define the mangled names explicitly?
#Botje's suggestion lead me to writing a linker script like this (the spaces in the PROVIDE stanza are significant):
EXTERN(bar__4fooRi);
PROVIDE(_ZN4foo9barERi = bar__4fooRi);
As far as I understood, this will regard bar__4fooRi as an externally defined symbol (which it is). If _ZN4foo9barERi is searched for, but not defined, bar__4fooRi will take its place.
I am calling the linker from the GNU toolchain like this (mind the order – the script needs to be after the dependant object but before the defining library):
g++ -o application application.o script.ld -lfoo
It looks like this could work.
At least in theory.
The linker now regards other parts of the library, which in turn depends on other unresolvable symbols including (but not limited to) __throw, __cp_pop_exception, and __builtin_delete. I have no idea where these functions are defined nowadays. Joxean Koret shows some locations in this blog post based on guesswork (__builtin_new probably is malloc) – but I am not that confident.
These findings lead me to the conclusion that the library relies on a different style of exception handling and probably memory management, too.
EDIT: The result may be purely academical due to ABI changes as pointed out by #eukaryota, a linker script can indeed be used to "alias" symbols. Here is a complete minimal example:
foo.h:
class Foo {
public:
int bar(int);
};
foo.cpp:
#include "foo.h"
int Foo::bar(int i) {
return i+21;
}
main.cpp:
class Foo {
public:
int baa(int); // use in-place "header" to simulate different name mangling algorithm
};
int main(int, char**) {
Foo f;
return f.baa(21);
}
script.ld:
EXTERN(_ZN3Foo3barEi);
PROVIDE(_ZN3Foo3baaEi = _ZN3Foo3barEi); /* declare "alias" */
Build process:
g++ -o libfoo.o -c foo.c
ar rvs libfoo.a libfoo.o # simulate building a library
g++ -o app main.o -L. script.ld -lfoo
app is compiled, can be executed and returns expected result.
I have a simple proof case file, which is called main.c
void bar(void);
void foo(void)
{
bar();
}
int main(void)
{
return 0;
}
As you can see there is no definition for bar()
My goal is to compile this on windows using cygwin's gcc.
I have figured out that I could use the following linker option:
--unresolved-symbols=ignore-all
This should tell the linker not to care about missing symbols. In the main.c example the missing symbol would not even be an issue, as foo is never called, therefore there should not be an undefined behavior when the program is executed.
I have 2 flavors of gcc, one for embedded ARM targets, and one from cygwin 64bit for windows.
The embedded ARM gcc is from here: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm , version 4_9-2015q3.
The Cygwin gcc is taken from https://cygwin.com 's 64bit installer, version 7.3.0-1
I use these compile options with the compilers:
arm-none-eabi-g++.exe -Wl,--unresolved-symbols=ignore-all main.c
g++.exe -Wl,--unresolved-symbols=ignore-all main.c
The first compiles and links without errors, as for the second I get this error message:
/cygdrive/c/Users/user/AppData/Local/Temp/ccRF8tf5.o:main.c:(.text+0x9): undefined reference to `bar()'
/cygdrive/c/Users/user/AppData/Local/Temp/ccRF8tf5.o:main.c:(.text+0x9): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `bar()'
collect2: error: ld returned 1 exit status
Where clearly the undefined reference to `bar()' message should have been suppressed by the option -Wl,--unresolved-symbols=ignore-all
(The second error message does not appear, if I use gcc from the 32 bit cygwin installer.)
The --help command for the cygwin ld shows the --unresolved-symbols=ignore-all as a valid option.
I suppose the cygwin gcc has been compiled in a way, that this option does not work, even though it is not complaining that it can not validate this option.
If for example I use this command:
g++.exe -Wl,--unresolved-symbols=dummy main.c
I get this error message:
/usr/lib/gcc/x86_64-pc-cygwin/7.3.0/../../../../x86_64-pc-cygwin/bin/ld: bad --unresolved-symbols option: dummy
Which for me tells, that --unresolved-symbols is in fact is an accepted command.
My questions would be:
Is there a way to see which commands are truly accepted by gcc
Is there some other way that could work using cygwin's gcc to compile this main.c example?
Compiling gcc for windows from sources with the proper option could maybe get --unresolved-symbols to work?
My motivation for this whole thing is that I want to unit test a single function from big files, that have multiple functions. Like in the following example:
#include "foobar.h"
int foo(void)
{
return 0;
}
void bar(void)
{
foobar();
}
The declaration of foobar() is in the foobar.h and the definition is in another file called foobar.c
If I wanted to run a unit test, which just links against the symbol foo() I would still get a linker error because of the missing symbol for foobar(). (linking against foobar.o would lead me to link to the complete chain of dependencies, which I want to avoid)
If this --unresolved-symbols option would work, then I would not need to mock or stub the foobar() function in my unit test.
I do understand that there are tools that can create automatically mocks, nevertheless I would like to get this to work.
Thanks for reading through.
I'm building a shared library that has respective code and compilation rules like the following:
// x.C
struct {
short len;
char s[32700];
} foo;
// u.C
extern struct {
short len;
char s[32700];
} foo;
void blah(void)
{
foo.s[0] = 0 ;
}
$CXX -c x.C -fPIC
$CXX -c u.C -fPIC
$CXX -shared -o x.so.1 -Wl,-soname,x.so.1 x.o u.o
This code compiles and links with the intel (v13-v16) compiler and the clang compiler (v3.6), but with the g++ (version 4.9.2) I get the link error:
u.o: relocation R_X86_64_PC32 against undefined symbol `foo' can not be used when making a shared object; recompile with -fPIC
The link error here about -fPIC is clearly wrong, since the code is compiled with fPIC. I also see a relocation record for the symbol in objdump -x output:
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000006 R_X86_64_PC32 foo-0x0000000000000003
Both the clang and gcc compilers produce warnings that guide correction of the code that allows it to link (at least this standalone version, the actual code will be harder to figure out where and how to fix) :
u.C:5:10: warning: anonymous type with no linkage used to declare variable '<anonymous struct> foo' with linkage
} foo;
^
and sure enough I can fix this by removing the anonymous structures:
// u.h
struct fooT {
short len;
char s[32700];
} ;
extern fooT foo ;
// u.C
#include "u.h"
void blah(void)
{
foo.s[0] = 0 ;
}
// x.C
#include "u.h"
struct fooT foo ;
So, while I have a fix, I'd like to understand what's going on here. I see some questions that have similar link errors:
shared library relocation R_X86_64_PC32 error
linker error "relocation R_X86_64_PC32 against undefined symbol" despite compilation with -fPIC
Odd linker issue "relocation R_X86_64_32 against" - not a typical -fPIC issue
linking a static(.a) library with a shared (.so) library, getting error "relocation R_X86_64_32S against a local symbol; recompile with -fPIC"
A couple of these indicate that this might be related to symbol visibility. Is gcc marking this symbol hidden triggering the eventual link error? Which one of the g++, clang++ or intel compilers is behaving properly or improperly here, or is this construct invalid and just plain unportable? If this is invalid code, what part of the C++ standard is it violating?
I'm reading section 3.5 and, assuming I read everything correctly, your non-typedef unnamed class has no linkage and as such cannot be referred to as extern.
Let's just review really quick:
Paragraphs one and two are definitions and preamble.
/3 has various reasons that it would be internal linkage. None of them seem to apply (static, const/constexpr, anonymous union).
/4 is all related to unnamed namespaces
/5 class scope and typedef scope things that don't apply.
/6 Block scope items that don't apply.
/7 More block scope items.
/8 Ah here we go Names not covered by these rules have no linkage....
So it looks to me like the linker is just getting confused because you're trying to extern refer to something with no linkage. While the error message seems bad/poorly worded it does seem fine for it to emit an error.
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 10 years ago.
I'm still fairly new to C++, so I apologize in advance if this is has a simple answer. I'm trying to use an overloaded operator. Here's the signature for that operator:
const Vector3D operator/(const Vector3D& lhs, const double rhs)
And here's the method where I'm trying to use it:
OrthonormalBasis::OrthonormalBasis(const Vector3D &a)
{
Vector3D t;
w = a / a.length();
t = getCollinearVector(w);
//More code goes here
}
When I try to compile, g++ comes back with the following error:
/file/path/orthonormalBasis.cpp:8: undefined reference to
`operator/(Vector3D const&, double)'
collect2: ld returned 1 exit status
The operator is defined in Vector3D.cpp, so I do have a definition.
What you are seeing is a linker error. Linking is a stage of creating an executable that happens after compiling. The job of the linker is to take all references to symbols and resolve them into references to their definitions.
This means that as input to the linker, you have to provide all the symbol definitions. Some of those will come from libraries, and some from .cpp files. Unfortunately, the linker cannot actually parse C++. It expects the compiler to have done that. The compiler than produces a .o file. That .o file contains the results of interpreting symbol definitions and producing stuff the CPU can execute directly. That's the kind of definition the linker needs.
Typically compiling a non-trivial program (i.e. one with multiple .cpp files) into an executable involves creating a bunch of .o files with the compiler, and then linking them together into an executable.
In your case, your symbol is defined in Vector3D.cpp and it is used in orthonormalBasis.cpp. I can also tell from the error that you're using g++ on a Unix platform of some kind. At a minimum the compile and link steps will look like this:
g++ -c Vector3D.cpp
g++ -c orthoNormalBasis.cpp
g++ Vector3D.o orthoNormalBasis.o
I'm betting you're just doing this:
g++ orthoNormalBasis.cpp
This is shorthand for:
g++ -c orthoNormalBasis.cpp
g++ orthoNormalBasis.o
As you can see, this completely misses even trying to compile Vector3D.cpp much less trying to link the resulting .o file into your executable. That's why you're getting that error.
It's mostly that you've only declared the overloaded operator/, not defined it, and so the linker is not able to link the function's definition.