How to force the linker to resolve weak symbols locally? - c++

Using g++, when two compilation units "a1.o" and "a2.o" both define and use the same weak symbol, the linker will silently resolve to the first occurrence of the symbol wherever it is used. As a result, the behavior of the application will depend on the order of the object files on the linker command line. What can be done to ensure that these symbols are resolved locally to each compilation unit?
For instance, as a minimalist example, if I have the following source files:
a1.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar1() {A a; a.foo();}
a2.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar2() {A a; a.foo();}
main.cpp:
void bar1();
void bar2();
int main()
{
bar1();
bar2();
}
and compile them with:
for i in a1 a2 main ; do g++ -c -o $i.o $i.cpp ; done
The output will depend on the relative position of a1.o and a2.o on the linker command line:
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a1.cpp
g++ -o main main.o a{2,1}.o ; ./main
a2.cpp
a2.cpp
I'd like to get the same result as if using the '-fno-weak' command line option:
for i in a1 a2 main ; do g++ -fno-weak -c -o $i.o $i.cpp ; done
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a2.cpp
but '-fno-weak' seems to lead to other complications. What are the alternatives (besides not inlining and fixing collisions)?
For those wondering what could be a typical use case: when writing mock components it is sometimes convenient to have header-only implementations. Different test fixtures end-up having different mock implementations of the same component type, which becomes an issue when all the fixtures are linked into a single test runner.

You asked:
What are the alternatives (besides not inlining and fixing collisions)?
Use local namespaces or anonymous namespaces.
a1.cpp:
#include <iostream>
namespace A1_namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
using namespace A1_namespace;
void bar1() {A a; a.foo();}
or
#include <iostream>
namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
void bar1() {A a; a.foo();}
Make similar changes to a2.cpp.

Related

Is it necessary to annotate the template specializations of an exported entity with export?

… or is it enough to declare them at the module interface unit?
test.cpp:
module;
#include <iostream>
export module M;
export
template<typename>
class T
{
public:
void foo() const
{ std::cout << "T" << std::endl; }
};
// export <-- NOT exported
template<>
class T<int>
{
public:
void foo() const
{ std::cout << "T<int>" << std::endl; }
};
main.cpp:
import M;
int main()
{
T<int> x;
x.foo();
return 0;
}
Output:
$ rm -f gcm.cache/* && $(HOME)/gcc-master/bin/g++ -O3 -fmodules-ts test.cpp main.cpp -o foo && ./foo
T<int>
$ $(HOME)/gcc-master/bin/g++ --version
g++ (GCC) 11.0.0 20210128 (experimental)
Exporting affects only name lookup and linkage. Neither of those is relevant to any kind of template specialization or instantiation, so they never need exporting.

How to use gcc options --wrap=symbol in class method

This is a simple example that can help me print malloc params value
void *__wrap_malloc(size_t size)
{
printf("My malloc function!\n");
return __real_malloc(size);
}
But I want to use in class method, like that
class A{
public:
void test(int a)
{
printf("%d", a):
}
}
This using type gives an error.
void A::__wrap_test(int a)
{
printf("wrap");
return A::test()
}
Can someone tell me how to use it correctly?
how to use it correctly?
To use at all, you first have to have a symbol. So first move the inline function definition to be non-inline so a symbol may be generated for it. Then you need to find the mangled name of the symbol. So first correct your typos and compile the library to an object file:
// a.hpp
class A {
public:
void test(int a);
};
// a.cpp
#include <stdio.h>
#include "a.hpp"
void A::test(int a) {
printf("%d\n", a);
}
After compilation check the generated mangled symbol name:
$ g++ -c a.cpp && nm a.o
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T _ZN1A4testEi
U printf
So here you can finally get the name of the symbol to wrap: _ZN1A4testEi. Then you can create the wrapped handler.
I am guessing most probably incorrectly that the first argument to a member function will be a pointer to the class - I did no research on the topic and I do not know if this is true. After getting the symbol name, we can write the main program:
// main.cpp
#include "a.hpp"
extern "C" {
void __real__ZN1A4testEi(A *t, int a);
void __wrap__ZN1A4testEi(A *t, int a) {
printf("wrap ");
return __real__ZN1A4testEi(t, a);
}
};
int main() {
A().test(5);
}
and compile&run with:
$ g++ -c -o a.o a.cpp
$ g++ -c -o main.o main.cpp
$ g++ -Wl,--wrap=_ZN1A4testEi a.o main.o -o main.out
$ ./main.out
wrap 5

How to make application symbols visible to a library?

I have an application that loads a library with dlopen, it looks like this:
#include <iostream>
#include <dlfcn.h>
void foo()
{
std::cout << "foo";
}
int main()
{
void* libbar = dlopen("./libbar.so", RTLD_LAZY);
if (!libbar)
{
std::cerr << dlerror() << std::endl;
return 1;
}
void(*bar)() = (void(*)())dlsym(libbar, "bar");
if (!bar)
{
std::cerr << dlerror() << std::endl;
return 1;
}
bar();
dlclose(libbar);
}
And here is libbar:
#include <iostream>
void foo();
extern "C"
void bar()
{
foo();
std::cout << "bar" << std::endl;
}
Output:
./libbar.so: undefined symbol: _Z3foov
Expected output:
foobar
How to make foo visible to libbar?
I'm actually using C++ and the real problem is with undefined symbols from constructors/member functions, but this should be very similar. I'm working on Linux with GCC 4.7.
You should compile and link main.cc with
g++ -rdynamic -Wall main.cc -o prog -ldl
The -rdynamic flag is important at link time.
And you'll better declare extern "C" those functions which you want to pass to dlsym.
See also the Program Library HowTo.

Unique address for constexpr variable

Is it possible to have a unique address allocated for a constexpr variable, i.e. the same for all translation units where the variable is available (usually through a header)? Consider the following example:
// foo.hh
#include <iostream>
constexpr int foo = 42;
// a.cc
#include "foo.hh"
void a(void) { std::cout << "a: " << &foo << std::endl; }
// b.cc
#include "foo.hh"
extern void a(void);
int main(int argc, char** argv) {
a();
std::cout << "b: " << &foo << std::endl;
}
Compiling a.cc and b.cc separately, and linking them together using gcc 4.7, I see two different addresses printed. If I add the keyword extern in the header, I get a linker error duplicate symbol _foo in: a.o and b.o which I find kind of surprising, because I thought that adding extern would more likely cause the compiler to import that symbol from another object instead of exporting it from the current object. But it seems my understanding of how things work was wrong here.
Is there a reasonable way to have a constexpr declared in one header, such that all translation units can use it in their constant expressions, and such that all translation units agree as to the address of that symbol? I would expect some additional code to denote the single translation unit where this symbol actually belongs to, just like with extern and non-extern variables without constexpr.
If you need to take the address of constexpr variable, declare it as a static member variable. It can be used as a constant expression this way (as opposed to using a function returning a const).
foo.h:
#ifndef FOO_H
#define FOO_H
struct Foo {
static constexpr int foo { 42 }; // declaration
};
#endif // FOO_H
foo.cpp:
#include "foo.hpp"
constexpr int Foo::foo; // definition
bar.cpp:
#include "foo.hpp"
const int* foo_addr() {
return &Foo::foo;
}
int foo_val() {
return Foo::foo;
}
main.cpp:
#include <iostream>
#include "foo.hpp"
extern const int* foo_addr();
extern int foo_val();
constexpr int arr[Foo::foo] {}; // foo used as constant expression
int main() {
std::cout << foo_addr() << " = " << foo_val() << std::endl;
std::cout << &Foo::foo << " = " << Foo::foo << std::endl;
}
Output:
$ g++ -std=c++11 foo.cpp bar.cpp main.cpp -o test && ./test
0x400a44 = 42
0x400a44 = 42
C++17 inline variables
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr: How to declare constexpr extern?
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(&notmain_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return &notmain_i;
}
Compile and run:
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
See also: How do inline variables work?
C++ standard on inline variables
The C++ standard guarantees that the addresses will be the same. C++17 N4659 standard draft
10.1.6 "The inline specifier":
6 An inline function or variable with external linkage shall have the same address in all translation units.
cppreference https://en.cppreference.com/w/cpp/language/inline explains that if static is not given, then it has external linkage.
Inline variable implementation
We can observe how it is implemented with:
nm main.o notmain.o
which contains:
main.o:
U _GLOBAL_OFFSET_TABLE_
U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i
notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i
and man nm says about u:
"u" The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process
there is just one symbol with this name and type in use.
so we see that there is a dedicated ELF extension for this.
I think constexpr is meant more for functions whose return value is constant. You can bind a constant variable to the return value of a constexpr function and expose that externally instead. For example:
// constexpr.h
#ifndef __CONSTEXPR_H
#define __CONSTEXPR_H
extern const int foo;
#endif // __CONSTEXPR_H
// constexpr.cpp
#include "constexpr.h"
constexpr int foo_expr()
{
return 42;
}
const int foo = foo_expr();
// unit1.cpp
#include <iostream>
#include "constexpr.h"
void unit1_print_foo()
{
std::cout << &foo << " = " << foo << std::endl;
}
// unit2.cpp
#include <iostream>
#include "constexpr.h"
void unit2_print_foo()
{
std::cout << &foo << " = " << foo << std::endl;
}
// main.cpp
extern void unit1_print_foo();
extern void unit2_print_foo();
int main(int, char**)
{
unit1_print_foo();
unit2_print_foo();
}
My result is:
$ g++-4.7 -std=c++11 constexpr.cpp unit1.cpp unit2.cpp main.cpp -o test && ./test
0x400ae4 = 42
0x400ae4 = 42
However, it should usually be sufficient to make the foo_expr function itself externally visible, and callers would use foo_expr() to get the value instead of treating it like a variable.

Explicit Specialization of non-template member function is not called

...unless something else from the library is called. Here is a minimal example.
test1.cpp
#include <iostream>
void proofOfTwoLinked();
template <class T>
struct Foo
{
void bar(){ std::cout << "normal bar\n"; }
};
struct A{};
struct B{};
struct C{};
struct D{};
template <> void Foo<B>::bar(){ std::cout << "B bar\n"; }
int main()
{
Foo<A> a;
Foo<B> b;
Foo<C> c;
Foo<D> d;
a.bar();
b.bar();
c.bar();
d.bar();
//proofOfTwoLinked();
}
test2.cpp
#include <iostream>
struct C;
template <class T>
struct Foo
{
void bar(){ std::cout << "normal bar\n"; }
};
template <> void Foo<C>::bar(){ std::cout << "C bar\n"; }
void proofOfTwoLinked()
{
std::cout << "Yup, two is linked\n";
}
If I compile the two together, the program works as expected:
$ rm test; rm *.a; rm *.o; g++ -c test1.cpp; g++ -c test2.cpp; g++ -o test test1.o test2.o; ./test
normal bar
B bar
C bar
normal bar
If I compile test2, put it in an archive, and then link the program against that... the specialization for type C is not executed when c.bar() is called:
$ rm test; rm *.a; rm *.o; g++ -c test1.cpp; g++ -c test2.cpp; ar -r test2.a test2.o; g++ -o test test1.o test2.a; ./test
ar: creating test2.a
normal bar
B bar
normal bar
normal bar
But if I uncomment the last function call of test1 (proofOfTwoLinked) and then compile again, the specialization is executed.
$ rm test; rm *.a; rm *.o; g++ -c test1.cpp; g++ -c test2.cpp; ar -r test2.a test2.o; g++ -o test test1.o test2.a; ./test
ar: creating test2.a
normal bar
B bar
C bar
normal bar
Yup, two is linked
This strikes me as weird, and is certainly contrary to my expectation. Is this in fact normal behavior? Perhaps since there already exists some form of every function that is called in main() before the linker searches test2.a it skips the archive. Is there a way to force the linker to "look at the whole archive"?
I'm using gcc 4.6.1 and ar 2.21.53 (in ubuntu).
Using MSVC2010SP1 I get slightly different results:
compiling together as is I don't get "C bar". This is as expected because test1.cpp and test2.cpp are separate compilation units and with no forward declarations of the specializations that the other contains test1.cpp will instantiate its the default "normal bar" and test2.cpp will not instantiate the "C bar" because it can't see anything using it.
when I uncomment proofOfTwoLinked(); i get "Yup, two is linked" which is expected because "proofOfTwoLinked()" is forward declaired. I still don't get "C bar" which is as expected because it is not forward declaired in test1.cpp
When I compile again adding
template <> void Foo<C>::bar();
to test1.cpp I get a linker error because although the test1.cpp compilation unit now knows there is a
template <> void Foo<C>::bar()
out there somewhere, test2.cpp still does not know that anyone is using it.
When I compile again adding
template void Foo<C>::bar();
to test2.cpp everything works and I get "C bar". Note that
template void Foo<C>::bar();
must be BEFORE its definition.
As far as I can tell MSVC is acting correctly and gcc is acting weird in your case. I used http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf section 14.7 as a reference, it might be helpful.