Commit 414eece9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clang-lto-v5.12-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull more clang LTO updates from Kees Cook:
 "Clang LTO x86 enablement.

  Full disclosure: while this has _not_ been in linux-next (since it
  initially looked like the objtool dependencies weren't going to make
  v5.12), it has been under daily build and runtime testing by Sami for
  quite some time. These x86 portions have been discussed on lkml, with
  Peter, Josh, and others helping nail things down.

  The bulk of the changes are to get objtool working happily. The rest
  of the x86 enablement is very small.

  Summary:

   - Generate __mcount_loc in objtool (Peter Zijlstra)

   - Support running objtool against vmlinux.o (Sami Tolvanen)

   - Clang LTO enablement for x86 (Sami Tolvanen)"

Link: https://lore.kernel.org/lkml/20201013003203.4168817-26-samitolvanen@google.com/
Link: https://lore.kernel.org/lkml/cover.1611263461.git.jpoimboe@redhat.com/

* tag 'clang-lto-v5.12-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  kbuild: lto: force rebuilds when switching CONFIG_LTO
  x86, build: allow LTO to be selected
  x86, cpu: disable LTO for cpu.c
  x86, vdso: disable LTO only for vDSO
  kbuild: lto: postpone objtool
  objtool: Split noinstr validation from --vmlinux
  x86, build: use objtool mcount
  tracing: add support for objtool mcount
  objtool: Don't autodetect vmlinux.o
  objtool: Fix __mcount_loc generation with Clang's assembler
  objtool: Add a pass for generating __mcount_loc
parents 6dd580b9 5e95325f
...@@ -862,6 +862,9 @@ ifdef CONFIG_FTRACE_MCOUNT_USE_CC ...@@ -862,6 +862,9 @@ ifdef CONFIG_FTRACE_MCOUNT_USE_CC
endif endif
endif endif
endif endif
ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
CC_FLAGS_USING += -DCC_USING_NOP_MCOUNT
endif
ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
ifdef CONFIG_HAVE_C_RECORDMCOUNT ifdef CONFIG_HAVE_C_RECORDMCOUNT
BUILD_C_RECORDMCOUNT := y BUILD_C_RECORDMCOUNT := y
...@@ -909,7 +912,8 @@ KBUILD_LDFLAGS += -mllvm -import-instr-limit=5 ...@@ -909,7 +912,8 @@ KBUILD_LDFLAGS += -mllvm -import-instr-limit=5
endif endif
ifdef CONFIG_LTO ifdef CONFIG_LTO
KBUILD_CFLAGS += $(CC_FLAGS_LTO) KBUILD_CFLAGS += -fno-lto $(CC_FLAGS_LTO)
KBUILD_AFLAGS += -fno-lto
export CC_FLAGS_LTO export CC_FLAGS_LTO
endif endif
...@@ -1243,6 +1247,10 @@ uapi-asm-generic: ...@@ -1243,6 +1247,10 @@ uapi-asm-generic:
PHONY += prepare-objtool prepare-resolve_btfids PHONY += prepare-objtool prepare-resolve_btfids
prepare-objtool: $(objtool_target) prepare-objtool: $(objtool_target)
ifeq ($(SKIP_STACK_VALIDATION),1) ifeq ($(SKIP_STACK_VALIDATION),1)
ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
@echo "error: Cannot generate __mcount_loc for CONFIG_DYNAMIC_FTRACE=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2
@false
endif
ifdef CONFIG_UNWINDER_ORC ifdef CONFIG_UNWINDER_ORC
@echo "error: Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2 @echo "error: Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel" >&2
@false @false
......
...@@ -97,6 +97,8 @@ config X86 ...@@ -97,6 +97,8 @@ config X86
select ARCH_SUPPORTS_DEBUG_PAGEALLOC select ARCH_SUPPORTS_DEBUG_PAGEALLOC
select ARCH_SUPPORTS_NUMA_BALANCING if X86_64 select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096 select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096
select ARCH_SUPPORTS_LTO_CLANG if X86_64
select ARCH_SUPPORTS_LTO_CLANG_THIN if X86_64
select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_RWLOCKS
select ARCH_USE_QUEUED_SPINLOCKS select ARCH_USE_QUEUED_SPINLOCKS
...@@ -169,6 +171,7 @@ config X86 ...@@ -169,6 +171,7 @@ config X86
select HAVE_CONTEXT_TRACKING if X86_64 select HAVE_CONTEXT_TRACKING if X86_64
select HAVE_CONTEXT_TRACKING_OFFSTACK if HAVE_CONTEXT_TRACKING select HAVE_CONTEXT_TRACKING_OFFSTACK if HAVE_CONTEXT_TRACKING
select HAVE_C_RECORDMCOUNT select HAVE_C_RECORDMCOUNT
select HAVE_OBJTOOL_MCOUNT if STACK_VALIDATION
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
......
...@@ -169,6 +169,11 @@ ifeq ($(ACCUMULATE_OUTGOING_ARGS), 1) ...@@ -169,6 +169,11 @@ ifeq ($(ACCUMULATE_OUTGOING_ARGS), 1)
KBUILD_CFLAGS += $(call cc-option,-maccumulate-outgoing-args,) KBUILD_CFLAGS += $(call cc-option,-maccumulate-outgoing-args,)
endif endif
ifdef CONFIG_LTO_CLANG
KBUILD_LDFLAGS += -plugin-opt=-code-model=kernel \
-plugin-opt=-stack-alignment=$(if $(CONFIG_X86_32),4,8)
endif
# Workaround for a gcc prelease that unfortunately was shipped in a suse release # Workaround for a gcc prelease that unfortunately was shipped in a suse release
KBUILD_CFLAGS += -Wno-sign-compare KBUILD_CFLAGS += -Wno-sign-compare
# #
......
...@@ -91,7 +91,7 @@ ifneq ($(RETPOLINE_VDSO_CFLAGS),) ...@@ -91,7 +91,7 @@ ifneq ($(RETPOLINE_VDSO_CFLAGS),)
endif endif
endif endif
$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL) $(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
# #
# vDSO code runs in userspace and -pg doesn't help with profiling anyway. # vDSO code runs in userspace and -pg doesn't help with profiling anyway.
...@@ -150,6 +150,7 @@ KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32)) ...@@ -150,6 +150,7 @@ KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(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 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 := $(filter-out $(CC_FLAGS_LTO),$(KBUILD_CFLAGS_32))
KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
KBUILD_CFLAGS_32 += -fno-stack-protector KBUILD_CFLAGS_32 += -fno-stack-protector
KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
......
...@@ -4,5 +4,9 @@ ...@@ -4,5 +4,9 @@
# itself be stack-protected # itself be stack-protected
CFLAGS_cpu.o := -fno-stack-protector CFLAGS_cpu.o := -fno-stack-protector
# Clang may incorrectly inline functions with stack protector enabled into
# __restore_processor_state(): https://bugs.llvm.org/show_bug.cgi?id=47479
CFLAGS_REMOVE_cpu.o := $(CC_FLAGS_LTO)
obj-$(CONFIG_PM_SLEEP) += cpu.o obj-$(CONFIG_PM_SLEEP) += cpu.o
obj-$(CONFIG_HIBERNATION) += hibernate_$(BITS).o hibernate_asm_$(BITS).o hibernate.o obj-$(CONFIG_HIBERNATION) += hibernate_$(BITS).o hibernate_asm_$(BITS).o hibernate.o
...@@ -60,6 +60,11 @@ config HAVE_NOP_MCOUNT ...@@ -60,6 +60,11 @@ config HAVE_NOP_MCOUNT
help help
Arch supports the gcc options -pg with -mrecord-mcount and -nop-mcount Arch supports the gcc options -pg with -mrecord-mcount and -nop-mcount
config HAVE_OBJTOOL_MCOUNT
bool
help
Arch supports objtool --mcount
config HAVE_C_RECORDMCOUNT config HAVE_C_RECORDMCOUNT
bool bool
help help
...@@ -612,10 +617,18 @@ config FTRACE_MCOUNT_USE_CC ...@@ -612,10 +617,18 @@ config FTRACE_MCOUNT_USE_CC
depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY
depends on FTRACE_MCOUNT_RECORD depends on FTRACE_MCOUNT_RECORD
config FTRACE_MCOUNT_USE_OBJTOOL
def_bool y
depends on HAVE_OBJTOOL_MCOUNT
depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY
depends on !FTRACE_MCOUNT_USE_CC
depends on FTRACE_MCOUNT_RECORD
config FTRACE_MCOUNT_USE_RECORDMCOUNT config FTRACE_MCOUNT_USE_RECORDMCOUNT
def_bool y def_bool y
depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY
depends on !FTRACE_MCOUNT_USE_CC depends on !FTRACE_MCOUNT_USE_CC
depends on !FTRACE_MCOUNT_USE_OBJTOOL
depends on FTRACE_MCOUNT_RECORD depends on FTRACE_MCOUNT_RECORD
config TRACING_MAP config TRACING_MAP
......
...@@ -218,27 +218,11 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), ...@@ -218,27 +218,11 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)),
endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
ifdef CONFIG_STACK_VALIDATION ifdef CONFIG_STACK_VALIDATION
ifndef CONFIG_LTO_CLANG
ifneq ($(SKIP_STACK_VALIDATION),1) ifneq ($(SKIP_STACK_VALIDATION),1)
__objtool_obj := $(objtree)/tools/objtool/objtool __objtool_obj := $(objtree)/tools/objtool/objtool
objtool_args = $(if $(CONFIG_UNWINDER_ORC),orc generate,check)
objtool_args += $(if $(part-of-module), --module,)
ifndef CONFIG_FRAME_POINTER
objtool_args += --no-fp
endif
ifdef CONFIG_GCOV_KERNEL
objtool_args += --no-unreachable
endif
ifdef CONFIG_RETPOLINE
objtool_args += --retpoline
endif
ifdef CONFIG_X86_SMAP
objtool_args += --uaccess
endif
# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file
...@@ -250,6 +234,7 @@ objtool_obj = $(if $(patsubst y%,, \ ...@@ -250,6 +234,7 @@ objtool_obj = $(if $(patsubst y%,, \
$(__objtool_obj)) $(__objtool_obj))
endif # SKIP_STACK_VALIDATION endif # SKIP_STACK_VALIDATION
endif # CONFIG_LTO_CLANG
endif # CONFIG_STACK_VALIDATION endif # CONFIG_STACK_VALIDATION
# Rebuild all objects when objtool changes, or is enabled/disabled. # Rebuild all objects when objtool changes, or is enabled/disabled.
......
...@@ -222,6 +222,18 @@ dtc_cpp_flags = -Wp,-MMD,$(depfile).pre.tmp -nostdinc \ ...@@ -222,6 +222,18 @@ dtc_cpp_flags = -Wp,-MMD,$(depfile).pre.tmp -nostdinc \
$(addprefix -I,$(DTC_INCLUDE)) \ $(addprefix -I,$(DTC_INCLUDE)) \
-undef -D__DTS__ -undef -D__DTS__
# Objtool arguments are also needed for modfinal with LTO, so we define
# then here to avoid duplication.
objtool_args = \
$(if $(CONFIG_UNWINDER_ORC),orc generate,check) \
$(if $(part-of-module), --module,) \
$(if $(CONFIG_FRAME_POINTER),, --no-fp) \
$(if $(or $(CONFIG_GCOV_KERNEL),$(CONFIG_LTO_CLANG)), \
--no-unreachable,) \
$(if $(CONFIG_RETPOLINE), --retpoline,) \
$(if $(CONFIG_X86_SMAP), --uaccess,) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount,)
# Useful for describing the dependency of composite objects # Useful for describing the dependency of composite objects
# Usage: # Usage:
# $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add) # $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add)
......
...@@ -9,7 +9,7 @@ __modfinal: ...@@ -9,7 +9,7 @@ __modfinal:
include include/config/auto.conf include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include include $(srctree)/scripts/Kbuild.include
# for c_flags # for c_flags and objtool_args
include $(srctree)/scripts/Makefile.lib include $(srctree)/scripts/Makefile.lib
# find all modules listed in modules.order # find all modules listed in modules.order
...@@ -34,10 +34,23 @@ ifdef CONFIG_LTO_CLANG ...@@ -34,10 +34,23 @@ ifdef CONFIG_LTO_CLANG
# With CONFIG_LTO_CLANG, reuse the object file we compiled for modpost to # With CONFIG_LTO_CLANG, reuse the object file we compiled for modpost to
# avoid a second slow LTO link # avoid a second slow LTO link
prelink-ext := .lto prelink-ext := .lto
endif
# ELF processing was skipped earlier because we didn't have native code,
# so let's now process the prelinked binary before we link the module.
ifdef CONFIG_STACK_VALIDATION
ifneq ($(SKIP_STACK_VALIDATION),1)
cmd_ld_ko_o += \
$(objtree)/tools/objtool/objtool $(objtool_args) \
$(@:.ko=$(prelink-ext).o);
endif # SKIP_STACK_VALIDATION
endif # CONFIG_STACK_VALIDATION
endif # CONFIG_LTO_CLANG
quiet_cmd_ld_ko_o = LD [M] $@ quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = \ cmd_ld_ko_o += \
$(LD) -r $(KBUILD_LDFLAGS) \ $(LD) -r $(KBUILD_LDFLAGS) \
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
-T scripts/module.lds -o $@ $(filter %.o, $^); \ -T scripts/module.lds -o $@ $(filter %.o, $^); \
......
...@@ -103,14 +103,36 @@ modpost_link() ...@@ -103,14 +103,36 @@ modpost_link()
objtool_link() objtool_link()
{ {
local objtoolcmd;
local objtoolopt; local objtoolopt;
if [ "${CONFIG_LTO_CLANG} ${CONFIG_STACK_VALIDATION}" = "y y" ]; then
# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.
if [ -n "${CONFIG_UNWINDER_ORC}" ]; then
objtoolcmd="orc generate"
fi
objtoolopt="${objtoolopt} --duplicate"
if [ -n "${CONFIG_FTRACE_MCOUNT_USE_OBJTOOL}" ]; then
objtoolopt="${objtoolopt} --mcount"
fi
fi
if [ -n "${CONFIG_VMLINUX_VALIDATION}" ]; then if [ -n "${CONFIG_VMLINUX_VALIDATION}" ]; then
objtoolopt="check" objtoolopt="${objtoolopt} --noinstr"
fi
if [ -n "${objtoolopt}" ]; then
if [ -z "${objtoolcmd}" ]; then
objtoolcmd="check"
fi
objtoolopt="${objtoolopt} --vmlinux"
if [ -z "${CONFIG_FRAME_POINTER}" ]; then if [ -z "${CONFIG_FRAME_POINTER}" ]; then
objtoolopt="${objtoolopt} --no-fp" objtoolopt="${objtoolopt} --no-fp"
fi fi
if [ -n "${CONFIG_GCOV_KERNEL}" ]; then if [ -n "${CONFIG_GCOV_KERNEL}" ] || [ -n "${CONFIG_LTO_CLANG}" ]; then
objtoolopt="${objtoolopt} --no-unreachable" objtoolopt="${objtoolopt} --no-unreachable"
fi fi
if [ -n "${CONFIG_RETPOLINE}" ]; then if [ -n "${CONFIG_RETPOLINE}" ]; then
...@@ -120,7 +142,7 @@ objtool_link() ...@@ -120,7 +142,7 @@ objtool_link()
objtoolopt="${objtoolopt} --uaccess" objtoolopt="${objtoolopt} --uaccess"
fi fi
info OBJTOOL ${1} info OBJTOOL ${1}
tools/objtool/objtool ${objtoolopt} ${1} tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1}
fi fi
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <objtool/builtin.h> #include <objtool/builtin.h>
#include <objtool/objtool.h> #include <objtool/objtool.h>
bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux; bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux, mcount, noinstr;
static const char * const check_usage[] = { static const char * const check_usage[] = {
"objtool check [<options>] file.o", "objtool check [<options>] file.o",
...@@ -34,13 +34,15 @@ const struct option check_options[] = { ...@@ -34,13 +34,15 @@ const struct option check_options[] = {
OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"), OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"),
OPT_BOOLEAN('s', "stats", &stats, "print statistics"), OPT_BOOLEAN('s', "stats", &stats, "print statistics"),
OPT_BOOLEAN('d', "duplicate", &validate_dup, "duplicate validation for vmlinux.o"), OPT_BOOLEAN('d', "duplicate", &validate_dup, "duplicate validation for vmlinux.o"),
OPT_BOOLEAN('n', "noinstr", &noinstr, "noinstr validation for vmlinux.o"),
OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"), OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"),
OPT_BOOLEAN('M', "mcount", &mcount, "generate __mcount_loc"),
OPT_END(), OPT_END(),
}; };
int cmd_check(int argc, const char **argv) int cmd_check(int argc, const char **argv)
{ {
const char *objname, *s; const char *objname;
struct objtool_file *file; struct objtool_file *file;
int ret; int ret;
...@@ -51,10 +53,6 @@ int cmd_check(int argc, const char **argv) ...@@ -51,10 +53,6 @@ int cmd_check(int argc, const char **argv)
objname = argv[0]; objname = argv[0];
s = strstr(objname, "vmlinux.o");
if (s && !s[9])
vmlinux = true;
file = objtool_open_read(objname); file = objtool_open_read(objname);
if (!file) if (!file)
return 1; return 1;
......
...@@ -249,7 +249,7 @@ static void init_insn_state(struct insn_state *state, struct section *sec) ...@@ -249,7 +249,7 @@ static void init_insn_state(struct insn_state *state, struct section *sec)
* not correctly determine insn->call_dest->sec (external symbols do * not correctly determine insn->call_dest->sec (external symbols do
* not have a section). * not have a section).
*/ */
if (vmlinux && sec) if (vmlinux && noinstr && sec)
state->noinstr = sec->noinstr; state->noinstr = sec->noinstr;
} }
...@@ -548,6 +548,78 @@ static int create_static_call_sections(struct objtool_file *file) ...@@ -548,6 +548,78 @@ static int create_static_call_sections(struct objtool_file *file)
return 0; return 0;
} }
static int create_mcount_loc_sections(struct objtool_file *file)
{
struct section *sec, *reloc_sec;
struct reloc *reloc;
unsigned long *loc;
struct instruction *insn;
int idx;
sec = find_section_by_name(file->elf, "__mcount_loc");
if (sec) {
INIT_LIST_HEAD(&file->mcount_loc_list);
WARN("file already has __mcount_loc section, skipping");
return 0;
}
if (list_empty(&file->mcount_loc_list))
return 0;
idx = 0;
list_for_each_entry(insn, &file->mcount_loc_list, mcount_loc_node)
idx++;
sec = elf_create_section(file->elf, "__mcount_loc", 0, sizeof(unsigned long), idx);
if (!sec)
return -1;
reloc_sec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
if (!reloc_sec)
return -1;
idx = 0;
list_for_each_entry(insn, &file->mcount_loc_list, mcount_loc_node) {
loc = (unsigned long *)sec->data->d_buf + idx;
memset(loc, 0, sizeof(unsigned long));
reloc = malloc(sizeof(*reloc));
if (!reloc) {
perror("malloc");
return -1;
}
memset(reloc, 0, sizeof(*reloc));
if (insn->sec->sym) {
reloc->sym = insn->sec->sym;
reloc->addend = insn->offset;
} else {
reloc->sym = find_symbol_containing(insn->sec, insn->offset);
if (!reloc->sym) {
WARN("missing symbol for insn at offset 0x%lx\n",
insn->offset);
return -1;
}
reloc->addend = insn->offset - reloc->sym->offset;
}
reloc->type = R_X86_64_64;
reloc->offset = idx * sizeof(unsigned long);
reloc->sec = reloc_sec;
elf_add_reloc(file->elf, reloc);
idx++;
}
if (elf_rebuild_reloc_section(file->elf, reloc_sec))
return -1;
return 0;
}
/* /*
* Warnings shouldn't be reported for ignored functions. * Warnings shouldn't be reported for ignored functions.
*/ */
...@@ -975,6 +1047,22 @@ static int add_call_destinations(struct objtool_file *file) ...@@ -975,6 +1047,22 @@ static int add_call_destinations(struct objtool_file *file)
insn->type = INSN_NOP; insn->type = INSN_NOP;
} }
if (mcount && !strcmp(insn->call_dest->name, "__fentry__")) {
if (reloc) {
reloc->type = R_NONE;
elf_write_reloc(file->elf, reloc);
}
elf_write_insn(file->elf, insn->sec,
insn->offset, insn->len,
arch_nop_insn(insn->len));
insn->type = INSN_NOP;
list_add_tail(&insn->mcount_loc_node,
&file->mcount_loc_list);
}
/* /*
* Whatever stack impact regular CALLs have, should be undone * Whatever stack impact regular CALLs have, should be undone
* by the RETURN of the called function. * by the RETURN of the called function.
...@@ -3048,6 +3136,13 @@ int check(struct objtool_file *file) ...@@ -3048,6 +3136,13 @@ int check(struct objtool_file *file)
goto out; goto out;
warnings += ret; warnings += ret;
if (mcount) {
ret = create_mcount_loc_sections(file);
if (ret < 0)
goto out;
warnings += ret;
}
out: out:
/* /*
* For now, don't fail the kernel build on fatal warnings. These * For now, don't fail the kernel build on fatal warnings. These
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
extern const struct option check_options[]; extern const struct option check_options[];
extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux; extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux, mcount, noinstr;
extern int cmd_check(int argc, const char **argv); extern int cmd_check(int argc, const char **argv);
extern int cmd_orc(int argc, const char **argv); extern int cmd_orc(int argc, const char **argv);
......
...@@ -40,6 +40,7 @@ struct instruction { ...@@ -40,6 +40,7 @@ struct instruction {
struct list_head list; struct list_head list;
struct hlist_node hash; struct hlist_node hash;
struct list_head static_call_node; struct list_head static_call_node;
struct list_head mcount_loc_node;
struct section *sec; struct section *sec;
unsigned long offset; unsigned long offset;
unsigned int len; unsigned int len;
......
...@@ -19,6 +19,7 @@ struct objtool_file { ...@@ -19,6 +19,7 @@ struct objtool_file {
struct list_head insn_list; struct list_head insn_list;
DECLARE_HASHTABLE(insn_hash, 20); DECLARE_HASHTABLE(insn_hash, 20);
struct list_head static_call_list; struct list_head static_call_list;
struct list_head mcount_loc_list;
bool ignore_unreachables, c_file, hints, rodata; bool ignore_unreachables, c_file, hints, rodata;
}; };
......
...@@ -62,6 +62,7 @@ struct objtool_file *objtool_open_read(const char *_objname) ...@@ -62,6 +62,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
INIT_LIST_HEAD(&file.insn_list); INIT_LIST_HEAD(&file.insn_list);
hash_init(file.insn_hash); hash_init(file.insn_hash);
INIT_LIST_HEAD(&file.static_call_list); INIT_LIST_HEAD(&file.static_call_list);
INIT_LIST_HEAD(&file.mcount_loc_list);
file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment"); file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
file.ignore_unreachables = no_unreachable; file.ignore_unreachables = no_unreachable;
file.hints = false; file.hints = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment