Is there any gcc/g++ linker flag than removes the hidden visibility from symbols of a shared library - linux

I went through this The hidden visibility does get applied in my shared libraries but works for static libraries on linux
and
Is there any way to override the -fvisibility=hidden at link time?
but I have follow up question
File: lib_mylib.h
int fun();
int fun1(void);
int fun2(void);
File: lib_mylib.c
#include <stdio.h>
int fun() {
return 2;
}
int fun1(void) {
return 2;
}
int fun2(void) {
return 2;
}
File: my_lib_shared.c
#include "my_lib.h"
int foo(void) {
return fun() + 4;
}
File: my_lib_shared.h
int foo();
File driver.c
/* filename: driver.c */
#include "my_lib.h"
#include "my_lib_shared.h"
#include <stdio.h>
int main() {
int x = foo() ;
return 0;
}
If I execute following steps
1) `gcc -fPIC -fvisibility=hidden -c my_lib.c -o lib_mylib.o`
2) `gcc -fPIC -fvisibility=hidden -shared -o libMyLibHidden.so lib_mylib.o`
3) `gcc -fPIC -c my_lib_shared.c -o my_lib_shared.o`
4) `gcc -shared -o libMyShared2.so my_lib_shared.o`
5) `gcc -L. -Wall -o test_hidden driver.c -lMyLibHidden -lMyShared2`
the output of objdump is as
objdump -T libMyLibHidden.so
libMyLibHidden.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000448 l d .init 0000000000000000 .init
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses
0000000000000658 g DF .fini 0000000000000000 Base _fini
0000000000000000 w D *UND* 0000000000000000 _deregisterTMCloneTable
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w DF *UND* 0000000000000126 GLIBC_2.2.5 _cxa_finalize
0000000000200938 g D *ABS* 0000000000000000 Base __bss_start
0000000000200948 g D *ABS* 0000000000000000 Base _end
0000000000200938 g D *ABS* 0000000000000000 Base _edata
0000000000000448 g DF .init 0000000000000000 Base _init
I did not any reference of functions of fun, fun1 and fun2 in the above objdump. Which is expected
and I get following error at final linking step
/tmp/ccMsEpFq.o: In function main':
driver.c:(.text+0xe): undefined reference tofun' collect2: error: ld returned 1 exit status
but in my actual code and shared libraries of libQtGui.so i can see in my Makefile -fvisibility=hidden is given as flag but still the symbols are available in my dynamic symbol table of libQtGui.so
=--------------------------------My question
is is there any flag in gcc linux or way where we can override the hidden visibility and make the symbols available in shared libraries
or there any flag in gcc linux where we can export all the symbols in the shared library
The flags of my Makefile while making shared library of libQtGui.so are
CFLAGS = -m64 -pipe -g -O2 -fvisibility=hidden -Wall -W -D_REENTRANT -fPIC $(DEFINES)
CXXFLAGS = -m64 -pipe -fpermissive -g -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -O2 -fvisibility=hidden -fvisibility-inlines-hidden -Wall -W -D_REENTRANT -fPIC $(DEFINES)
INCPATH = -I../../mkspecs/linux-g++-64 -I. -I../../include/QtCore -I../../include/QtCore -I../../include -I../../include/QtGui -I../3rdparty/libpng -I../3rdparty/zlib -I/usr/include/freetype2 -I../3rdparty/harfbuzz/src -Idialogs -I.moc/release-shared -I/usr/X11R6/include -I.uic/release-shared
LINK = g++
LFLAGS = -m64 -Wl,-rpath/shared_libary_path -shared -Wl,-soname,libQtGui.so.4

Just remove the -fvisibility=hidden flag and all functions will be exported.

Related

__attribute__ ((weak)) not work for global variable

pqy#localhost ~/src/test/a $ cat m.c
#include <stdio.h>
int aaaaa __attribute__ ((weak)) =8;
int main(void){
printf("%d\n", aaaaa);
return 0;
}
pqy#localhost ~/src/test/a $ cat lib.c
int aaaaa = 5;
pqy#localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -o m -L. -lb -Wl,-rpath=$PWD;./m
8
Above is my code and test result. I am confused why it does not work as expected.
Also try function, not work ether. Below is the test result.
pqy#localhost ~/src/test/a $ cat lib.c
int fun() {
return 5;
}
pqy#localhost ~/src/test/a $ cat m.c
#include <stdio.h>
__attribute__((weak)) int fun() {
return 8;
}
int main(void){
printf("%d\n", fun());
return 0;
}
pqy#localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -O0 -o m -L. -lb -Wl,-rpath=$PWD;./m
8
pqy#localhost ~/src/test/a $ ldd m
linux-vdso.so.1 (0x00007ffd819ec000)
libb.so => /home/pqy/src/test/a/libb.so (0x00007f7226738000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7226533000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7226744000)
pqy#localhost ~/src/test/a $
At bottom what you have observed here is just the fact that the linker will not
resolve a symbol dynamically if it can resolve it statically. See:
main.c
extern void foo(void);
extern void need_dynamic_foo(void);
extern void need_static_foo(void);
int main(void){
foo();
need_dynamic_foo();
need_static_foo();
return 0;
}
dynamic_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (dynamic)");
}
void need_dynamic_foo(void)
{
puts(__func__);
}
static_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static)");
}
void need_static_foo(void)
{
puts(__func__);
}
Compile the sources so:
$ gcc -Wall -c main.c static_foo.c
$ gcc -Wall -fPIC -c dynamic_foo.c
Make a shared library:
$ gcc -shared -o libfoo.so dynamic_foo.o
And link a program:
$ gcc -o prog main.o static_foo.o libfoo.so -Wl,-rpath=$PWD
It runs like:
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
So foo and need_static_foo were statically resolved to the definitions from static_foo.o and
the definition of foo from libfoo.so was ignored, despite the fact that libfoo.so
was needed and provided the definition of need_dynamic_foo. It makes no difference
if we change the linkage order to:
$ gcc -o prog main.o libfoo.so static_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
It also makes no difference if we replace static_foo.c with:
static_weak_foo.c
#include <stdio.h>
void __attribute__((weak)) foo(void)
{
puts("foo (static weak)");
}
void need_static_foo(void)
{
puts(__func__);
}
Compile that and relink:
$ gcc -Wall -c static_weak_foo.c
$ gcc -o prog main.o libfoo.so static_weak_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static weak)
need_dynamic_foo
need_static_foo
Although the definition of foo in static_weak_foo.c is now declared weak,
the fact that foo can be statically resolved to this definition
still preempts any need to resolve it dynamically.
Now if we write another source file containing another strong definition of
foo:
static_strong_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static strong)");
}
and compile it and link as follows:
$ gcc -Wall -c static_strong_foo.c
$ gcc -o prog main.o static_weak_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
we see:
$ ./prog
foo (static strong)
need_dynamic_foo
need_static_foo
Now, libfoo.so still provides the definition of need_dynamic_foo, because there
is no other; static_weak_foo.o still provides the only definition of need_static_foo,
and the definition of foo in libfoo.so is still ignored because the symbol
can be statically resolved.
But in this case there are two definitions of foo in different files that are
available to resolve it statically: the weak definition in static_weak_foo.o and
the strong definition in static_strong_foo.o. By the linkage rules that you are
familiar with, the strong definition wins.
If both of these statically linked definitions of foo were strong, there would of course be a
multiple definition error, just like:
$ gcc -o prog main.o static_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
static_strong_foo.o: In function `foo':
static_strong_foo.c:(.text+0x0): multiple definition of `foo'
static_foo.o:static_foo.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
in which the dynamic definition in libfoo.so plays no part. So you can
be guided by this practical principle: The rules you are familiar with for arbitrating
between weak and strong definitions of the same symbol in a linkage only apply
to rival definitions which would provoke a multiple definition error in the absence
of the weak attribute.
The symbol is resolved at link stage, during the link stage only the weak symbol aaaaa = 8 is visible.
If the symbol can be resolved in the link stage, it won't generate a relocation entry, then nothing will happen at load stage
There are no aaaaa in the relocation table:
% objdump -R m
m: file format elf64-x86-64
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
0000000000003dc8 R_X86_64_RELATIVE *ABS*+0x0000000000001130
0000000000003dd0 R_X86_64_RELATIVE *ABS*+0x00000000000010f0
0000000000004028 R_X86_64_RELATIVE *ABS*+0x0000000000004028
0000000000003fd8 R_X86_64_GLOB_DAT _ITM_deregisterTMCloneTable
0000000000003fe0 R_X86_64_GLOB_DAT __libc_start_main#GLIBC_2.2.5
0000000000003fe8 R_X86_64_GLOB_DAT __gmon_start__
0000000000003ff0 R_X86_64_GLOB_DAT _ITM_registerTMCloneTable
0000000000003ff8 R_X86_64_GLOB_DAT __cxa_finalize#GLIBC_2.2.5
0000000000004018 R_X86_64_JUMP_SLOT printf#GLIBC_2.2.5
Сompiler or linker builds files from the command line in reverse order. In other words, files with ((weak)) should be located earlier in the command line than dynamic ones.

Why does LuaJIT not print with `-mavx2`?

I am trying to write a Lua binding for a C library with LuaJIT's C ffi, but encountered this problem.
LuaJIT doesn't print the line, but only with -mavx2 flag set.
Here are the steps to reproduce the issue:
Environment
CPU: Intel(R) Core(TM) i5 CPU M 560 # 2.67GHz
OS: Ubuntu 16.04, 64bit
GCC version : gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
LuaJIT version: 2.0.4
Actually I ran this inside the fantastic ZeroBrane Studio (Latest version)
test.c
#include <stdint.h>
uint64_t aux(const uint64_t b)
{
return b & b;
}
void test(uint64_t state)
{
uint64_t b[64];
for (int i = 0; i < 64; i++)
{
b[i] = (state<<1) ^ state;
}
aux(b[0]);
}
Compiling to a shared library
gcc -W -Wall -Winline -g -fPIC -shared -O3 -o libtest.so test.c # without -mavx2
gcc -W -Wall -Winline -g -fPIC -shared -O3 -mavx2 -o libtest.so test.c # with -mavx2
Using the library in LuaJIT
test.lua
local ffi = require("ffi")
local L = ffi.load("./libtest.so")
ffi.cdef[[
void test(uint64_t);
]]
local s = ffi.new("uint64_t", 0);
print("Hello!")
L.test(s)
print("Hello!")
Output
Without -mavx2: hello!\nhello\n, as expected.
With -mavx2: hello!\n

Compile error on cygwin with strerror_r

I am getting a build error using make:
g++ -std=c++11 -DHAVE_CONFIG_H -I. -I../src/config -I. -I./obj -DBOOST_SP_USE_STD_ATOMIC -DBOOST_
AC_USE_STD_ATOMIC -pthread -I/usr/include -I./leveldb/include -I./leveldb/helpers/memenv -I./secp2
56k1/include -I./univalue/include -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS -std=c99 -D_XOPEN_SOURCE=
500 -g -O2 -Wall -Wextra -Wformat -Wvla -Wformat-security -Wno-unused-parameter -MT libbitcoin_co
mmon_a-netbase.o -MD -MP -MF .deps/libbitcoin_common_a-netbase.Tpo -c -o libbitcoin_common_a-netbase
.o `test -f 'netbase.cpp' || echo './'`netbase.cpp
cc1plus: warning: command line option `-std=c99' is valid for C/ObjC but not for C++
In file included from /usr/include/boost/assert.hpp:58:0,
from /usr/include/boost/range/size.hpp:23,
from /usr/include/boost/range/functions.hpp:20,
from /usr/include/boost/range/iterator_range_core.hpp:38,
from /usr/include/boost/range/iterator_range.hpp:13,
from /usr/include/boost/range/as_literal.hpp:22,
from /usr/include/boost/algorithm/string/case_conv.hpp:19,
from netbase.cpp:25:
netbase.cpp: In function `bool LookupIntern(const char*, std::vector<CNetAddr>&, unsigned int, bool)
':
netbase.cpp:95:39: warning: comparison between signed and unsigned integer expressions [-Wsign-compa
re]
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
netbase.cpp:101:39: warning: comparison between signed and unsigned integer expressions [-Wsign-comp
are]
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
netbase.cpp: In function `std::string NetworkErrorString(int)':
netbase.cpp:720:41: error: `strerror_r' was not declared in this scope
if (strerror_r(err, buf, sizeof(buf)))
^
^
Evidently cygwin does support strerror_r as per https://cygwin.com/cygwin-api/compatibility.html#std-susv4
Code snippet where the code is breaking:
#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
s = strerror_r(err, buf, sizeof(buf));
#else /* POSIX variant always returns message in buffer */
s = buf;
if (strerror_r(err, buf, sizeof(buf)))
buf[0] = 0;
#endif
Can someone guide me as to how I can fix this ?
TIA

Find out a function symbol's visibility in an object file (.o)

I only cares about default/hidden visibility.
The .o file is not compiled with IPO.
How to find out a symbol's visibility in the .o file?
Why I have to find it out from .o file:
On certain platform, I ran into a gcov.a which appears problematic.
And I have to figure out where it is wrong.
1. I cannot know how exactly the toolchain is configured and built.
2. As part of libgcc magic, figure it out from source code is extremely difficult.
You can find out the visibility of a symbol in an object file by examining
the file's symbol table with objdump -t. If the symbol is hidden it
will be labelled .hidden in the 6th field of its objdump record, followed
by its name. If its visibility is default there will be no such label and
the 6th field will be the name (the usual case). For example:
foo.c (default visibility)
#include <stdio.h>
void foo(void)
{
puts("foo");
}
Compile and examine:
$ gcc -c -fPIC foo.c
$ objdump -t foo.o | grep foo
foo.o: file format elf64-x86-64
0000000000000000 l df *ABS* 0000000000000000 foo.c
0000000000000000 g F .text 0000000000000013 foo
foo.c (hidden visibility)
#include <stdio.h>
__attribute__ ((visibility ("hidden"))) void foo(void)
{
puts("foo");
}
Recompile and re-examine:
$ gcc -c -fPIC foo.c
$ objdump -t foo.o | grep foo
foo.o: file format elf64-x86-64
0000000000000000 l df *ABS* 0000000000000000 foo.c
0000000000000000 g F .text 0000000000000013 .hidden foo

dylib dynamic library calling a dylib : Undefined symbols for architecture i386

Under mac os x with g++ from gcc-5.2 I am trying to do the following : create a dylib exporting a class defined by header tmp8bis_dylib.h and source tmp8bis_dylib.cpp, and then create another dylib out of a source file tmp8bis.cpp using and linking to the previous dylib. Header and sources are in the same directory. I compile as follows :
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis_dylib.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis_dylib.o -o ./tmp8bis_dylib.dylib
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis.o -o ./tmp8bis.dylib
and get this :
Undefined symbols for architecture i386:
"complex::cmodule(double, double)", referenced from:
_mymodule in tmp8bis.o
"complex::complex(double, double)", referenced from:
_mymodule in tmp8bis.o
"complex::~complex()", referenced from:
_mymodule in tmp8bis.o
ld: symbol(s) not found for architecture i386
collect2: error: ld returned 1 exit status
make: *** [all] Error 1
Obviously, I tried to pass various include and library paths with -I and -L flags respectively, with the very same result... Any idea ?
Files are below :
For tmp8bis_dylib.h :
#ifndef TMP_8_BIS_DYLIB_H
#define TMP_8_BIS_DYLIB_H
class complex
{
public:
double real;
double imag;
public:
complex();
complex(double x);
complex(double x,double y);
double cmodule(double x, double y);
~complex();
};
#endif
For tmp8bis_dylib.cpp :
#include "./tmp8bis_dylib.h"
#include <math.h>
extern "C"
{
complex::complex()
{
real = 0.0 ;
imag = 0.0 ;
}
complex::complex(double x)
{
real = x ;
imag = 0.0 ;
}
complex::complex(double x,double y)
{
real = x ;
imag = y ;
}
double complex::cmodule(double x, double y)
{
double res = sqrt(x*x+y*y);
return res ;
}
complex::~complex()
{
}
}
For tmp8bis.cpp :
#include <math.h>
#include "./tmp8bis_dylib.h"
extern "C"
{
double mymodule(double x, double y)
{
complex z(x,y);
double ret = z.cmodule(x,y);
return ret;
}
}
Precision. -m32 is because I need 32 bits dylib because the final dylib will be plugged into excel 2011's (for mac) VBA, which is 32 bits.
EDIT. Following Brett Hale's comment about Apple's advises about dylibs, I added
#define EXPORT __attribute__((visibility("default")))
after the #include's from tmp8bis.cpp, and EXPORT's for all its member functions, and compiled as follows :
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis_dylib.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis_dylib.o -fvisibility=hidden -o ./tmp8bis_dylib.dylib
did a sudo cp ./tmp8bis_dylib.dylib /opt/lib/libtmp8bis_dylib.dylib and then compiled :
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis.o -o ./tmp8bis.dylib -L/opt/lib
and got the same result as before... Nor did
g++-5.2.0 -m32 -dynamiclib ./tmp8bis.o -o ./tmp8bis.dylib -ltmp8bis_dylib.dylib
make my day.
Without resorting to #define EXPORT __attribute__((visibility("default"))) or any -fvisibility=hidden
g++-5.2.0 -m32 -Wall -fpic -g -c ./tmp8bis_dylib.cpp
g++-5.2.0 -m32 -shared ./tmp8bis_dylib.o -o ./libtmp8bis_dylib.dylib
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis.cpp
g++-5.2.0 -m32 -shared ./tmp8bis.o -o ./tmp8bis.dylib -L. -ltmp8bis_dylib
finally worked. I did not managed to succeed without -fpic, naming libtmp8bis_dylib.dylib and using -ltmp8bis_dylib.

Resources