diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 003bc26..3497a7c 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -158,14 +158,9 @@ __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
 	@:
 
 # Linus' kernel sanity checking tool
-ifneq ($(KBUILD_CHECKSRC),0)
-  ifeq ($(KBUILD_CHECKSRC),2)
-    quiet_cmd_force_checksrc = CHECK   $<
-          cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
-  else
-      quiet_cmd_checksrc     = CHECK   $<
-            cmd_checksrc     = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
-  endif
+ifeq ($(KBUILD_CHECKSRC),2)
+quiet_cmd_force_checksrc = CHECK   $<
+      cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
 endif
 
 # Do section mismatch analysis for each module/built-in.o
@@ -219,108 +214,28 @@ cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
 $(obj)/%.i: $(src)/%.c FORCE
 	$(call if_changed_dep,cc_i_c)
 
-cmd_gensymtypes =                                                           \
-    $(CPP) -D__GENKSYMS__ $(c_flags) $< |                                   \
-    $(GENKSYMS) $(if $(1), -T $(2))                                         \
-     $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))             \
-     $(if $(KBUILD_PRESERVE),-p)                                            \
-     -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
-
-quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
-cmd_cc_symtypes_c =                                                         \
-    set -e;                                                                 \
-    $(call cmd_gensymtypes,true,$@) >/dev/null;                             \
-    test -s $@ || rm -f $@
-
-$(obj)/%.symtypes : $(src)/%.c FORCE
-	$(call cmd,cc_symtypes_c)
-
-# C (.c) files
-# The C file is compiled and updated dependency information is generated.
-# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
-
-quiet_cmd_cc_o_c = CC $(quiet_modtag)  $@
-
-ifndef CONFIG_MODVERSIONS
-cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
-
-else
-# When module versioning is enabled the following steps are executed:
-# o compile a .tmp_<file>.o from <file>.c
-# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
-#   not export symbols, we just rename .tmp_<file>.o to <file>.o and
-#   are done.
-# o otherwise, we calculate symbol versions using the good old
-#   genksyms on the preprocessed source and postprocess them in a way
-#   that they are usable as a linker script
-# o generate <file>.o from .tmp_<file>.o using the linker to
-#   replace the unresolved symbols __crc_exported_symbol with
-#   the actual value of the checksum generated by genksyms
-
-cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
-cmd_modversions =								\
-	if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then		\
-		$(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes))	\
-		    > $(@D)/.tmp_$(@F:.o=.ver);					\
-										\
-		$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) 			\
-			-T $(@D)/.tmp_$(@F:.o=.ver);				\
-		rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);		\
-	else									\
-		mv -f $(@D)/.tmp_$(@F) $@;					\
-	fi;
-endif
-
-ifdef CONFIG_FTRACE_MCOUNT_RECORD
-ifdef BUILD_C_RECORDMCOUNT
-ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
-  RECORDMCOUNT_FLAGS = -w
-endif
-# Due to recursion, we must skip empty.o.
-# The empty.o file is created in the make process in order to determine
-#  the target endianness and word size. It is made before all other C
-#  files, including recordmcount.
-sub_cmd_record_mcount =					\
-	if [ $(@) != "scripts/mod/empty.o" ]; then	\
-		$(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)";	\
-	fi;
-recordmcount_source := $(srctree)/scripts/recordmcount.c \
-		    $(srctree)/scripts/recordmcount.h
-else
-sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
-	"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
-	"$(if $(CONFIG_64BIT),64,32)" \
-	"$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
-	"$(LD)" "$(NM)" "$(RM)" "$(MV)" \
-	"$(if $(part-of-module),1,0)" "$(@)";
-recordmcount_source := $(srctree)/scripts/recordmcount.pl
-endif
-cmd_record_mcount = 						\
-	if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then	\
-		$(sub_cmd_record_mcount)			\
-	fi;
-endif
-
 define rule_cc_o_c
-	$(call echo-cmd,checksrc) $(cmd_checksrc)			  \
-	$(call echo-cmd,cc_o_c) $(cmd_cc_o_c);				  \
-	$(cmd_modversions)						  \
-	$(call echo-cmd,record_mcount)					  \
-	$(cmd_record_mcount)						  \
-	scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >    \
-	                                              $(dot-target).tmp;  \
-	rm -f $(depfile);						  \
+	$(CONFIG_SHELL) $(srctree)/scripts/kcc.sh			\
+	    $< $@ $(depfile)						\
+	    $(if $(part-of-module),m,b)					\
+	    "$(echo-why)"						\
+	    $(c_flags);							\
+	scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >	\
+	                                           $(dot-target).tmp;	\
+	rm -f $(depfile);						\
 	mv -f $(dot-target).tmp $(dot-target).cmd
 endef
+# cmd_cc_o_c is required by if_changed_rule to detect changes in options
+cmd_cc_o_c = $(CC) $(c_flags)
 
 # Built-in and composite module parts
-$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
+$(obj)/%.o: $(src)/%.c FORCE
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 
 # Single-part modules are special since we need to mark them in $(MODVERDIR)
 
-$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
+$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 	@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
diff --git a/scripts/kcc.sh b/scripts/kcc.sh
new file mode 100644
index 0000000..2b0bad6
--- /dev/null
+++ b/scripts/kcc.sh
@@ -0,0 +1,187 @@
+#!/bin/sh
+# kernel wrapper for cc
+# In the simple case we just call cc with the supplied arguments.
+# But we may check the source with sparse before we call cc.
+# And we may postprocess the source or the .o file to support
+# module versioning and function tracing.
+
+# Error out on error
+set -e
+
+# Print command and execute
+# ${quiet} determine which command to print (if any)
+run()
+{
+	case "${quiet}" in
+		"silent_")
+			shift
+			;;
+		"quiet_")
+			printf "  %s \n" "$1 ${why}"
+			shift
+			;;
+		*)
+			shift
+			echo "$*"
+	esac
+
+	# Run the command
+	$*
+}
+
+# Calculate symbol versions on the preprocessed source
+# using genksyms and postprocess the output in a way
+# that it is usable as a linker script.
+# Then generate the .o file with the __crc_exported_symbol replaced.
+gen_sym_types()
+{
+	if [ "${KBUILD_SYMTYPES}" = "y" ]; then
+		dump_types="-T $1.symtypes"
+	fi
+
+	if [ "${CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX}" = "y" ]; then
+		mod_prefix="-s _"
+	fi
+
+	if [ "${KBUILD_PRESERVE}" != "" ]; then
+		preserve="-p";
+		if [ -f $1.symref ]; then
+			reference="-r $1.symref"
+		fi
+	fi
+
+	out=$1.ver
+	shift
+
+	${CPP} -D__GENKSYMS__ $* ${infile} | \
+	    ${GENKSYMS} ${dump_types} ${mod_prefix} ${preserve} ${reference} > ${out}
+
+	# Generate <file>.o from .tmp_<file>.o using the linker to
+	# replace the unresolved symbols __crc_exported_symbol with
+	# the actual value of the checksum generated by genksyms
+	${LD} ${LDFLAGS} -r -o ${outfile} ${tmpfile}.o -T ${out}
+	rm -f ${tmpfile}.o ${out}
+}
+
+# Create __mcount_loc section with pointers to all calls to mcount
+record_mcount()
+{
+	# Due to recursion, we must skip empty.o.
+	# The empty.o file is created in the make process in order to determine
+	# the target endianness and word size. It is made before all other C
+	# files, including recordmcount.
+
+	if [ "$(basename ${outfile})" = "empty.o" ]; then
+		return
+	fi
+
+	if [ "${BUILD_C_RECORDMCOUNT}" != "" ]; then
+		if [ "${RECORDMCOUNT_WARN}" != "" ]; then
+			warn_on_notrace="-w"
+		fi
+
+                ${objtree}/scripts/recordmcount ${warn_on_notrace} ${outfile}
+	else
+
+		mcount=${srctree}/scripts/recordmcount.pl
+		if [ "${CONFIG_CPU_BIG_ENDIAN}" != "" ]; then
+			endian=big
+		else
+			endian=little
+		fi
+		if [ "${CONFIG_64BIT}" != "" ]; then
+			bits=64
+		else
+			bits=32
+		fi
+		if [ "${module}" = "m" ]; then
+			is_module=1
+		else
+			is_module=0
+		fi
+
+		${mcount} ${ARCH} ${endian} ${bits} "${OBJDUMP}" "${OBJCOPY}" \
+		    "${CC} ${KBUILD_CFLAGS}" "${LD}" "${NM}" "${RM}" "${MV}"  \
+		    ${is_module} ${outfile}
+	fi
+}
+
+# Delete output files in case of error
+trap cleanup SIGHUP SIGINT SIGQUIT SIGTERM ERR
+cleanup()
+{
+        rm -f ${outfile}
+}
+
+#
+#
+# kcc.sh infile outfile depfile {b,m} why {options to cc}
+#  where b == built-in, m == module
+
+infile=$1
+shift
+outfile=$1
+shift
+depfile=$1
+shift
+
+# Print [M] for modules
+if [ $1 = m ]; then
+	module=m
+	modtag="[M]"
+else
+	modtag="   "
+fi
+shift
+
+why=$1
+shift
+
+# We need access to CONFIG_ symbols
+case "${KCONFIG_CONFIG}" in
+*/*)
+        . "${KCONFIG_CONFIG}"
+        ;;
+*)
+        # Force using a file from the current directory
+        . "./${KCONFIG_CONFIG}"
+esac
+
+#set -x
+
+# Run sparse (or another checker) on the input file?
+if [ "${KBUILD_CHECKSRC}" = "1" ]; then
+	cmd="${CHECK} ${CHECKFLAGS} $* ${infile}"
+	run "CHECK   ${infile}" ${cmd}
+fi
+
+# Have we enabled module versioning?
+if [ "${CONFIG_MODVERSIONS}" = "" ]; then
+	cccmd="${CC} $* -c -o ${outfile} ${infile}"
+	run "CC ${modtag}  ${outfile}" ${cccmd}
+else
+	# Module versioning is enabled
+	# If the .o file contains exported symbol calculate symbol versions
+	dir=$(dirname ${outfile})
+	file=$(basename ${outfile})
+	tmpfile=${dir}/.tmp_${file}
+
+	cccmd="${CC} $* -c -o ${tmpfile}.o ${infile}"
+	run "CC ${modtag}  ${outfile}" ${cccmd}
+
+        if ${OBJDUMP} -h ${tmpfile}.o | grep -q __ksymtab; then
+		# The .o file contains exported symbols
+		# (contains __ksymtab section)
+		# Calculate symbol versions using genksyms
+		gen_sym_types ${tmpfile} $*
+        else
+                mv -f ${tmpfile}.o ${outfile}
+        fi
+fi
+
+# Do we have to run record_mcount?
+if [ "${CONFIG_FTRACE_MCOUNT_RECORD}" != "" ]; then
+	if [ $(echo $* | grep -c -e "-pg") -gt 0 ]; then
+		record_mcount
+	fi
+fi
