5

From https://gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Optimize-Options.html#index-fsemantic-interposition

-fsemantic-interposition

Some object formats, like ELF, allow interposing of symbols by the dynamic linker. This means that for symbols exported from the DSO, the compiler cannot perform interprocedural propagation, inlining and other optimizations in anticipation that the function or variable in question may change. While this feature is useful, for example, to rewrite memory allocation functions by a debugging implementation, it is expensive in the terms of code quality. With -fno-semantic-interposition the compiler assumes that if interposition happens for functions the overwriting function will have precisely the same semantics (and side effects). Similarly if interposition happens for variables, the constructor of the variable will be the same. The flag has no effect for functions explicitly declared inline (where it is never allowed for interposition to change semantics) and for symbols explicitly declared weak.

From https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-visibility-function-attribute

protected

Protected visibility is like default visibility except that it indicates that references within the defining module bind to the definition in that module. That is, the declared entity cannot be overridden by another module.

This sounds exactly the same.

Is there any real difference, other than that -fno-semantic-interposition to change any functions explicitly marked default to protected?

Community
  • 1
  • 1
o11c
  • 15,265
  • 4
  • 50
  • 75
  • Semantic interposition is indeed much less useful if you already use `-fvisibility=hidden` and annotate your function visibilities (see [here](https://stackoverflow.com/a/48521068/2170527) for more details). – yugr Jul 09 '18 at 09:35
  • As a side note, `protected` visibility is usually not recommended as it slows down runtime linking (see excellent post by Ian Lance Taylor [here](https://www.airs.com/blog/archives/307)). – yugr Jul 09 '18 at 09:38
  • @yugr the indirection only happens for the rare case where you need the address, *and* AFAICT it is still no worse than `default`. – o11c Jul 09 '18 at 17:26

2 Answers2

1

This question is difficult to answer because currently, -fsemantic-interposition does not actually work. In this example,

int a;

int
f1 (int a)
{
  return a;
}

int
f2 (void)
{
  return f1 (a) - a;
}

the body of f2 is effectively optimized into return 0; even with -O2 -fsemantic-interposition (and also with -O2 -fno-semantic-interposition, in case the sense of the option is reversed in the documentation). I filed a bug.

The likely intent is that -fsemantic-interposition would disable such optimizations, so that you end up with a call to f1 and an explicit computation of the result.

ELF symbol visibility is not really related to that, mainly because it only applies to dynamic linking. The link editor can still interpose symbols at static link time (using the -z muldefs option, for example), so the compiler should really provide a way to enable interposition without altering symbol properties (so something else beyond __attribute__ ((weak))).

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • Per closing comments on that bug, I added `-fPIC` ... then `-fsemantic-interposition -fvisibility=protected` allows exactly the same optimization as `-fno-semantic-interposition` – o11c Jul 08 '18 at 16:58
  • 1
    `-fsemantic-interposition` only affects code compiled for shared libraries (with `-fPIC`). Functions in executables are not interposable so compiler will optimize them regardless of `-semantic-interposition`. Bug was resolved as invalid for that reason. – yugr Jul 09 '18 at 09:32
0

-fno-semantic-interposition should be about code generation. -fvisibility=protected is about a symbol attribute. protected visibility came before -fsemantic-interposition and, as explained in Ulrich Drepper's How to Write Shared Libraries, it's a visibility attribute you shouldn't use.

The generic ELF ABI defines another visibility mode: protected. In this scheme references to symbols defined in the same object are always satisfied locally. But the symbols are still available outside the DSO. This sounds like an ideal mechanism to optimize DSO by avoiding the use of exported symbols (see section 2.2.7) but it isn’t. Processing references to protected symbols is even more expensive than normal lookup. The problem is a require- ment in the ISO C standard. The standard requires that function pointers, pointing to the same function, can becompared for equality. This rule would be violated with a fast and simple-minded implementation of the protected visibility. Assume an application which references a pro- tected function in a DSO. Also in the DSO is another function which references said function. The pointer in the application points to the PLT entry for the function in the application’s PLT. If a protected symbol lookup would simply return the address of the function inside the DSO the addresses would differ. In programming environments without this requirement on function pointers the use of the protected visibility would be useful and fast. But since there usually is only one implementation of the dynamic linker on the sys- tem and this implementation has to handle C programs as well, the use of protected is highly discouraged.

If you want your library to refer to its own globals without the possibility of interposition (and with greater speed for functions due to PLT avoidance), the preferred way is to define the symbol with a hidden alias and use the hidden alias internally.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • That doesn't explain how `-fno-semantic-interposition` is any different. (nor does it explain how protected visibility is somehow worse than default visibility ... and it ignores the fact that most functions are called directly, not turned into function pointers) – o11c Jul 07 '18 at 23:38
  • `-fno-semantic-interposition` tells the compiler to optimize code as if symbols weren't interposable. `__attribute__((visibility("protected")))` tells the compiler to attach a visibility attribute to the symbol it generates ( the `-fvisibility=*` CLI option specifies a default) which in turn instructs the linker to link the symbol in a specific way. Namely through a PLT for functions if they're visible, IP-relatively if they're hidden, and in some PLT-involving nondescript but expensive way if they're protected. – Petr Skocik Jul 07 '18 at 23:50