Commit d937a6df authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool updates from Ingo Molnar:
 "The biggest changes in this cycle were the vmlinux.o optimizations by
   Peter Zijlstra, which are preparatory and optimization work to run
   objtool against the much richer vmlinux.o object file, to perform
   new, whole-program section based logic. That work exposed a handful
   of problems with the existing code, which fixes and optimizations are
   merged here. The complete 'vmlinux.o and noinstr' work is still work
   in progress, targeted for v5.8.

  There's also assorted fixes and enhancements from Josh Poimboeuf.

  In particular I'd like to draw attention to commit 644592d3,
  which turns fatal objtool errors into failed kernel builds. This
  behavior is IMO now justified on multiple grounds (it's easy currently
  to not notice an essentially corrupted kernel build), and the commit
  has been in -next testing for several weeks, but there could still be
  build failures with old or weird toolchains. Should that be widespread
  or high profile enough then I'd suggest a quick revert, to not hold up
  the merge window"

* 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (22 commits)
  objtool: Re-arrange validate_functions()
  objtool: Optimize find_rela_by_dest_range()
  objtool: Delete cleanup()
  objtool: Optimize read_sections()
  objtool: Optimize find_symbol_by_name()
  objtool: Resize insn_hash
  objtool: Rename find_containing_func()
  objtool: Optimize find_symbol_*() and read_symbols()
  objtool: Optimize find_section_by_name()
  objtool: Optimize find_section_by_index()
  objtool: Add a statistics mode
  objtool: Optimize find_symbol_by_index()
  x86/kexec: Make relocate_kernel_64.S objtool clean
  x86/kexec: Use RIP relative addressing
  objtool: Rename func_for_each_insn_all()
  objtool: Rename func_for_each_insn()
  objtool: Introduce validate_return()
  objtool: Improve call destination function detection
  objtool: Fix clang switch table edge case
  objtool: Add relocation check for alternative sections
  ...
parents 2ce94bc4 350994bf
...@@ -28,7 +28,6 @@ KASAN_SANITIZE_dumpstack_$(BITS).o := n ...@@ -28,7 +28,6 @@ KASAN_SANITIZE_dumpstack_$(BITS).o := n
KASAN_SANITIZE_stacktrace.o := n KASAN_SANITIZE_stacktrace.o := n
KASAN_SANITIZE_paravirt.o := n KASAN_SANITIZE_paravirt.o := n
OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_test_nx.o := y OBJECT_FILES_NON_STANDARD_test_nx.o := y
OBJECT_FILES_NON_STANDARD_paravirt_patch.o := y OBJECT_FILES_NON_STANDARD_paravirt_patch.o := y
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <asm/kexec.h> #include <asm/kexec.h>
#include <asm/processor-flags.h> #include <asm/processor-flags.h>
#include <asm/pgtable_types.h> #include <asm/pgtable_types.h>
#include <asm/nospec-branch.h>
#include <asm/unwind_hints.h>
/* /*
* Must be relocatable PIC code callable as a C function * Must be relocatable PIC code callable as a C function
...@@ -39,6 +41,7 @@ ...@@ -39,6 +41,7 @@
.align PAGE_SIZE .align PAGE_SIZE
.code64 .code64
SYM_CODE_START_NOALIGN(relocate_kernel) SYM_CODE_START_NOALIGN(relocate_kernel)
UNWIND_HINT_EMPTY
/* /*
* %rdi indirection_page * %rdi indirection_page
* %rsi page_list * %rsi page_list
...@@ -105,6 +108,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel) ...@@ -105,6 +108,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
SYM_CODE_END(relocate_kernel) SYM_CODE_END(relocate_kernel)
SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
UNWIND_HINT_EMPTY
/* set return address to 0 if not preserving context */ /* set return address to 0 if not preserving context */
pushq $0 pushq $0
/* store the start address on the stack */ /* store the start address on the stack */
...@@ -192,14 +196,12 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) ...@@ -192,14 +196,12 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
1: 1:
popq %rdx popq %rdx
leaq PAGE_SIZE(%r10), %rsp leaq PAGE_SIZE(%r10), %rsp
ANNOTATE_RETPOLINE_SAFE
call *%rdx call *%rdx
/* get the re-entry point of the peer system */ /* get the re-entry point of the peer system */
movq 0(%rsp), %rbp movq 0(%rsp), %rbp
call 1f leaq relocate_kernel(%rip), %r8
1:
popq %r8
subq $(1b - relocate_kernel), %r8
movq CP_PA_SWAP_PAGE(%r8), %r10 movq CP_PA_SWAP_PAGE(%r8), %r10
movq CP_PA_BACKUP_PAGES_MAP(%r8), %rdi movq CP_PA_BACKUP_PAGES_MAP(%r8), %rdi
movq CP_PA_TABLE_PAGE(%r8), %rax movq CP_PA_TABLE_PAGE(%r8), %rax
...@@ -212,6 +214,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) ...@@ -212,6 +214,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
SYM_CODE_END(identity_mapped) SYM_CODE_END(identity_mapped)
SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped) SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
UNWIND_HINT_EMPTY
movq RSP(%r8), %rsp movq RSP(%r8), %rsp
movq CR4(%r8), %rax movq CR4(%r8), %rax
movq %rax, %cr4 movq %rax, %cr4
...@@ -233,6 +236,7 @@ SYM_CODE_END(virtual_mapped) ...@@ -233,6 +236,7 @@ SYM_CODE_END(virtual_mapped)
/* Do the copies */ /* Do the copies */
SYM_CODE_START_LOCAL_NOALIGN(swap_pages) SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
UNWIND_HINT_EMPTY
movq %rdi, %rcx /* Put the page_list in %rcx */ movq %rdi, %rcx /* Put the page_list in %rcx */
xorl %edi, %edi xorl %edi, %edi
xorl %esi, %esi xorl %esi, %esi
......
...@@ -11,6 +11,7 @@ objtool-y += objtool.o ...@@ -11,6 +11,7 @@ objtool-y += objtool.o
objtool-y += libstring.o objtool-y += libstring.o
objtool-y += libctype.o objtool-y += libctype.o
objtool-y += str_error_r.o objtool-y += str_error_r.o
objtool-y += librbtree.o
CFLAGS += -I$(srctree)/tools/lib CFLAGS += -I$(srctree)/tools/lib
...@@ -25,3 +26,7 @@ $(OUTPUT)libctype.o: ../lib/ctype.c FORCE ...@@ -25,3 +26,7 @@ $(OUTPUT)libctype.o: ../lib/ctype.c FORCE
$(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE $(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
$(call rule_mkdir) $(call rule_mkdir)
$(call if_changed_dep,cc_o_c) $(call if_changed_dep,cc_o_c)
$(OUTPUT)librbtree.o: ../lib/rbtree.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include "builtin.h" #include "builtin.h"
#include "check.h" #include "check.h"
bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess; bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats;
static const char * const check_usage[] = { static const char * const check_usage[] = {
"objtool check [<options>] file.o", "objtool check [<options>] file.o",
...@@ -31,6 +31,7 @@ const struct option check_options[] = { ...@@ -31,6 +31,7 @@ const struct option check_options[] = {
OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"),
OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"), OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"),
OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"), OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"),
OPT_BOOLEAN('s', "stats", &stats, "print statistics"),
OPT_END(), OPT_END(),
}; };
......
...@@ -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; extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats;
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);
......
This diff is collapsed.
...@@ -50,7 +50,7 @@ struct instruction { ...@@ -50,7 +50,7 @@ struct instruction {
struct objtool_file { struct objtool_file {
struct elf *elf; struct elf *elf;
struct list_head insn_list; struct list_head insn_list;
DECLARE_HASHTABLE(insn_hash, 16); DECLARE_HASHTABLE(insn_hash, 20);
bool ignore_unreachables, c_file, hints, rodata; bool ignore_unreachables, c_file, hints, rodata;
}; };
......
This diff is collapsed.
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <gelf.h> #include <gelf.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/rbtree.h>
#include <linux/jhash.h>
#ifdef LIBELF_USE_DEPRECATED #ifdef LIBELF_USE_DEPRECATED
# define elf_getshdrnum elf_getshnum # define elf_getshdrnum elf_getshnum
...@@ -25,11 +27,12 @@ ...@@ -25,11 +27,12 @@
struct section { struct section {
struct list_head list; struct list_head list;
struct hlist_node hash;
struct hlist_node name_hash;
GElf_Shdr sh; GElf_Shdr sh;
struct rb_root symbol_tree;
struct list_head symbol_list; struct list_head symbol_list;
DECLARE_HASHTABLE(symbol_hash, 8);
struct list_head rela_list; struct list_head rela_list;
DECLARE_HASHTABLE(rela_hash, 16);
struct section *base, *rela; struct section *base, *rela;
struct symbol *sym; struct symbol *sym;
Elf_Data *data; Elf_Data *data;
...@@ -41,7 +44,9 @@ struct section { ...@@ -41,7 +44,9 @@ struct section {
struct symbol { struct symbol {
struct list_head list; struct list_head list;
struct rb_node node;
struct hlist_node hash; struct hlist_node hash;
struct hlist_node name_hash;
GElf_Sym sym; GElf_Sym sym;
struct section *sec; struct section *sec;
char *name; char *name;
...@@ -71,19 +76,51 @@ struct elf { ...@@ -71,19 +76,51 @@ struct elf {
int fd; int fd;
char *name; char *name;
struct list_head sections; struct list_head sections;
DECLARE_HASHTABLE(rela_hash, 16); DECLARE_HASHTABLE(symbol_hash, 20);
DECLARE_HASHTABLE(symbol_name_hash, 20);
DECLARE_HASHTABLE(section_hash, 16);
DECLARE_HASHTABLE(section_name_hash, 16);
DECLARE_HASHTABLE(rela_hash, 20);
}; };
#define OFFSET_STRIDE_BITS 4
#define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)
#define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1))
#define for_offset_range(_offset, _start, _end) \
for (_offset = ((_start) & OFFSET_STRIDE_MASK); \
_offset <= ((_end) & OFFSET_STRIDE_MASK); \
_offset += OFFSET_STRIDE)
static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
{
u32 ol, oh, idx = sec->idx;
offset &= OFFSET_STRIDE_MASK;
ol = offset;
oh = offset >> 32;
__jhash_mix(ol, oh, idx);
return ol;
}
static inline u32 rela_hash(struct rela *rela)
{
return sec_offset_hash(rela->sec, rela->offset);
}
struct elf *elf_read(const char *name, int flags); struct elf *elf_read(const char *name, int flags);
struct section *find_section_by_name(struct elf *elf, const char *name); struct section *find_section_by_name(struct elf *elf, const char *name);
struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
struct symbol *find_symbol_by_name(struct elf *elf, const char *name); struct symbol *find_symbol_by_name(struct elf *elf, const char *name);
struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); struct symbol *find_symbol_containing(struct section *sec, unsigned long offset);
struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset);
struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
unsigned int len); unsigned long offset, unsigned int len);
struct symbol *find_containing_func(struct section *sec, unsigned long offset); struct symbol *find_func_containing(struct section *sec, unsigned long offset);
struct section *elf_create_section(struct elf *elf, const char *name, size_t struct section *elf_create_section(struct elf *elf, const char *name, size_t
entsize, int nr); entsize, int nr);
struct section *elf_create_rela_section(struct elf *elf, struct section *base); struct section *elf_create_rela_section(struct elf *elf, struct section *base);
......
...@@ -81,7 +81,7 @@ int create_orc(struct objtool_file *file) ...@@ -81,7 +81,7 @@ int create_orc(struct objtool_file *file)
return 0; return 0;
} }
static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, static int create_orc_entry(struct elf *elf, struct section *u_sec, struct section *ip_relasec,
unsigned int idx, struct section *insn_sec, unsigned int idx, struct section *insn_sec,
unsigned long insn_off, struct orc_entry *o) unsigned long insn_off, struct orc_entry *o)
{ {
...@@ -109,9 +109,10 @@ static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, ...@@ -109,9 +109,10 @@ static int create_orc_entry(struct section *u_sec, struct section *ip_relasec,
rela->addend = insn_off; rela->addend = insn_off;
rela->type = R_X86_64_PC32; rela->type = R_X86_64_PC32;
rela->offset = idx * sizeof(int); rela->offset = idx * sizeof(int);
rela->sec = ip_relasec;
list_add_tail(&rela->list, &ip_relasec->rela_list); list_add_tail(&rela->list, &ip_relasec->rela_list);
hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset); hash_add(elf->rela_hash, &rela->hash, rela_hash(rela));
return 0; return 0;
} }
...@@ -182,7 +183,7 @@ int create_orc_sections(struct objtool_file *file) ...@@ -182,7 +183,7 @@ int create_orc_sections(struct objtool_file *file)
if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc, if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc,
sizeof(struct orc_entry))) { sizeof(struct orc_entry))) {
if (create_orc_entry(u_sec, ip_relasec, idx, if (create_orc_entry(file->elf, u_sec, ip_relasec, idx,
insn->sec, insn->offset, insn->sec, insn->offset,
&insn->orc)) &insn->orc))
return -1; return -1;
...@@ -194,7 +195,7 @@ int create_orc_sections(struct objtool_file *file) ...@@ -194,7 +195,7 @@ int create_orc_sections(struct objtool_file *file)
/* section terminator */ /* section terminator */
if (prev_insn) { if (prev_insn) {
if (create_orc_entry(u_sec, ip_relasec, idx, if (create_orc_entry(file->elf, u_sec, ip_relasec, idx,
prev_insn->sec, prev_insn->sec,
prev_insn->offset + prev_insn->len, prev_insn->offset + prev_insn->len,
&empty)) &empty))
......
...@@ -118,7 +118,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, ...@@ -118,7 +118,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
} }
} }
orig_rela = find_rela_by_dest(sec, offset + entry->orig); orig_rela = find_rela_by_dest(elf, sec, offset + entry->orig);
if (!orig_rela) { if (!orig_rela) {
WARN_FUNC("can't find orig rela", sec, offset + entry->orig); WARN_FUNC("can't find orig rela", sec, offset + entry->orig);
return -1; return -1;
...@@ -133,7 +133,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, ...@@ -133,7 +133,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
alt->orig_off = orig_rela->addend; alt->orig_off = orig_rela->addend;
if (!entry->group || alt->new_len) { if (!entry->group || alt->new_len) {
new_rela = find_rela_by_dest(sec, offset + entry->new); new_rela = find_rela_by_dest(elf, sec, offset + entry->new);
if (!new_rela) { if (!new_rela) {
WARN_FUNC("can't find new rela", WARN_FUNC("can't find new rela",
sec, offset + entry->new); sec, offset + entry->new);
......
...@@ -21,7 +21,7 @@ static inline char *offstr(struct section *sec, unsigned long offset) ...@@ -21,7 +21,7 @@ static inline char *offstr(struct section *sec, unsigned long offset)
char *name, *str; char *name, *str;
unsigned long name_off; unsigned long name_off;
func = find_containing_func(sec, offset); func = find_func_containing(sec, offset);
if (func) { if (func) {
name = func->name; name = func->name;
name_off = offset - func->offset; name_off = offset - func->offset;
......
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