Reading Visibility in the GNU wiki, it is clear.
Taking this example from C++ Tutorials
// classes example
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
Is it possible to make area() public and set_values(int,int) local as shown in the first link without altering the code?
I wrote my makefile to get the .so
someproj.so : someproj.cpp
g++ --std=c++11 -O3 -fPIC -shared someproj.cpp -o someproj.so
Modified to make all symbols hidden by adding -fvisibility=hidden
someproj.so : someproj.cpp
g++ --std=c++11 -O3 -fvisibility=hidden -fPIC -shared someproj.cpp -o someproj.so
Is it possible to customized which functions are exposed by modifying the compilation command above?
Currently using 4.7.2 version of gcc
Is it possible to customize which functions are exposed by modifying the compilation command above?
No. Compilation option -fvisibility=[default|internal|hidden|protected]
(and note it is not a linkage option) makes the compiler attribute the specified dynamic visibility type to all global symbols
generated in the compilation unit except those that are specifically excluded by having a countervailing __attribute__((visibility(....)))
applied in the source code. Which makes the answer to your other question:
Is it possible to make area() public and set_values(int,int) local as shown in the first link without altering the code?
also No.
How would you change the source code to make Rectangle::area() dynamically
visible while all other global symbols are hidden for dynamic linkage by -fvisibility=hidden?
Here is a walk-through:
Let's start with:
rectangle.cpp (1)
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
and simply compile it to a PIC rectangle.o so:
$ g++ -Wall -c -fPIC rectangle.cpp
Then check the global symbol table:
$ nm -C rectangle.o
0000000000000000 T Rectangle::set_values(int, int)
Note that Rectangle::area isn't there. It's not available for
linkage at all, so the question of its dynamic visibility just does not arise.
That is because it is defined inline in the class definition and never called
in the compilation unit, so gcc need not even compile its definition. It vanishes
from the object file.
Rectangle::set_values, on the other hand, is not defined inline, so the compiler
emits a global symbol and definition.
To make Rectangle::area eligible for some visibility type, we first need to make
it a global symbol by not defining it inline:
rectangle.cpp (2)
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area();
};
int Rectangle::area() {return width*height;}
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
Recompile and again check the global symbol table:
$ g++ -Wall -c -fPIC rectangle.cpp
$ nm -C rectangle.o
000000000000001a T Rectangle::set_values(int, int)
0000000000000000 T Rectangle::area()
Good. Now a global definition of Rectangle::area appears.
Next let's make a shared library librectangle.so from rectangle.o:
$ g++ -o librectangle.so --shared rectangle.o
Here are the Rectangle::* symbols in its global symbol table:
$ nm -C librectangle.so | grep 'Rectangle::'
00000000000005d4 T Rectangle::set_values(int, int)
00000000000005ba T Rectangle::area()
And here are the Rectangle::* symbols in its dynamic symbol table:
$ nm -CD librectangle.so | grep 'Rectangle::'
00000000000005d4 T Rectangle::set_values(int, int)
00000000000005ba T Rectangle::area()
They're the same.
Now let's hide those symbols for dynamic linkage. We need to recompile rectangle.cpp
then relink the shared library:
$ g++ -Wall -c -fPIC -fvisibility=hidden rectangle.cpp
$ g++ -o librectangle.so --shared rectangle.o
Here again are the Rectangle::* symbols now in the global symbol table:
$ nm -C librectangle.so | grep 'Rectangle::'
0000000000000574 t Rectangle::set_values(int, int)
000000000000055a t Rectangle::area()
They're the same as before.
And here are the Rectangle::* symbols now in the dynamic symbol table:
$ nm -CD librectangle.so | grep 'Rectangle::'; echo Done
Done
Now there are none, thanks to -fvisibility=hidden.
Finally, let's make just Rectangle::area dynamically visible, keeping all
the other global symbols dynamically hidden. We need to change the source code
again:
rectangle.cpp (3)
class Rectangle {
int width, height;
public:
void set_values (int,int);
__attribute__((visibility("default"))) int area();
};
int Rectangle::area() {return width*height;}
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
Then recompile and relink:
$ g++ -Wall -c -fPIC -fvisibility=hidden rectangle.cpp
$ g++ -o librectangle.so --shared rectangle.o
The global symbol table still shows:
$ nm -C librectangle.so | grep 'Rectangle::'
00000000000005a4 t Rectangle::set_values(int, int)
000000000000058a T Rectangle::area()
And the dynamic symbol table only shows:
$ nm -CD librectangle.so | grep 'Rectangle::'
000000000000058a T Rectangle::area()
Rectangle::area is now the only symbol that the shared library exposes for
dynamic linkage.
And before you go...
One thing more about:
Is it possible to make area() public and set_values(int,int) local as shown in the first link without altering the code?
Making a symbol hidden for dynamic linkage doesn't make it local. Dynamic visibility (default|internal|hidden|protected)
is an attribute of global symbols only. For linkage purposes, local symbols don't exist. The only ways to
make a symbol local that would otherwise be global are:-
In C or C++ source, qualify its definition with the static keyword
In C++ source, enclose its definition in an anonymous namespace
Then the symbol does not appear in the global, or dynamic, symbol tables.
Related
I have the program which needs v2xmvtest.so. When i try to build it via make i get undefined reference to *
Seems like that function from libssl1.0. (If i install it, it's built fine)
But i do not see the place where these function are used. More than that, when i try ldd v2xmvtest.so it does show only libvssl1.1 dependency.
Summary:
Is there a way to find out where those finctions from libvssl1.0 are used in the program ? (i have source code of the v2xmvtest.so and try to search, but there no any of these)
I need a description why ldd does not show me libssl1.0 dependency, but during linkning it's needed
Thank you!
Libraries are not required to fully define used symbols. For instance you can have lib.cpp:
int foo();
int bar(int x)
{
return x + foo();
}
and it compiles even foo is actually not defined yet:
g++ lib.cpp -shared -o lib.so
Then you can have main.cpp:
#include <iostream>
int bar(int);
int foo()
{
return 10;
}
int main()
{
std::cout << bar(42) << std::endl;
}
which defines foo and compiles successfully with lib.so:
g++ main.cpp lib.so -o main
The foo function in lib.so is expected just to be provided when the application is linked and is not specified where exactly from, even not necessary from a library.
You can check for undefined symbols in a library using nm tool:
nm -C -u lib.so
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U foo()
w __cxa_finalize##GLIBC_2.17
w __gmon_start__
And finally you can force gcc to ensure no undefined symbols are used by the object files by compiling with -Wl,-z,defs linker flag:
g++ lib.cpp -shared -Wl,-z,defs -o lib.so
...
lib.cpp:(.text+0x24): undefined reference to `foo()'
I have a C++ dynamic library (on macOS) that has a templated function with some explicit instantiations that are exported in the public API. Client code only sees the template declaration; they have no idea what goes on inside it and are relying on these instantiations to be available at link time.
For some reason, only some of these explicit instantiations are made visible in the dynamic library.
Here is a simple example:
// libtest.cpp
#define VISIBLE __attribute__((visibility("default")))
template<typename T> T foobar(T arg) {
return arg;
}
template int VISIBLE foobar(int);
template int* VISIBLE foobar(int*);
I would expect both instantiations to be visible, but only the non-pointer one is:
$ clang++ -dynamiclib -O2 -Wall -Wextra -std=c++1z -stdlib=libc++ -fvisibility=hidden -fPIC libtest.cpp -o libtest.dylib
$ nm -gU libtest.dylib | c++filt
0000000000000f90 T int foobar<int>(int)
This test program fails to link because the pointer one is missing:
// client.cpp
template<typename T> T foobar(T); // assume this was in the library header
int main() {
foobar<int>(1);
foobar<int*>(nullptr);
return 0;
}
$ clang++ -O2 -Wall -Wextra -std=c++1z -stdlib=libc++ -L. -ltest client.cpp -o client
Undefined symbols for architecture x86_64:
"int* foobar<int*>(int*)", referenced from:
_main in client-e4fe7d.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
There does seem to be some connection between the types and the visibility. If I change the return type to void, they are all visible (even if the template arguments are still pointers or whatever). Especially bizarre, this exports both:
template auto VISIBLE foobar(int) -> int;
template auto VISIBLE foobar(int*) -> int*;
Is this a bug? Why would apparent syntactic sugar change behavior?
It works if I change the template definition to be visible, but it seems non-ideal because only a few of these instantiations should be exported... and I still want to understand why this is happening, either way.
I am using Apple LLVM version 8.0.0 (clang-800.0.42.1).
Your problem is reproducible on linux:
$ clang++ --version
clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
$ clang++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden \
-fPIC libtest.cpp -o libtest.so
$ nm -C libtest.so | grep foobar
0000000000000620 W int foobar<int>(int)
0000000000000630 t int* foobar<int*>(int*)
The non-pointer overload is weakly global but the pointer overload is
local.
The cause of this is obscured by clang's slack diagnosing of the __attribute__
syntax extension, which after all is a GCC invention. If we compile with
g++ instead we get:
$ g++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
libtest.cpp:9:36: warning: ‘visibility’ attribute ignored on non-class types [-Wattributes]
template int * VISIBLE foobar(int *);
^
Notice that g++ ignores the visibility attribute only in the pointer overload,
and, just like clang - and consistent with that warning - it emits code with:
$ nm -C libtest.so | grep foobar
0000000000000610 W int foobar<int>(int)
0000000000000620 t int* foobar<int*>(int*)
Clearly clang is doing the same thing, but not telling us why.
The difference between the overloads that satisfies g++ with one and
dissatisfies it with the other is the difference between int and int *.
On that basis we'd expect g++ to be satisfied with the change:
template int VISIBLE foobar(int);
//template int * VISIBLE foobar(int *);
template float VISIBLE foobar(float);
And so it is:
$ g++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -C libtest.so | grep foobar
0000000000000650 W float foobar<float>(float)
0000000000000640 W int foobar<int>(int)
And so is clang:
$ clang++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -C libtest.so | grep foobar
0000000000000660 W float foobar<float>(float)
0000000000000650 W int foobar<int>(int)
Both of them will do what you want for overloads with T a non-pointer type, but
not with T a pointer type.
What you face here, however, is not a ban on dynamically visible functions
that return pointers rather than non-pointers. It couldn't have escaped notice if
visibility was as broken as that. It is just a ban on types of the form:
D __attribute__((visibility("...")))
where D is a pointer or reference type, as distinct from types of the form:
E __attribute__((visibility("..."))) *
or:
E __attribute__((visibility("..."))) &
where E is not a pointer or reference type. The distinction is between:
A (pointer or reference that has visibility ...) to type D
and:
A (pointer or reference to type E) that has visibility ...
See:
$ cat demo.cpp
int xx ;
int __attribute__((visibility("default"))) * pvxx; // OK
int * __attribute__((visibility("default"))) vpxx; // Not OK
int __attribute__((visibility("default"))) & rvxx = xx; // OK,
int & __attribute__((visibility("default"))) vrxx = xx; // Not OK
$ g++ -shared -Wall -Wextra -std=c++1z -fvisibility=hidden -o libdemo.so demo.cpp
demo.cpp:3:46: warning: ‘visibility’ attribute ignored on non-class types [-Wattributes]
int * __attribute__((visibility("default"))) vpxx; // Not OK
^
demo.cpp:5:46: warning: ‘visibility’ attribute ignored on non-class types [-Wattributes]
int & __attribute__((visibility("default"))) vrxx = xx; // Not OK
^
$ nm -C libdemo.so | grep xx
0000000000201030 B pvxx
0000000000000620 R rvxx
0000000000201038 b vpxx
0000000000000628 r vrxx
0000000000201028 b xx
The OK declarations become global symbols; the Not OK ones become local,
and only the former are dynamically visible:
nm -CD libdemo.so | grep xx
0000000000201030 B pvxx
0000000000000620 R rvxx
This behaviour is reasonable. We can't expect a compiler to attribute
global, dynamic visibility to a pointer or reference that could point or
refer to something that does not have global or dynamic visibility.
This reasonable behaviour only appears to frustrate your objective because
- as you probably now see:
template int VISIBLE foobar(int);
template int* VISIBLE foobar(int*);
doesn't mean what you thought it did. You thought that, for given type U,
template U VISIBLE foobar(U);
declares a template instantiating function that has default
visibility, accepting an argument of type U and returning the same. In fact,
it declares a template instantiating function that accepts an argument of
type U and returns type:
U __attribute__((visibility("default")))
which is allowed for U = int, but disallowed for U = int *.
To express your intention that instantations of template<typename T> T foobar(T arg)
shall be dynamically visible functions, qualify the type of the template function
itself with the visibility attribute. Per GCC's documentation of the __attribute__
syntax - which admittedly
says nothing specific concerning templates - you must make an attribute
qualification of a function in a declaration other than its definition. So complying
with that, you'd revise your code like:
// libtest.cpp
#define VISIBLE __attribute__((visibility("default")))
template<typename T> T foobar(T arg) VISIBLE;
template<typename T> T foobar(T arg) {
return arg;
}
template int foobar(int);
template int* foobar(int*);
g++ no longer has any gripes:
$ g++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -CD libtest.so | grep foobar
0000000000000640 W int foobar<int>(int)
0000000000000650 W int* foobar<int*>(int*)
and both of the overloads are dynamically visible. The same goes for clang:
$ clang++ -shared -O2 -Wall -Wextra -std=c++1z -fvisibility=hidden -fPIC libtest.cpp -o libtest.so
$ nm -CD libtest.so | grep foobar
0000000000000650 W int foobar<int>(int)
0000000000000660 W int* foobar<int*>(int*)
With any luck, you'll have the same result with clang on Mac OS
I have a header file that declares a template with a static variable and also defines it:
/* my_header.hpp */
#ifndef MY_HEADER_HPP_
#define MY_HEADER_HPP_
#include <cstdio>
template<int n>
struct foo {
static int bar;
static void dump() { printf("%d\n", bar); }
};
template<int n>
int foo<n>::bar;
#endif // MY_HEADER_HPP_
This header is included both by main.cpp and a shared library mylib. In particular, mylib_baz.hpp just includes this template and declares a function that modifies a specialization of the template.
/* mylib_baz.hpp */
#ifndef MYLIB_BAZ_HPP_
#define MYLIB_BAZ_HPP_
#include "my_header.hpp"
typedef foo<123> mylib_foo;
void init_mylib_foo();
#endif // MYLIB_BAZ_HPP_
and
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
When I make mylib.so (containing mylib_baz.o), the symbol for foo<123>::bar is present and declared weak. However, the symbol for foo<123>::bar is declared weak also in my main.o:
/* main.cpp */
#include "my_header.hpp"
#include "mylib_baz.hpp"
int main() {
foo<123>::bar = 456;
foo<123>::dump(); /* outputs 456 */
init_mylib_foo(); /* outputs 123 */
foo<123>::dump(); /* outputs 123 -- is this guaranteed? */
}
It appears that I am violating one definition rule (foo<123>::bar defined both in my_header.cpp and main.cpp). However, both with g++ and clang the symbols are declared weak (or unique), so I am not getting bitten by this -- all accesses to foo<123>::bar modify the same object.
Question 1: Is this a coincidence (maybe ODR works differently for static members of templates?) or am I in fact guaranteed this behavior by the standard?
Question 2: How could I have predicted the behavior I'm observing? That is, what exactly makes the compiler declare symbol weak?
There is no ODR violation. You have one definition of bar. It is here:
template<int n>
int foo<n>::bar; // <==
As bar is static, that indicates that there is one definition across all translation units. Even though bar will show up once in all of your object files (they need a symbol for it, after all), the linker will merge them together to be the one true definition of bar. You can see that:
$ g++ -std=c++11 -c mylib_baz.cpp -o mylib_baz.o
$ g++ -std=c++11 -c main.cpp -o main.o
$ g++ main.o mylib_baz.o -o a.out
Produces:
$ nm mylib_baz.o | c++filt | grep bar
0000000000000000 u foo<123>::bar
$ nm main.o | c++filt | grep bar
0000000000000000 u foo<123>::bar
$ nm a.out | c++filt | grep bar
0000000000601038 u foo<123>::bar
Where u indicates:
"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.
Will this code result in undefined behavior?
header.h
#ifdef __cplusplus
extern "C"
{
#endif
inline int foo(int a)
{
return a * 2;
}
#ifdef __cplusplus
}
#endif
def.c
#include "header.h"
extern inline int foo(int a);
use.c
#include "header.h"
int bar(int a)
{
return foo(a + 3);
}
main.cpp
#include <stdio.h>
#include "header.h"
extern "C"
{
int bar(int a);
}
int main(int argc, char** argv)
{
printf("%d\n", foo(argc));
printf("%d\n", bar(argc));
}
This is a example of a program where an inline function has to be used in both C and C++. Would it work if def.c was removed and foo was not used in C? (This is assuming that the C compiler is C99.)
This code works when compiled with:
gcc -std=c99 -pedantic -Wall -Wextra -c -o def.o def.c
g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp
gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c
g++ -std=c++11 -pedantic -Wall -Wextra -o extern_C_inline def.o main.o use.o
foo is only in extern_C_inline once because the different versions that the compiler outputs in different object files get merged, but I would like to know if this behavior is specified by the standard. If I remove extern definition of foo and make it static then foo will appear in the extern_C_inline multiple times because the compiler outputs it in each compilation unit.
The program is valid as written, but def.c is required to ensure the code always works with all compilers and any combination of optimisation levels for the different files.
Because there is a declaration with extern on it, def.c provides an external definition of the function foo(), which you can confirm with nm:
$ nm def.o
0000000000000000 T foo
That definition will always be present in def.o no matter how that file is compiled.
In use.c there is an inline definition of foo(), but according to 6.7.4 in the C standard it is unspecified whether the call to foo() uses that inline definition or uses an external definition (in practice whether it uses the inline definition depends on whether the file is optimised or not). If the compiler chooses to use the inline definition it will work. If it chooses not to use the inline definition (e.g. because it is compiled without optimisations) then you need an external definition in some other file.
Without optimisation use.o has an undefined reference:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c
$ nm use.o
0000000000000000 T bar
U foo
But with optimisation it doesn't:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c -O3
$ nm use.o
0000000000000000 T bar
In main.cpp there will be a definition of foo() but it will typically generate a weak symbol, so it might not be kept by the linker if another definition is found in another object. If the weak symbol exists, it can satisfy any possible reference in use.o that requires an external definition, but if the compiler inlines foo() in main.o then it might not emit any definition of foo() in main.o, and so the definition in def.o would still be needed to satisfy use.o
Without optimisation main.o contains a weak symbol:
$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp
$ nm main.o
U bar
0000000000000000 W foo
0000000000000000 T main
U printf
However compiling main.cpp with -O3 inlines the call to foo and the compiler does not emit any symbol for it:
$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp -O3
$ nm main.o
U bar
0000000000000000 T main
U printf
So if foo() is not inlined in use.o but is inlined in main.o then you need the external definition in def.o
Would it work if def.c was removed and foo was not used in C?
Yes. If foo is only used in the C++ file then you do not need the external definition of foo in def.o because main.o either contains its own (weak) definition or will inline the function. The definition in foo.o is only needed to satisfy non-inlined calls to foo from other C code.
Aside: the C++ compiler is allowed to skip generating any symbol for foo when optimising main.o because the C++ standard says that a function declared inline in one translation unit must be declared inline in all translation units, and to call a function declared inline the definition must be available in the same file as the call. That means the compiler knows that if some other file wants to call foo() then that other file must contain the definition of foo(), and so when that other file is compiled the compiler will be able to generate another weak symbol definition of the function (or inline it) as needed. So there is no need to output foo in main.o if all the calls in main.o have been inlined.
These are differnet semantics from C, where the inline definition in use.c might be ignored by the compiler, and the external definition in def.o must exist even if nothing in def.c calls it.
Im doing a project that works with ELF files. Right now Im using the following as a sample input -
class C {
public:
C();
C(int x, int y);
int getX();
private:
int x;
int y;
};
class SubC : public C {
int z;
};
int f() {return 0;}
C c;
SubC subC;
int i;
double d;
I then run
gcc test.cpp -g -c -o test.o
and I get test.o as expected. I then feed test.o into a library I found called peter-dwarf. My problem is that the library says "no section .debug_str found in test.o"
Am I doing something wrong during compilation? Or is the library not working?
Edit: should have been a -g in there
Use -g in gcc to generate the debug symbols. You may also refer to the documentation of debugging options of gcc here.
The -g alone might not include DWARF information if your system is configured in some way. There is a number of switches related to DWARF specifically, so if -g alone does not work, you may need to go there and mangle with other switches.
Probably you need to compile with debugging information enabled. Try:
gcc -g test.cpp -c -o test.o