4

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 every call from one function to another inside the .so needs a PLT lookup. I was therefore happy to see that gcc version 5.1 has added the option -fno-semantic-interposition. However, when I try to make a .so where one function calls another without using a PLT, I get the error message:

relocation R_X86_64_PC32 against symbol `functionname' can not be used when making a shared object; recompile with -fPIC

I expected the option -fno-semantic-interposition to eliminate this error message, but it doesn't. -mcmodel=large doesn't help either. The reference to the function is indeed position-independent, which the error message actually confirms (R_X86_64_PC32 means PC-relative 32-bit relocation in 64-bit mode). -fPIC does not really mean position-independent, as the name would imply, it actually means use GOT and PLT.

I cannot use __attribute__((visibility ("hidden"))) because the called function and the caller are compiled in seperate files (caller is in C++, called function is in assembly).

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.

(g++ version is 5.2.1 Ubuntu, 64-bit mode).

Is there a way to make the linker accept a cross-reference inside a .so without the GOT/PLT lookup?

Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192
A Fog
  • 4,360
  • 1
  • 30
  • 32
  • Future readers: see also http://stackoverflow.com/questions/10849308/x86-64-is-it-possible-to-in-line-substitute-plt-got-references for trying to avoid the PLT when calling across shared-object boundaries. (e.g. from a program into a library). The best that seems to be possible is replacing indirection through the PLT with an indirect `call` through a pointer from the non-lazy GOT. – Peter Cordes May 31 '16 at 15:32

1 Answers1

6

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.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • As a side note, some other compilers (LLVM) do semantic interposition by default (thus breaking ELF semantics but shining in benchmarks). – yugr Nov 10 '16 at 16:11