This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ELF interposition and One Definition Rule

cgraph_function_body_availability determine if body of a given function is
available in current compilation unit and if so, if it may be overwritten by
completely different semantic by (dynamic)linker. Function that is
AVAIL_AVAILABLE can still be repleaced by a function fron different unit, but
its effects must be the same.

Our default behaviour special case inline functions that are always
AVAIL_AVAILABLE and, via decl_replaceable_p, also any COMDAT (that may be for
functions since all COMDATs are also inlines, but makes difference for
variables I think).

In the variable initializer case we also special case DECL_VIRTUAL and assume
that there is only one possible initializer for every virtual variable.

The performance implications of cgraph_function_body_availability are important;
-fPIC costs over 10% of performance but making everything AVAIL_AVAILABLE cuts
the costs well under 1%.

My understanding of C++ One Definition Rule, in a strict sense, does not a
allow in to define two functions of the same name and different semantics in a
valid program . I also think that all DSOs eventually linked together or
dlopenned are part of the same program.  So theoretically, for C++ produced
code, we may go with AVAIL_AVAILABLE everywhere.

After some discussion on mainline list Michael Matz pointed out that one can
understand ODR in a sense that the interposed function was never part of the
program, since it is completely replaced.

On IRC we got into an agreement that we may disallow interposition for
virtuals, since replacing these seems fishy - they don't even have address well
defined and compiler can freely duplicate and/or unify them.  I think same
apply for C++ constructors and destructors now.

Does the following patch seems sane?

If there will be no opposition till end of week, I will go ahead with it.

Of course I would be happier with a stronger rule - for instance allowing
interposition only on plain functions not on methods.

Main benefits of AVAILABLE is inlining, but it also helps to avoid expensive
dynamic relocations. Making virtual functions AVAILABLE will allow us to hide
them fron interaces of shared libraries.  This should turn good part of
non-local dynamic relocations into local dynamic relocations in practice.

Bootstrapped/regtested ppc64-linux.


	* cgraph.c (cgraph_function_body_availability): Also return
	AVAIL_AVAILABLE for virtual functions, constructors and destructors.
Index: cgraph.c
--- cgraph.c	(revision 201996)
+++ cgraph.c	(working copy)
@@ -2035,6 +2052,29 @@ cgraph_function_body_availability (struc
      behaviour on replacing inline function by different body.  */
   else if (DECL_DECLARED_INLINE_P (node->symbol.decl))
     avail = AVAIL_AVAILABLE;
+  /* C++ One Deifnition Rule states that in the entire program, an object or
+     non-inline function cannot have more than one definition; if an object or
+     function is used, it must have exactly one definition. You can declare an
+     object or function that is never used, in which case you don't have to
+     provide a definition. In no event can there be more than one definition.
+     In the interposition done by linking or dynamic linking one function
+     is replaced by another.  Direct interpretation of C++ ODR would imply
+     that both functions must origin from the same definition and thus be
+     semantically equivalent and we should always return AVAIL_AVAILABLE.
+     We however opted to be more conservative and allow interposition
+     for common (noninline) functions and methods based on interpretation
+     of ODR that simply consider the replaced function definition to not
+     be part of the program.
+     We however do allow interposition of virtual functions on the basis that
+     their address is not well defined and compiler is free to duplicate their
+     bodies same way as it does with inline functions.  */
+  else if (DECL_VIRTUAL_P (node->symbol.decl)
+	   || DECL_CXX_CONSTRUCTOR_P (node->symbol.decl)
+	   || DECL_CXX_DESTRUCTOR_P (node->symbol.decl))
+    avail = AVAIL_AVAILABLE;
   /* If the function can be overwritten, return OVERWRITABLE.  Take
      care at least of two notable extensions - the COMDAT functions

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]