Skip to content

Commit 6b90bd4

Browse files
ephox-gcc-pluginsMichal Marek
authored andcommitted
GCC plugin infrastructure
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]>
1 parent 2440387 commit 6b90bd4

22 files changed

+1872
-5
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ modules.builtin
3737
Module.symvers
3838
*.dwo
3939
*.su
40+
*.c.[012]*.*
4041

4142
#
4243
# Top-level generic files

Documentation/dontdiff

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*.bc
44
*.bin
55
*.bz2
6+
*.c.[012]*.*
67
*.cis
78
*.cpio
89
*.csp

Documentation/gcc-plugins.txt

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
GCC plugin infrastructure
2+
=========================
3+
4+
5+
1. Introduction
6+
===============
7+
8+
GCC plugins are loadable modules that provide extra features to the
9+
compiler [1]. They are useful for runtime instrumentation and static analysis.
10+
We can analyse, change and add further code during compilation via
11+
callbacks [2], GIMPLE [3], IPA [4] and RTL passes [5].
12+
13+
The GCC plugin infrastructure of the kernel supports all gcc versions from
14+
4.5 to 6.0, building out-of-tree modules, cross-compilation and building in a
15+
separate directory.
16+
Plugin source files have to be compilable by both a C and a C++ compiler as well
17+
because gcc versions 4.5 and 4.6 are compiled by a C compiler,
18+
gcc-4.7 can be compiled by a C or a C++ compiler,
19+
and versions 4.8+ can only be compiled by a C++ compiler.
20+
21+
Currently the GCC plugin infrastructure supports only the x86, arm and arm64
22+
architectures.
23+
24+
This infrastructure was ported from grsecurity [6] and PaX [7].
25+
26+
--
27+
[1] https://gcc.gnu.org/onlinedocs/gccint/Plugins.html
28+
[2] https://gcc.gnu.org/onlinedocs/gccint/Plugin-API.html#Plugin-API
29+
[3] https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
30+
[4] https://gcc.gnu.org/onlinedocs/gccint/IPA.html
31+
[5] https://gcc.gnu.org/onlinedocs/gccint/RTL.html
32+
[6] https://grsecurity.net/
33+
[7] https://pax.grsecurity.net/
34+
35+
36+
2. Files
37+
========
38+
39+
$(src)/scripts/gcc-plugins
40+
This is the directory of the GCC plugins.
41+
42+
$(src)/scripts/gcc-plugins/gcc-common.h
43+
This is a compatibility header for GCC plugins.
44+
It should be always included instead of individual gcc headers.
45+
46+
$(src)/scripts/gcc-plugin.sh
47+
This script checks the availability of the included headers in
48+
gcc-common.h and chooses the proper host compiler to build the plugins
49+
(gcc-4.7 can be built by either gcc or g++).
50+
51+
$(src)/scripts/gcc-plugins/gcc-generate-gimple-pass.h
52+
$(src)/scripts/gcc-plugins/gcc-generate-ipa-pass.h
53+
$(src)/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
54+
$(src)/scripts/gcc-plugins/gcc-generate-rtl-pass.h
55+
These headers automatically generate the registration structures for
56+
GIMPLE, SIMPLE_IPA, IPA and RTL passes. They support all gcc versions
57+
from 4.5 to 6.0.
58+
They should be preferred to creating the structures by hand.
59+
60+
61+
3. Usage
62+
========
63+
64+
You must install the gcc plugin headers for your gcc version,
65+
e.g., on Ubuntu for gcc-4.9:
66+
67+
apt-get install gcc-4.9-plugin-dev
68+
69+
Enable a GCC plugin based feature in the kernel config:
70+
71+
CONFIG_GCC_PLUGIN_CYC_COMPLEXITY = y
72+
73+
To compile only the plugin(s):
74+
75+
make gcc-plugins
76+
77+
or just run the kernel make and compile the whole kernel with
78+
the cyclomatic complexity GCC plugin.
79+
80+
81+
4. How to add a new GCC plugin
82+
==============================
83+
84+
The GCC plugins are in $(src)/scripts/gcc-plugins/. You can use a file or a directory
85+
here. It must be added to $(src)/scripts/gcc-plugins/Makefile,
86+
$(src)/scripts/Makefile.gcc-plugins and $(src)/arch/Kconfig.
87+
See the cyc_complexity_plugin.c (CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) GCC plugin.

MAINTAINERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4979,6 +4979,15 @@ L: [email protected]
49794979
S: Odd Fixes (e.g., new signatures)
49804980
F: drivers/scsi/fdomain.*
49814981

4982+
GCC PLUGINS
4983+
M: Kees Cook <[email protected]>
4984+
R: Emese Revfy <[email protected]>
4985+
4986+
S: Maintained
4987+
F: scripts/gcc-plugins/
4988+
F: scripts/gcc-plugin.sh
4989+
F: Documentation/gcc-plugins.txt
4990+
49824991
GCOV BASED KERNEL PROFILING
49834992
M: Peter Oberparleiter <[email protected]>
49844993
S: Maintained

Makefile

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ ifeq ($(KBUILD_EXTMOD),)
552552
# in parallel
553553
PHONY += scripts
554554
scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
555-
asm-generic
555+
asm-generic gcc-plugins
556556
$(Q)$(MAKE) $(build)=$(@)
557557

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

634+
PHONY += gcc-plugins
635+
gcc-plugins: scripts_basic
636+
ifdef CONFIG_GCC_PLUGINS
637+
$(Q)$(MAKE) $(build)=scripts/gcc-plugins
638+
endif
639+
@:
640+
641+
include scripts/Makefile.gcc-plugins
642+
634643
ifdef CONFIG_READABLE_ASM
635644
# Disable optimizations that make assembler listings hard to read.
636645
# reorder blocks reorders the control in the function
@@ -1026,7 +1035,7 @@ prepare1: prepare2 $(version_h) include/generated/utsrelease.h \
10261035

10271036
archprepare: archheaders archscripts prepare1 scripts_basic
10281037

1029-
prepare0: archprepare
1038+
prepare0: archprepare gcc-plugins
10301039
$(Q)$(MAKE) $(build)=.
10311040

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

15121522
# Generate tags for editors

arch/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,21 @@ config SECCOMP_FILTER
357357

358358
See Documentation/prctl/seccomp_filter.txt for details.
359359

360+
config HAVE_GCC_PLUGINS
361+
bool
362+
help
363+
An arch should select this symbol if it supports building with
364+
GCC plugins.
365+
366+
menuconfig GCC_PLUGINS
367+
bool "GCC plugins"
368+
depends on HAVE_GCC_PLUGINS
369+
help
370+
GCC plugins are loadable modules that provide extra features to the
371+
compiler. They are useful for runtime instrumentation and static analysis.
372+
373+
See Documentation/gcc-plugins.txt for details.
374+
360375
config HAVE_CC_STACKPROTECTOR
361376
bool
362377
help

arch/arm/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ config ARM
5454
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
5555
select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
5656
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
57+
select HAVE_GCC_PLUGINS
5758
select HAVE_GENERIC_DMA_COHERENT
5859
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
5960
select HAVE_IDE if PCI || ISA || PCMCIA

arch/arm64/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ config ARM64
7676
select HAVE_FTRACE_MCOUNT_RECORD
7777
select HAVE_FUNCTION_TRACER
7878
select HAVE_FUNCTION_GRAPH_TRACER
79+
select HAVE_GCC_PLUGINS
7980
select HAVE_GENERIC_DMA_COHERENT
8081
select HAVE_HW_BREAKPOINT if PERF_EVENTS
8182
select HAVE_IRQ_TIME_ACCOUNTING

arch/um/Kconfig.common

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ config UML
99
select GENERIC_CPU_DEVICES
1010
select GENERIC_IO
1111
select GENERIC_CLOCKEVENTS
12+
select HAVE_GCC_PLUGINS
1213
select TTY # Needed for line.c
1314

1415
config MMU

arch/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ config X86
111111
select HAVE_FUNCTION_GRAPH_FP_TEST
112112
select HAVE_FUNCTION_GRAPH_TRACER
113113
select HAVE_FUNCTION_TRACER
114+
select HAVE_GCC_PLUGINS
114115
select HAVE_GENERIC_DMA_COHERENT if X86_32
115116
select HAVE_HW_BREAKPOINT
116117
select HAVE_IDE

arch/x86/entry/vdso/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \
7575
-fno-omit-frame-pointer -foptimize-sibling-calls \
7676
-DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
7777

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

8080
#
8181
# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
@@ -145,6 +145,7 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
145145
KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32))
146146
KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
147147
KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32))
148+
KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32))
148149
KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
149150
KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
150151
KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)

scripts/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ subdir-$(CONFIG_DTC) += dtc
4747
subdir-$(CONFIG_GDB_SCRIPTS) += gdb
4848

4949
# Let clean descend into subdirs
50-
subdir- += basic kconfig package
50+
subdir- += basic kconfig package gcc-plugins

scripts/Makefile.gcc-plugins

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
ifdef CONFIG_GCC_PLUGINS
2+
__PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC))
3+
PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)")
4+
5+
GCC_PLUGINS_CFLAGS := $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y))
6+
7+
export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN
8+
9+
ifeq ($(PLUGINCC),)
10+
ifneq ($(GCC_PLUGINS_CFLAGS),)
11+
ifeq ($(call cc-ifversion, -ge, 0405, y), y)
12+
PLUGINCC := $(shell $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)")
13+
$(warning warning: your gcc installation does not support plugins, perhaps the necessary headers are missing?)
14+
else
15+
$(warning warning: your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least)
16+
endif
17+
endif
18+
endif
19+
20+
KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
21+
GCC_PLUGIN := $(gcc-plugin-y)
22+
23+
endif

scripts/gcc-plugin.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/sh
2+
srctree=$(dirname "$0")
3+
gccplugins_dir=$($3 -print-file-name=plugin)
4+
plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
5+
#include "gcc-common.h"
6+
#if BUILDING_GCC_VERSION >= 4008 || defined(ENABLE_BUILD_WITH_CXX)
7+
#warning $2 CXX
8+
#else
9+
#warning $1 CC
10+
#endif
11+
EOF
12+
)
13+
14+
if [ $? -ne 0 ]
15+
then
16+
exit 1
17+
fi
18+
19+
case "$plugincc" in
20+
*"$1 CC"*)
21+
echo "$1"
22+
exit 0
23+
;;
24+
25+
*"$2 CXX"*)
26+
# the c++ compiler needs another test, see below
27+
;;
28+
29+
*)
30+
exit 1
31+
;;
32+
esac
33+
34+
# we need a c++ compiler that supports the designated initializer GNU extension
35+
plugincc=$($2 -c -x c++ -std=gnu++98 - -fsyntax-only -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
36+
#include "gcc-common.h"
37+
class test {
38+
public:
39+
int test;
40+
} test = {
41+
.test = 1
42+
};
43+
EOF
44+
)
45+
46+
if [ $? -eq 0 ]
47+
then
48+
echo "$2"
49+
exit 0
50+
fi
51+
exit 1

scripts/gcc-plugins/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
GCC_PLUGINS_DIR := $(shell $(CC) -print-file-name=plugin)
2+
3+
ifeq ($(PLUGINCC),$(HOSTCC))
4+
HOSTLIBS := hostlibs
5+
HOST_EXTRACFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu99 -ggdb
6+
export HOST_EXTRACFLAGS
7+
else
8+
HOSTLIBS := hostcxxlibs
9+
HOST_EXTRACXXFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti
10+
HOST_EXTRACXXFLAGS += -fno-exceptions -fasynchronous-unwind-tables -ggdb
11+
HOST_EXTRACXXFLAGS += -Wno-narrowing -Wno-unused-variable
12+
export HOST_EXTRACXXFLAGS
13+
endif
14+
15+
export GCCPLUGINS_DIR HOSTLIBS
16+
17+
$(HOSTLIBS)-y := $(GCC_PLUGIN)
18+
always := $($(HOSTLIBS)-y)
19+
20+
clean-files += *.so

0 commit comments

Comments
 (0)