History

kbuild/Makefile: Prepare for using macros in inline assembly code to work around asm() related GCC inlining bugs

Using macros in inline assembly allows us to work around bugs in GCC's inlining decisions. Compile macros.S and use it to assemble all C files. Currently only x86 will use it. Background: The inlining pass of GCC doesn't include an assembler, so it's not aware of basic properties of the generated code, such as its size in bytes, or that there are such things as discontiuous blocks of code and data due to the newfangled linker feature called 'sections' ... Instead GCC uses a lazy and fragile heuristic: it does a linear count of certain syntactic and whitespace elements in inlined assembly block source code, such as a count of new-lines and semicolons (!), as a poor substitute for "code size and complexity". Unsurprisingly this heuristic falls over and breaks its neck whith certain common types of kernel code that use inline assembly, such as the frequent practice of putting useful information into alternative sections. As a result of this fresh, 20+ years old GCC bug, GCC's inlining decisions are effectively disabled for inlined functions that make use of such asm() blocks, because GCC thinks those sections of code are "large" - when in reality they are often result in just a very low number of machine instructions. This absolute lack of inlining provess when GCC comes across such asm() blocks both increases generated kernel code size and causes performance overhead, which is particularly noticeable on paravirt kernels, which make frequent use of these inlining facilities in attempt to stay out of the way when running on baremetal hardware. Instead of fixing the compiler we use a workaround: we set an assembly macro and call it from the inlined assembly block. As a result GCC considers the inline assembly block as a single instruction. (Which it often isn't but I digress.) This uglifies and bloats the source code - for example just the refcount related changes have this impact: Makefile | 9 +++++++-- arch/x86/Makefile | 7 +++++++ arch/x86/kernel/macros.S | 7 +++++++ scripts/Kbuild.include | 4 +++- scripts/mod/Makefile | 2 ++ 5 files changed, 26 insertions(+), 3 deletions(-) Yay readability and maintainability, it's not like assembly code is hard to read and maintain ... We also hope that GCC will eventually get fixed, but we are not holding our breath for that. Yet we are optimistic, it might still happen, any decade now. [ mingo: Wrote new changelog describing the background. ]

Nadav Amit committed 8 years ago

Commit 77b0bf51 parent 35e76b95 files · +26 −3Browse files

Unified · Split

5 files
  1. Makefile +7 −2
  2. arch/x86/Makefile +7 −0
  3. arch/x86/kernel/macros.S +7 −0
  4. scripts/Kbuild.include +3 −1
  5. scripts/mod/Makefile +2 −0
Makefile+7−2
@@ -1071,7 +1071,7 @@ scripts: scripts_basic asm-generic gcc-plugins $(autoksyms_h) · 1070 unmodified lines
1071# version.h and scripts_basic is processed / created.1071# version.h and scripts_basic is processed / created.
1072 1072
1073# Listed in dependency order1073# Listed in dependency order
1074PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare31074PHONY += prepare archprepare macroprepare prepare0 prepare1 prepare2 prepare3
1075 1075
1076# prepare3 is used to check if we are building in a separate output directory,1076# prepare3 is used to check if we are building in a separate output directory,
1077# and if so do:1077# and if so do:
@@ -1094,7 +1094,9 @@ prepare2: prepare3 outputmakefile asm-generic · 16 unmodified lines
1094prepare1: prepare2 $(version_h) $(autoksyms_h) include/generated/utsrelease.h1094prepare1: prepare2 $(version_h) $(autoksyms_h) include/generated/utsrelease.h
1095 $(cmd_crmodverdir)1095 $(cmd_crmodverdir)
1096 1096
1097archprepare: archheaders archscripts prepare1 scripts_basic1097macroprepare: prepare1 archmacros
1098
1099archprepare: archheaders archscripts macroprepare scripts_basic
1098 1100
1099prepare0: archprepare gcc-plugins1101prepare0: archprepare gcc-plugins
1100 $(Q)$(MAKE) $(build)=.1102 $(Q)$(MAKE) $(build)=.
@@ -1162,6 +1164,9 @@ archheaders: · 61 unmodified lines
1162PHONY += archscripts1164PHONY += archscripts
1163archscripts:1165archscripts:
1164 1166
1167PHONY += archmacros
1168archmacros:
1169
1165PHONY += __headers1170PHONY += __headers
1166__headers: $(version_h) scripts_basic uapi-asm-generic archheaders archscripts1171__headers: $(version_h) scripts_basic uapi-asm-generic archheaders archscripts
1167 $(Q)$(MAKE) $(build)=scripts build_unifdef1172 $(Q)$(MAKE) $(build)=scripts build_unifdef
arch/x86/Makefile+7−0
@@ -236,6 +236,13 @@ archscripts: scripts_basic · 235 unmodified lines
236archheaders:236archheaders:
237 $(Q)$(MAKE) $(build)=arch/x86/entry/syscalls all237 $(Q)$(MAKE) $(build)=arch/x86/entry/syscalls all
238 238
239archmacros:
240 $(Q)$(MAKE) $(build)=arch/x86/kernel arch/x86/kernel/macros.s
241
242ASM_MACRO_FLAGS = -Wa,arch/x86/kernel/macros.s -Wa,-
243export ASM_MACRO_FLAGS
244KBUILD_CFLAGS += $(ASM_MACRO_FLAGS)
245
239###246###
240# Kernel objects247# Kernel objects
241 248
arch/x86/kernel/macros.S+7−0
@@ -0,0 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3/*
4 * This file includes headers whose assembly part includes macros which are
5 * commonly used. The macros are precompiled into assmebly file which is later
6 * assembled together with each compiled file.
7 */
scripts/Kbuild.include+3−1
@@ -115,7 +115,9 @@ __cc-option = $(call try-run,\ · 114 unmodified lines
115 115
116# Do not attempt to build with gcc plugins during cc-option tests.116# Do not attempt to build with gcc plugins during cc-option tests.
117# (And this uses delayed resolution so the flags will be up to date.)117# (And this uses delayed resolution so the flags will be up to date.)
118CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS))118# In addition, do not include the asm macros which are built later.
119CC_OPTION_FILTERED = $(GCC_PLUGINS_CFLAGS) $(ASM_MACRO_FLAGS)
120CC_OPTION_CFLAGS = $(filter-out $(CC_OPTION_FILTERED),$(KBUILD_CFLAGS))
119 121
120# cc-option122# cc-option
121# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)123# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
scripts/mod/Makefile+2−0
@@ -4,6 +4,8 @@ OBJECT_FILES_NON_STANDARD := y · 3 unmodified lines
4hostprogs-y := modpost mk_elfconfig4hostprogs-y := modpost mk_elfconfig
5always := $(hostprogs-y) empty.o5always := $(hostprogs-y) empty.o
6 6
7CFLAGS_REMOVE_empty.o := $(ASM_MACRO_FLAGS)
8
7modpost-objs := modpost.o file2alias.o sumversion.o9modpost-objs := modpost.o file2alias.o sumversion.o
8 10
9devicetable-offsets-file := devicetable-offsets.h11devicetable-offsets-file := devicetable-offsets.h