[hjl@gnu-tools-1 hidden]$ cat bar.c extern void foo (void) __attribute__((visibility("hidden"))) ; void bar (void) { foo (); } [hjl@gnu-tools-1 hidden]$ cat foo.c void foo (void) { } [hjl@gnu-tools-1 hidden]$ cat xxx.c extern void bar (void); void xxx (void) { bar (); } [hjl@gnu-tools-1 hidden]$ cat main.c extern void xxx (void); int main (void) { xxx (); return 0; } [hjl@gnu-tools-1 hidden]$ make gcc -O2 -g -c -o main.o main.c gcc -O2 -g -fpic -c -o foo.o foo.c gcc -O2 -g -shared -o libfoo.so foo.o gcc -O2 -g -c -o bar.o bar.c gcc -O2 -g -c -o xxx.o xxx.c ar rc libbar.a bar.o foo.o xxx.o gcc -o main main.o libfoo.so libbar.a -Wl,-R. libbar.a(bar.o): In function `bar': /export/home/hjl/bugs/binutils/hidden/bar.c:6: undefined reference to `foo' /usr/local/bin/ld: main: hidden symbol `foo' isn't defined /usr/local/bin/ld: final link failed: Bad value collect2: error: ld returned 1 exit status Makefile:13: recipe for target 'main' failed make: *** [main] Error 1 [hjl@gnu-tools-1 hidden]$
This behavior is expected. When linker first checks foo.o in libbar.a, foo is defined in libfoo.so. Linker decides not to pull in foo.o. Then linker pulls in xxx.o in libbar.a to resolve reference to xxx, which leads to bar.o in libbar.a pulled in for bar.o and results in turning foo into hidden. Linker won't rescan libbar.a for foo. You should use # gcc -o main main.o libbar.a libfoo.so libbar.a -Wl,-R.