diff mbox

[v2,1/2] compiler-gcc.h: add gnu_inline to all inline declarations

Message ID 20180605170532.170361-2-ndesaulniers@google.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nick Desaulniers June 5, 2018, 5:05 p.m. UTC
Functions marked extern inline do not emit an externally visible
function when the gnu89 C standard is used. Some KBUILD Makefiles
overwrite KBUILD_CFLAGS. This is an issue for GCC 5.1+ users as without
an explicit C standard specified, the default is gnu11. Since c99, the
semantics of extern inline have changed such that an externally visible
function is always emitted. This can lead to multiple definition errors
of extern inline functions at link time of compilation units whose build
files have removed an explicit C standard compiler flag for users of GCC
5.1+ or Clang.

Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
---
 include/linux/compiler-gcc.h | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

Comments

Joe Perches June 5, 2018, 5:23 p.m. UTC | #1
On Tue, 2018-06-05 at 10:05 -0700, Nick Desaulniers wrote:
> Functions marked extern inline do not emit an externally visible
> function when the gnu89 C standard is used. Some KBUILD Makefiles
> overwrite KBUILD_CFLAGS. This is an issue for GCC 5.1+ users as without
> an explicit C standard specified, the default is gnu11. Since c99, the
> semantics of extern inline have changed such that an externally visible
> function is always emitted. This can lead to multiple definition errors
> of extern inline functions at link time of compilation units whose build
> files have removed an explicit C standard compiler flag for users of GCC
> 5.1+ or Clang.
[]
> diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
[]
> @@ -72,17 +72,24 @@
>   * -Wunused-function.  This turns out to avoid the need for complex #ifdef
>   * directives.  Suppress the warning in clang as well by using "unused"
>   * function attribute, which is redundant but not harmful for gcc.
> + * Prefer gnu_inline, so that extern inline functions do not emit an
> + * externally visible function. This makes extern inline behave as per gnu89
> + * semantics rather than c99. This prevents multiple symbol definition errors
> + * of extern inline functions at link time.
>   */
>  #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||		\
>      !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
> -#define inline inline		__attribute__((always_inline,unused)) notrace
> -#define __inline__ __inline__	__attribute__((always_inline,unused)) notrace
> -#define __inline __inline	__attribute__((always_inline,unused)) notrace
> +#define inline \
> +	inline __attribute__((always_inline, unused, gnu_inline)) notrace
> +#define __inline__ \
> +	__inline__ __attribute__((always_inline, unused, gnu_inline)) notrace
> +#define __inline \
> +	__inline __attribute__((always_inline, unused, gnu_inline)) notrace

Perhaps these are simpler as

#define __inline__	inline
#define __inline	inline

>  #else
>  /* A lot of inline functions can cause havoc with function tracing */
> -#define inline inline		__attribute__((unused)) notrace
> -#define __inline__ __inline__	__attribute__((unused)) notrace
> -#define __inline __inline	__attribute__((unused)) notrace
> +#define inline inline		__attribute__((unused, gnu_inline)) notrace
> +#define __inline__ __inline__	__attribute__((unused, gnu_inline)) notrace
> +#define __inline __inline	__attribute__((unused, gnu_inline)) notrace
>  #endif

And only set once along with:

>  #define __always_inline	inline __attribute__((always_inline))

And perhaps this __always_inline should be updated
with gnu_inline as well

--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nick Desaulniers June 5, 2018, 5:55 p.m. UTC | #2
On Tue, Jun 5, 2018 at 10:23 AM Joe Perches <joe@perches.com> wrote:
> On Tue, 2018-06-05 at 10:05 -0700, Nick Desaulniers wrote:
> >  #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||             \
> >      !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
> > -#define inline inline                __attribute__((always_inline,unused)) notrace
> > -#define __inline__ __inline__        __attribute__((always_inline,unused)) notrace
> > -#define __inline __inline    __attribute__((always_inline,unused)) notrace
> > +#define inline \
> > +     inline __attribute__((always_inline, unused, gnu_inline)) notrace
> > +#define __inline__ \
> > +     __inline__ __attribute__((always_inline, unused, gnu_inline)) notrace
> > +#define __inline \
> > +     __inline __attribute__((always_inline, unused, gnu_inline)) notrace
>
> Perhaps these are simpler as
>
> #define __inline__      inline
> #define __inline        inline
>
> >  #else
> >  /* A lot of inline functions can cause havoc with function tracing */
> > -#define inline inline                __attribute__((unused)) notrace
> > -#define __inline__ __inline__        __attribute__((unused)) notrace
> > -#define __inline __inline    __attribute__((unused)) notrace
> > +#define inline inline                __attribute__((unused, gnu_inline)) notrace
> > +#define __inline__ __inline__        __attribute__((unused, gnu_inline)) notrace
> > +#define __inline __inline    __attribute__((unused, gnu_inline)) notrace
> >  #endif
>
> And only set once along with:
>
> >  #define __always_inline      inline __attribute__((always_inline))
>
> And perhaps this __always_inline should be updated
> with gnu_inline as well
>

Great idea, I'll pick this up and add you to the Suggested-by: tag in
v3. Thanks Joe!
Nick Desaulniers June 7, 2018, 5:26 p.m. UTC | #3
On Tue, Jun 5, 2018 at 10:23 AM Joe Perches <joe@perches.com> wrote:
>
> On Tue, 2018-06-05 at 10:05 -0700, Nick Desaulniers wrote:
> > Functions marked extern inline do not emit an externally visible
> > function when the gnu89 C standard is used. Some KBUILD Makefiles
> > overwrite KBUILD_CFLAGS. This is an issue for GCC 5.1+ users as without
> > an explicit C standard specified, the default is gnu11. Since c99, the
> > semantics of extern inline have changed such that an externally visible
> > function is always emitted. This can lead to multiple definition errors
> > of extern inline functions at link time of compilation units whose build
> > files have removed an explicit C standard compiler flag for users of GCC
> > 5.1+ or Clang.
> []
> > diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
> []
> > @@ -72,17 +72,24 @@
> >   * -Wunused-function.  This turns out to avoid the need for complex #ifdef
> >   * directives.  Suppress the warning in clang as well by using "unused"
> >   * function attribute, which is redundant but not harmful for gcc.
> > + * Prefer gnu_inline, so that extern inline functions do not emit an
> > + * externally visible function. This makes extern inline behave as per gnu89
> > + * semantics rather than c99. This prevents multiple symbol definition errors
> > + * of extern inline functions at link time.
> >   */
> >  #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||             \
> >      !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
> > -#define inline inline                __attribute__((always_inline,unused)) notrace
> > -#define __inline__ __inline__        __attribute__((always_inline,unused)) notrace
> > -#define __inline __inline    __attribute__((always_inline,unused)) notrace
> > +#define inline \
> > +     inline __attribute__((always_inline, unused, gnu_inline)) notrace
> > +#define __inline__ \
> > +     __inline__ __attribute__((always_inline, unused, gnu_inline)) notrace
> > +#define __inline \
> > +     __inline __attribute__((always_inline, unused, gnu_inline)) notrace
>
> Perhaps these are simpler as
>
> #define __inline__      inline
> #define __inline        inline

Working on this now, going to push v3 soon.  I was wondering more
about these definitions of inline.

Probably want:

#define __inline__ __inline__ inline
#define __inline __inline inline

These are the only references I found to:

__inline__: https://gcc.gnu.org/onlinedocs/gcc/Inline.html
__inline: http://www.keil.com/support/man/docs/armcc/armcc_chr1359124967692.htm

The commit that introduced them was:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a1365647022eb05a5993f270a78e9bef3bf554eb
which was an interesting read.

I get the feeling that the use of __inline__ or __inline (vs inline)
in the kernel may be wrong and their use should be eradicated in the
follow up patch set, but it would be cool if others have additional
insight.

This code in Clang seems to treat them all as the same:
https://github.com/llvm-mirror/clang/blob/1a597eeed3579b4320b62ff55150195482545992/lib/Lex/PPDirectives.cpp#L2285
Nick Desaulniers June 7, 2018, 5:29 p.m. UTC | #4
On Thu, Jun 7, 2018 at 10:26 AM Nick Desaulniers
<ndesaulniers@google.com> wrote:
>
> On Tue, Jun 5, 2018 at 10:23 AM Joe Perches <joe@perches.com> wrote:
> >
> > On Tue, 2018-06-05 at 10:05 -0700, Nick Desaulniers wrote:
> > > Functions marked extern inline do not emit an externally visible
> > > function when the gnu89 C standard is used. Some KBUILD Makefiles
> > > overwrite KBUILD_CFLAGS. This is an issue for GCC 5.1+ users as without
> > > an explicit C standard specified, the default is gnu11. Since c99, the
> > > semantics of extern inline have changed such that an externally visible
> > > function is always emitted. This can lead to multiple definition errors
> > > of extern inline functions at link time of compilation units whose build
> > > files have removed an explicit C standard compiler flag for users of GCC
> > > 5.1+ or Clang.
> > []
> > > diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
> > []
> > > @@ -72,17 +72,24 @@
> > >   * -Wunused-function.  This turns out to avoid the need for complex #ifdef
> > >   * directives.  Suppress the warning in clang as well by using "unused"
> > >   * function attribute, which is redundant but not harmful for gcc.
> > > + * Prefer gnu_inline, so that extern inline functions do not emit an
> > > + * externally visible function. This makes extern inline behave as per gnu89
> > > + * semantics rather than c99. This prevents multiple symbol definition errors
> > > + * of extern inline functions at link time.
> > >   */
> > >  #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||             \
> > >      !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
> > > -#define inline inline                __attribute__((always_inline,unused)) notrace
> > > -#define __inline__ __inline__        __attribute__((always_inline,unused)) notrace
> > > -#define __inline __inline    __attribute__((always_inline,unused)) notrace
> > > +#define inline \
> > > +     inline __attribute__((always_inline, unused, gnu_inline)) notrace
> > > +#define __inline__ \
> > > +     __inline__ __attribute__((always_inline, unused, gnu_inline)) notrace
> > > +#define __inline \
> > > +     __inline __attribute__((always_inline, unused, gnu_inline)) notrace
> >
> > Perhaps these are simpler as
> >
> > #define __inline__      inline
> > #define __inline        inline
>
> Probably want:
>
> #define __inline__ __inline__ inline
> #define __inline __inline inline

Oh, never mind, if my changes to `inline` add the `inline` keyword,
then we can remove the redefinition __inline__ and __inline.  All that
to say your original suggestion is better than my follow up.
Nick Desaulniers June 7, 2018, 5:33 p.m. UTC | #5
On Tue, Jun 5, 2018 at 10:23 AM Joe Perches <joe@perches.com> wrote:
>
> On Tue, 2018-06-05 at 10:05 -0700, Nick Desaulniers wrote:
> And only set once along with:
>
> >  #define __always_inline      inline __attribute__((always_inline))
>
> And perhaps this __always_inline should be updated
> with gnu_inline as well
>

This should pick up the additional attributes from adding `inline` to
the redefinition.

Attributes can be combined via:

__attribute__((a)) __attribute__((b))

or

__attribute__((a, b))
diff mbox

Patch

diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index b4bf73f5e38f..7827bdf0e5e9 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -72,17 +72,24 @@ 
  * -Wunused-function.  This turns out to avoid the need for complex #ifdef
  * directives.  Suppress the warning in clang as well by using "unused"
  * function attribute, which is redundant but not harmful for gcc.
+ * Prefer gnu_inline, so that extern inline functions do not emit an
+ * externally visible function. This makes extern inline behave as per gnu89
+ * semantics rather than c99. This prevents multiple symbol definition errors
+ * of extern inline functions at link time.
  */
 #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||		\
     !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
-#define inline inline		__attribute__((always_inline,unused)) notrace
-#define __inline__ __inline__	__attribute__((always_inline,unused)) notrace
-#define __inline __inline	__attribute__((always_inline,unused)) notrace
+#define inline \
+	inline __attribute__((always_inline, unused, gnu_inline)) notrace
+#define __inline__ \
+	__inline__ __attribute__((always_inline, unused, gnu_inline)) notrace
+#define __inline \
+	__inline __attribute__((always_inline, unused, gnu_inline)) notrace
 #else
 /* A lot of inline functions can cause havoc with function tracing */
-#define inline inline		__attribute__((unused)) notrace
-#define __inline__ __inline__	__attribute__((unused)) notrace
-#define __inline __inline	__attribute__((unused)) notrace
+#define inline inline		__attribute__((unused, gnu_inline)) notrace
+#define __inline__ __inline__	__attribute__((unused, gnu_inline)) notrace
+#define __inline __inline	__attribute__((unused, gnu_inline)) notrace
 #endif
 
 #define __always_inline	inline __attribute__((always_inline))