Skip to content

Commit

Permalink
GCC plugin infrastructure
Browse files Browse the repository at this point in the history
This patch allows to build the whole kernel with GCC plugins. It was ported from
grsecurity/PaX. The infrastructure supports building out-of-tree modules and
building in a separate directory. Cross-compilation is supported too.
Currently the x86, arm, arm64 and uml architectures enable plugins.

The directory of the gcc plugins is scripts/gcc-plugins. You can use a file or a directory
there. The plugins compile with these options:
 * -fno-rtti: gcc is compiled with this option so the plugins must use it too
 * -fno-exceptions: this is inherited from gcc too
 * -fasynchronous-unwind-tables: this is inherited from gcc too
 * -ggdb: it is useful for debugging a plugin (better backtrace on internal
    errors)
 * -Wno-narrowing: to suppress warnings from gcc headers (ipa-utils.h)
 * -Wno-unused-variable: to suppress warnings from gcc headers (gcc_version
    variable, plugin-version.h)

The infrastructure introduces a new Makefile target called gcc-plugins. It
supports all gcc versions from 4.5 to 6.0. The scripts/gcc-plugin.sh script
chooses the proper host compiler (gcc-4.7 can be built by either gcc or g++).
This script also checks the availability of the included headers in
scripts/gcc-plugins/gcc-common.h.

The gcc-common.h header contains frequently included headers for GCC plugins
and it has a compatibility layer for the supported gcc versions.

The gcc-generate-*-pass.h headers automatically generate the registration
structures for GIMPLE, SIMPLE_IPA, IPA and RTL passes.

Note that 'make clean' keeps the *.so files (only the distclean or mrproper
targets clean all) because they are needed for out-of-tree modules.

Based on work created by the PaX Team.

Signed-off-by: Emese Revfy <[email protected]>
Acked-by: Kees Cook <[email protected]>
Signed-off-by: Michal Marek <[email protected]>
  • Loading branch information
ephox-gcc-plugins authored and Michal Marek committed Jun 7, 2016
1 parent 2440387 commit 6b90bd4
Show file tree
Hide file tree
Showing 22 changed files with 1,872 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ modules.builtin
Module.symvers
*.dwo
*.su
*.c.[012]*.*

#
# Top-level generic files
Expand Down
1 change: 1 addition & 0 deletions Documentation/dontdiff
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*.bc
*.bin
*.bz2
*.c.[012]*.*
*.cis
*.cpio
*.csp
Expand Down
87 changes: 87 additions & 0 deletions Documentation/gcc-plugins.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
GCC plugin infrastructure
=========================


1. Introduction
===============

GCC plugins are loadable modules that provide extra features to the
compiler [1]. They are useful for runtime instrumentation and static analysis.
We can analyse, change and add further code during compilation via
callbacks [2], GIMPLE [3], IPA [4] and RTL passes [5].

The GCC plugin infrastructure of the kernel supports all gcc versions from
4.5 to 6.0, building out-of-tree modules, cross-compilation and building in a
separate directory.
Plugin source files have to be compilable by both a C and a C++ compiler as well
because gcc versions 4.5 and 4.6 are compiled by a C compiler,
gcc-4.7 can be compiled by a C or a C++ compiler,
and versions 4.8+ can only be compiled by a C++ compiler.

Currently the GCC plugin infrastructure supports only the x86, arm and arm64
architectures.

This infrastructure was ported from grsecurity [6] and PaX [7].

--
[1] https://gcc.gnu.org/onlinedocs/gccint/Plugins.html
[2] https://gcc.gnu.org/onlinedocs/gccint/Plugin-API.html#Plugin-API
[3] https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
[4] https://gcc.gnu.org/onlinedocs/gccint/IPA.html
[5] https://gcc.gnu.org/onlinedocs/gccint/RTL.html
[6] https://grsecurity.net/
[7] https://pax.grsecurity.net/


2. Files
========

$(src)/scripts/gcc-plugins
This is the directory of the GCC plugins.

$(src)/scripts/gcc-plugins/gcc-common.h
This is a compatibility header for GCC plugins.
It should be always included instead of individual gcc headers.

$(src)/scripts/gcc-plugin.sh
This script checks the availability of the included headers in
gcc-common.h and chooses the proper host compiler to build the plugins
(gcc-4.7 can be built by either gcc or g++).

$(src)/scripts/gcc-plugins/gcc-generate-gimple-pass.h
$(src)/scripts/gcc-plugins/gcc-generate-ipa-pass.h
$(src)/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
$(src)/scripts/gcc-plugins/gcc-generate-rtl-pass.h
These headers automatically generate the registration structures for
GIMPLE, SIMPLE_IPA, IPA and RTL passes. They support all gcc versions
from 4.5 to 6.0.
They should be preferred to creating the structures by hand.


3. Usage
========

You must install the gcc plugin headers for your gcc version,
e.g., on Ubuntu for gcc-4.9:

apt-get install gcc-4.9-plugin-dev

Enable a GCC plugin based feature in the kernel config:

CONFIG_GCC_PLUGIN_CYC_COMPLEXITY = y

To compile only the plugin(s):

make gcc-plugins

or just run the kernel make and compile the whole kernel with
the cyclomatic complexity GCC plugin.


4. How to add a new GCC plugin
==============================

The GCC plugins are in $(src)/scripts/gcc-plugins/. You can use a file or a directory
here. It must be added to $(src)/scripts/gcc-plugins/Makefile,
$(src)/scripts/Makefile.gcc-plugins and $(src)/arch/Kconfig.
See the cyc_complexity_plugin.c (CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) GCC plugin.
9 changes: 9 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4979,6 +4979,15 @@ L: [email protected]
S: Odd Fixes (e.g., new signatures)
F: drivers/scsi/fdomain.*

GCC PLUGINS
M: Kees Cook <[email protected]>
R: Emese Revfy <[email protected]>
L: [email protected]
S: Maintained
F: scripts/gcc-plugins/
F: scripts/gcc-plugin.sh
F: Documentation/gcc-plugins.txt

GCOV BASED KERNEL PROFILING
M: Peter Oberparleiter <[email protected]>
S: Maintained
Expand Down
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ ifeq ($(KBUILD_EXTMOD),)
# in parallel
PHONY += scripts
scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
asm-generic
asm-generic gcc-plugins
$(Q)$(MAKE) $(build)=$(@)

# Objects we will link into vmlinux / subdirs we need to visit
Expand Down Expand Up @@ -631,6 +631,15 @@ endif
# Tell gcc to never replace conditional load with a non-conditional one
KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)

PHONY += gcc-plugins
gcc-plugins: scripts_basic
ifdef CONFIG_GCC_PLUGINS
$(Q)$(MAKE) $(build)=scripts/gcc-plugins
endif
@:

include scripts/Makefile.gcc-plugins

ifdef CONFIG_READABLE_ASM
# Disable optimizations that make assembler listings hard to read.
# reorder blocks reorders the control in the function
Expand Down Expand Up @@ -1026,7 +1035,7 @@ prepare1: prepare2 $(version_h) include/generated/utsrelease.h \

archprepare: archheaders archscripts prepare1 scripts_basic

prepare0: archprepare
prepare0: archprepare gcc-plugins
$(Q)$(MAKE) $(build)=.

# All the preparing..
Expand Down Expand Up @@ -1507,6 +1516,7 @@ clean: $(clean-dirs)
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*.symtypes' -o -name 'modules.order' \
-o -name modules.builtin -o -name '.tmp_*.o.*' \
-o -name '*.c.[012]*.*' \
-o -name '*.gcno' \) -type f -print | xargs rm -f

# Generate tags for editors
Expand Down
15 changes: 15 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,21 @@ config SECCOMP_FILTER

See Documentation/prctl/seccomp_filter.txt for details.

config HAVE_GCC_PLUGINS
bool
help
An arch should select this symbol if it supports building with
GCC plugins.

menuconfig GCC_PLUGINS
bool "GCC plugins"
depends on HAVE_GCC_PLUGINS
help
GCC plugins are loadable modules that provide extra features to the
compiler. They are useful for runtime instrumentation and static analysis.

See Documentation/gcc-plugins.txt for details.

config HAVE_CC_STACKPROTECTOR
bool
help
Expand Down
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ config ARM
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
select HAVE_GCC_PLUGINS
select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
select HAVE_IDE if PCI || ISA || PCMCIA
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ config ARM64
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_GCC_PLUGINS
select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if PERF_EVENTS
select HAVE_IRQ_TIME_ACCOUNTING
Expand Down
1 change: 1 addition & 0 deletions arch/um/Kconfig.common
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ config UML
select GENERIC_CPU_DEVICES
select GENERIC_IO
select GENERIC_CLOCKEVENTS
select HAVE_GCC_PLUGINS
select TTY # Needed for line.c

config MMU
Expand Down
1 change: 1 addition & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ config X86
select HAVE_FUNCTION_GRAPH_FP_TEST
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
select HAVE_GCC_PLUGINS
select HAVE_GENERIC_DMA_COHERENT if X86_32
select HAVE_HW_BREAKPOINT
select HAVE_IDE
Expand Down
3 changes: 2 additions & 1 deletion arch/x86/entry/vdso/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \
-fno-omit-frame-pointer -foptimize-sibling-calls \
-DDISABLE_BRANCH_PROFILING -DBUILD_VDSO

$(vobjs): KBUILD_CFLAGS += $(CFL)
$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)

#
# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
Expand Down Expand Up @@ -145,6 +145,7 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
Expand Down
2 changes: 1 addition & 1 deletion scripts/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ subdir-$(CONFIG_DTC) += dtc
subdir-$(CONFIG_GDB_SCRIPTS) += gdb

# Let clean descend into subdirs
subdir- += basic kconfig package
subdir- += basic kconfig package gcc-plugins
23 changes: 23 additions & 0 deletions scripts/Makefile.gcc-plugins
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
ifdef CONFIG_GCC_PLUGINS
__PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC))
PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)")

GCC_PLUGINS_CFLAGS := $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y))

export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN

ifeq ($(PLUGINCC),)
ifneq ($(GCC_PLUGINS_CFLAGS),)
ifeq ($(call cc-ifversion, -ge, 0405, y), y)
PLUGINCC := $(shell $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)")
$(warning warning: your gcc installation does not support plugins, perhaps the necessary headers are missing?)
else
$(warning warning: your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least)
endif
endif
endif

KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
GCC_PLUGIN := $(gcc-plugin-y)

endif
51 changes: 51 additions & 0 deletions scripts/gcc-plugin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh
srctree=$(dirname "$0")
gccplugins_dir=$($3 -print-file-name=plugin)
plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
#include "gcc-common.h"
#if BUILDING_GCC_VERSION >= 4008 || defined(ENABLE_BUILD_WITH_CXX)
#warning $2 CXX
#else
#warning $1 CC
#endif
EOF
)

if [ $? -ne 0 ]
then
exit 1
fi

case "$plugincc" in
*"$1 CC"*)
echo "$1"
exit 0
;;

*"$2 CXX"*)
# the c++ compiler needs another test, see below
;;

*)
exit 1
;;
esac

# we need a c++ compiler that supports the designated initializer GNU extension
plugincc=$($2 -c -x c++ -std=gnu++98 - -fsyntax-only -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
#include "gcc-common.h"
class test {
public:
int test;
} test = {
.test = 1
};
EOF
)

if [ $? -eq 0 ]
then
echo "$2"
exit 0
fi
exit 1
20 changes: 20 additions & 0 deletions scripts/gcc-plugins/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
GCC_PLUGINS_DIR := $(shell $(CC) -print-file-name=plugin)

ifeq ($(PLUGINCC),$(HOSTCC))
HOSTLIBS := hostlibs
HOST_EXTRACFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu99 -ggdb
export HOST_EXTRACFLAGS
else
HOSTLIBS := hostcxxlibs
HOST_EXTRACXXFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti
HOST_EXTRACXXFLAGS += -fno-exceptions -fasynchronous-unwind-tables -ggdb
HOST_EXTRACXXFLAGS += -Wno-narrowing -Wno-unused-variable
export HOST_EXTRACXXFLAGS
endif

export GCCPLUGINS_DIR HOSTLIBS

$(HOSTLIBS)-y := $(GCC_PLUGIN)
always := $($(HOSTLIBS)-y)

clean-files += *.so
Loading

0 comments on commit 6b90bd4

Please sign in to comment.