Shared objects (*.so) in Unix-like systems are inefficient because of the symbol interposition: Every access to a global variable inside the .so needs a GOT lookup, and ever
Is there a way to make the linker accept a cross-reference inside a .so without the GOT/PLT lookup?
Yes: attribute((visibility("hidden")))
is exactly the way to do it.
I cannot use attribute((visibility ("hidden"))) because the called function and the caller are compiled in seperate files
You are confused: visibility("hidden")
means that the symbol will not be exported from the shared library, when it is finally linked. But the symbol is global and visible across multiple translation units before that final link.
Proof:
$ cat t1.c
extern int foo() __attribute__((visibility("hidden")));
int main() { return foo(); }
$ cat t2.c
int foo() __attribute__((visibility("hidden")));
int foo() { return 42; }
$ gcc -c -fPIC t1.c t2.c
$ gcc -shared t1.o t2.o -o t.so
$ nm -D t.so | grep foo
$
I tried to make an assembly listing to see what the option -fno-semantic-interposition does. I found out that it makes a reference to a local alias when one function calls another in the same file, but it still uses a PLT when calling a function in another file.
If you read the discussion in gcc-patches, you'll see that the -fno-semantic-interposition
is about allowing inlining of possibly interposable functions, not about the way they are actually called when not inlined.