77b0bf55bc
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. ] Tested-by: Kees Cook <keescook@chromium.org> Signed-off-by: Nadav Amit <namit@vmware.com> Acked-by: Masahiro Yamada <yamada.masahiro@socionext.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Michal Marek <michal.lkml@markovi.net> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kbuild@vger.kernel.org Link: http://lkml.kernel.org/r/20181003213100.189959-3-namit@vmware.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
30 lines
871 B
Makefile
30 lines
871 B
Makefile
# SPDX-License-Identifier: GPL-2.0
|
|
OBJECT_FILES_NON_STANDARD := y
|
|
|
|
hostprogs-y := modpost mk_elfconfig
|
|
always := $(hostprogs-y) empty.o
|
|
|
|
CFLAGS_REMOVE_empty.o := $(ASM_MACRO_FLAGS)
|
|
|
|
modpost-objs := modpost.o file2alias.o sumversion.o
|
|
|
|
devicetable-offsets-file := devicetable-offsets.h
|
|
|
|
$(obj)/$(devicetable-offsets-file): $(obj)/devicetable-offsets.s FORCE
|
|
$(call filechk,offsets,__DEVICETABLE_OFFSETS_H__)
|
|
|
|
targets += $(devicetable-offsets-file) devicetable-offsets.s
|
|
|
|
# dependencies on generated files need to be listed explicitly
|
|
|
|
$(obj)/modpost.o $(obj)/file2alias.o $(obj)/sumversion.o: $(obj)/elfconfig.h
|
|
$(obj)/file2alias.o: $(obj)/$(devicetable-offsets-file)
|
|
|
|
quiet_cmd_elfconfig = MKELF $@
|
|
cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@
|
|
|
|
$(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE
|
|
$(call if_changed,elfconfig)
|
|
|
|
targets += elfconfig.h
|