From 5e3992fe72748ed3892be876f09d4d990548b7af Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 18 Apr 2023 14:27:47 -0700 Subject: objtool: Limit unreachable warnings to once per function Unreachable instruction warnings are limited to once per object file. That no longer makes sense for vmlinux validation, which might have more unreachable instructions lurking in other places. Change it to once per function. Note this affects some other (much rarer) non-fatal warnings as well. In general I think one-warning-per-function makes sense, as related warnings can accumulate quickly and we want to eventually get back to failing the build with -Werror anyway. Reviewed-by: Miroslav Benes Link: https://lore.kernel.org/r/9d38f881bfc34e031c74e4e90064ccb3e49f599a.1681853186.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 0fcf99c91400..98e6c3b5fefc 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4514,6 +4514,7 @@ static int validate_sls(struct objtool_file *file) static int validate_reachable_instructions(struct objtool_file *file) { struct instruction *insn; + int warnings = 0; if (file->ignore_unreachables) return 0; @@ -4523,10 +4524,10 @@ static int validate_reachable_instructions(struct objtool_file *file) continue; WARN_INSN(insn, "unreachable instruction"); - return 1; + warnings++; } - return 0; + return warnings; } int check(struct objtool_file *file) -- cgit v1.2.3 From ca653464dd097fe64e69f1735e9f348b2a0f8037 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 18 Apr 2023 14:27:48 -0700 Subject: objtool: Add verbose option for disassembling affected functions When a warning is associated with a function, add an option to disassemble that function. This makes it easier for reporters to submit the information needed to diagnose objtool warnings. Reviewed-by: Miroslav Benes Link: https://lore.kernel.org/r/dd0fe13428ede186f09c74059a8001f4adcea5fc.1681853186.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/Documentation/objtool.txt | 5 +++ tools/objtool/builtin-check.c | 5 +++ tools/objtool/check.c | 77 +++++++++++++++++++++++++++++++++ tools/objtool/include/objtool/builtin.h | 1 + 4 files changed, 88 insertions(+) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/Documentation/objtool.txt b/tools/objtool/Documentation/objtool.txt index 744db4218e7a..8db1f29bf432 100644 --- a/tools/objtool/Documentation/objtool.txt +++ b/tools/objtool/Documentation/objtool.txt @@ -244,6 +244,11 @@ To achieve the validation, objtool enforces the following rules: Objtool warnings ---------------- +NOTE: When requesting help with an objtool warning, please recreate with +OBJTOOL_VERBOSE=1 (e.g., "make OBJTOOL_VERBOSE=1") and send the full +output, including any disassembly below the warning, to the objtool +maintainers. + For asm files, if you're getting an error which doesn't make sense, first make sure that the affected code follows the above rules. diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 7c175198d09f..5e21cfb7661d 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -93,6 +93,7 @@ static const struct option check_options[] = { OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"), OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"), OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), + OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"), OPT_END(), }; @@ -118,6 +119,10 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[]) parse_options(envc, envv, check_options, env_usage, 0); } + env = getenv("OBJTOOL_VERBOSE"); + if (env && !strcmp(env, "1")) + opts.verbose = true; + argc = parse_options(argc, argv, check_options, usage, 0); if (argc != 1) usage_with_options(usage, check_options); diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 98e6c3b5fefc..0bd0ca4c767c 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4530,6 +4530,81 @@ static int validate_reachable_instructions(struct objtool_file *file) return warnings; } +/* 'funcs' is a space-separated list of function names */ +static int disas_funcs(const char *funcs) +{ + const char *objdump_str, *cross_compile; + int size, ret; + char *cmd; + + cross_compile = getenv("CROSS_COMPILE"); + + objdump_str = "%sobjdump -wdr %s | gawk -M -v _funcs='%s' '" + "BEGIN { split(_funcs, funcs); }" + "/^$/ { func_match = 0; }" + "/<.*>:/ { " + "f = gensub(/.*<(.*)>:/, \"\\\\1\", 1);" + "for (i in funcs) {" + "if (funcs[i] == f) {" + "func_match = 1;" + "base = strtonum(\"0x\" $1);" + "break;" + "}" + "}" + "}" + "{" + "if (func_match) {" + "addr = strtonum(\"0x\" $1);" + "printf(\"%%04x \", addr - base);" + "print;" + "}" + "}' 1>&2"; + + /* fake snprintf() to calculate the size */ + size = snprintf(NULL, 0, objdump_str, cross_compile, objname, funcs) + 1; + if (size <= 0) { + WARN("objdump string size calculation failed"); + return -1; + } + + cmd = malloc(size); + + /* real snprintf() */ + snprintf(cmd, size, objdump_str, cross_compile, objname, funcs); + ret = system(cmd); + if (ret) { + WARN("disassembly failed: %d", ret); + return -1; + } + + return 0; +} + +static int disas_warned_funcs(struct objtool_file *file) +{ + struct symbol *sym; + char *funcs = NULL, *tmp; + + for_each_sym(file, sym) { + if (sym->warned) { + if (!funcs) { + funcs = malloc(strlen(sym->name) + 1); + strcpy(funcs, sym->name); + } else { + tmp = malloc(strlen(funcs) + strlen(sym->name) + 2); + sprintf(tmp, "%s %s", funcs, sym->name); + free(funcs); + funcs = tmp; + } + } + } + + if (funcs) + disas_funcs(funcs); + + return 0; +} + int check(struct objtool_file *file) { int ret, warnings = 0; @@ -4674,6 +4749,8 @@ int check(struct objtool_file *file) warnings += ret; } + if (opts.verbose) + disas_warned_funcs(file); if (opts.stats) { printf("nr_insns_visited: %ld\n", nr_insns_visited); diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index 2a108e648b7a..fcca6662c8b4 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -37,6 +37,7 @@ struct opts { bool no_unreachable; bool sec_address; bool stats; + bool verbose; }; extern struct opts opts; -- cgit v1.2.3 From ced23d2e3762ecfb859ae65d3a351218edff7205 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 18 Apr 2023 14:27:49 -0700 Subject: objtool: Include backtrace in verbose mode Include backtrace in verbose mode. This makes it easy to gather all the information needed for diagnosing objtool warnings. Reviewed-by: Miroslav Benes Link: https://lore.kernel.org/r/c255224fabcf7e64bac232fec1c77c9fc2d7d7ab.1681853186.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/Documentation/objtool.txt | 4 ++-- tools/objtool/check.c | 26 ++++++++++---------------- tools/objtool/include/objtool/warn.h | 14 ++++++++------ 3 files changed, 20 insertions(+), 24 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/Documentation/objtool.txt b/tools/objtool/Documentation/objtool.txt index 8db1f29bf432..9ec8cbf20668 100644 --- a/tools/objtool/Documentation/objtool.txt +++ b/tools/objtool/Documentation/objtool.txt @@ -246,8 +246,8 @@ Objtool warnings NOTE: When requesting help with an objtool warning, please recreate with OBJTOOL_VERBOSE=1 (e.g., "make OBJTOOL_VERBOSE=1") and send the full -output, including any disassembly below the warning, to the objtool -maintainers. +output, including any disassembly or backtrace below the warning, to the +objtool maintainers. For asm files, if you're getting an error which doesn't make sense, first make sure that the affected code follows the above rules. diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 0bd0ca4c767c..71985f3a6fa6 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3657,8 +3657,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, ret = validate_branch(file, func, alt->insn, state); if (ret) { - if (opts.backtrace) - BT_FUNC("(alt)", insn); + BT_INSN(insn, "(alt)"); return ret; } } @@ -3703,8 +3702,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, ret = validate_branch(file, func, insn->jump_dest, state); if (ret) { - if (opts.backtrace) - BT_FUNC("(branch)", insn); + BT_INSN(insn, "(branch)"); return ret; } } @@ -3802,8 +3800,8 @@ static int validate_unwind_hint(struct objtool_file *file, { if (insn->hint && !insn->visited && !insn->ignore) { int ret = validate_branch(file, insn_func(insn), insn, *state); - if (ret && opts.backtrace) - BT_FUNC("<=== (hint)", insn); + if (ret) + BT_INSN(insn, "<=== (hint)"); return ret; } @@ -3861,8 +3859,7 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) ret = validate_unret(file, alt->insn); if (ret) { - if (opts.backtrace) - BT_FUNC("(alt)", insn); + BT_INSN(insn, "(alt)"); return ret; } } @@ -3888,10 +3885,8 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) } ret = validate_unret(file, insn->jump_dest); if (ret) { - if (opts.backtrace) { - BT_FUNC("(branch%s)", insn, - insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); - } + BT_INSN(insn, "(branch%s)", + insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : ""); return ret; } @@ -3913,8 +3908,7 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) ret = validate_unret(file, dest); if (ret) { - if (opts.backtrace) - BT_FUNC("(call)", insn); + BT_INSN(insn, "(call)"); return ret; } /* @@ -4216,8 +4210,8 @@ static int validate_symbol(struct objtool_file *file, struct section *sec, state->uaccess = sym->uaccess_safe; ret = validate_branch(file, insn_func(insn), insn, *state); - if (ret && opts.backtrace) - BT_FUNC("<=== (sym)", insn); + if (ret) + BT_INSN(insn, "<=== (sym)"); return ret; } diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/objtool/warn.h index f195deab456e..ac04d3fe4dd9 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -63,12 +63,14 @@ static inline char *offstr(struct section *sec, unsigned long offset) _insn->sym->warned = 1; \ }) -#define BT_FUNC(format, insn, ...) \ -({ \ - struct instruction *_insn = (insn); \ - char *_str = offstr(_insn->sec, _insn->offset); \ - WARN(" %s: " format, _str, ##__VA_ARGS__); \ - free(_str); \ +#define BT_INSN(insn, format, ...) \ +({ \ + if (opts.verbose || opts.backtrace) { \ + struct instruction *_insn = (insn); \ + char *_str = offstr(_insn->sec, _insn->offset); \ + WARN(" %s: " format, _str, ##__VA_ARGS__); \ + free(_str); \ + } \ }) #define WARN_ELF(format, ...) \ -- cgit v1.2.3 From fedb724c3db5490234ddde0103811c28c2fedae0 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 18 Apr 2023 14:27:50 -0700 Subject: objtool: Detect missing __noreturn annotations Most "unreachable instruction" warnings these days seem to actually be the result of a missing __noreturn annotation. Add an explicit check for that. Reviewed-by: Miroslav Benes Link: https://lore.kernel.org/r/6e2b93d8c65eaed6c4166a358269dc0ef01f890c.1681853186.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/Documentation/objtool.txt | 6 ++++++ tools/objtool/check.c | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/Documentation/objtool.txt b/tools/objtool/Documentation/objtool.txt index 9ec8cbf20668..f9345e0ce740 100644 --- a/tools/objtool/Documentation/objtool.txt +++ b/tools/objtool/Documentation/objtool.txt @@ -303,6 +303,12 @@ the objtool maintainers. If it's not actually in a callable function (e.g. kernel entry code), change ENDPROC to END. +3. file.o: warning: objtool: foo+0x48c: bar() is missing a __noreturn annotation + + The call from foo() to bar() doesn't return, but bar() is missing the + __noreturn annotation. NOTE: In addition to adding the __noreturn + annotation, the function name also needs to be added to + 'global_noreturns' in tools/objtool/check.c. 4. file.o: warning: objtool: func(): can't find starting instruction or diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 71985f3a6fa6..8d1b4226608c 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4507,7 +4507,8 @@ static int validate_sls(struct objtool_file *file) static int validate_reachable_instructions(struct objtool_file *file) { - struct instruction *insn; + struct instruction *insn, *prev_insn; + struct symbol *call_dest; int warnings = 0; if (file->ignore_unreachables) @@ -4517,6 +4518,17 @@ static int validate_reachable_instructions(struct objtool_file *file) if (insn->visited || ignore_unreachable_insn(file, insn)) continue; + prev_insn = prev_insn_same_sec(file, insn); + if (prev_insn && prev_insn->dead_end) { + call_dest = insn_call_dest(prev_insn); + if (call_dest) { + WARN_INSN(insn, "%s() is missing a __noreturn annotation", + call_dest->name); + warnings++; + continue; + } + } + WARN_INSN(insn, "unreachable instruction"); warnings++; } -- cgit v1.2.3 From 55eeab2a8a11b71586ef0ad3adf532ca5f97d4be Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 18 Apr 2023 14:27:51 -0700 Subject: objtool: Ignore exc_double_fault() __noreturn warnings This is a hack, but it works for now. Problem is, exc_double_fault() may or may not return, depending on whether CONFIG_X86_ESPFIX64 is set. But objtool has no visibility to the kernel config. "Fix" it by silencing the exc_double_fault() __noreturn warning. This removes the following warning: vmlinux.o: warning: objtool: xenpv_exc_double_fault+0xd: exc_double_fault() is missing a __noreturn annotation Reviewed-by: Miroslav Benes Link: https://lore.kernel.org/r/a45b085071d3a7d049a20f9e78754452336ecbe8.1681853186.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 8d1b4226608c..8dac1e35264e 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4505,6 +4505,35 @@ static int validate_sls(struct objtool_file *file) return warnings; } +static bool ignore_noreturn_call(struct instruction *insn) +{ + struct symbol *call_dest = insn_call_dest(insn); + + /* + * FIXME: hack, we need a real noreturn solution + * + * Problem is, exc_double_fault() may or may not return, depending on + * whether CONFIG_X86_ESPFIX64 is set. But objtool has no visibility + * to the kernel config. + * + * Other potential ways to fix it: + * + * - have compiler communicate __noreturn functions somehow + * - remove CONFIG_X86_ESPFIX64 + * - read the .config file + * - add a cmdline option + * - create a generic objtool annotation format (vs a bunch of custom + * formats) and annotate it + */ + if (!strcmp(call_dest->name, "exc_double_fault")) { + /* prevent further unreachable warnings for the caller */ + insn->sym->warned = 1; + return true; + } + + return false; +} + static int validate_reachable_instructions(struct objtool_file *file) { struct instruction *insn, *prev_insn; @@ -4521,7 +4550,7 @@ static int validate_reachable_instructions(struct objtool_file *file) prev_insn = prev_insn_same_sec(file, insn); if (prev_insn && prev_insn->dead_end) { call_dest = insn_call_dest(prev_insn); - if (call_dest) { + if (call_dest && !ignore_noreturn_call(prev_insn)) { WARN_INSN(insn, "%s() is missing a __noreturn annotation", call_dest->name); warnings++; -- cgit v1.2.3 From 34245659debd194cbd4148d2ee5176306bdf8899 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 18 Apr 2023 14:27:52 -0700 Subject: objtool: Remove superfluous global_noreturns entries lbug_with_loc() no longer exists, and resume_play_dead() is static (objtool only checks globals and weaks). Reviewed-by: Miroslav Benes Link: https://lore.kernel.org/r/2725d7f2ccc2361c6903de9ebaa2b5bb304f7ac2.1681853186.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 8dac1e35264e..8c2762de7ae3 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -217,7 +217,6 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, "kthread_complete_and_exit", "kthread_exit", "kunit_try_catch_throw", - "lbug_with_loc", "machine_real_restart", "make_task_dead", "mpt_halt_firmware", @@ -225,7 +224,6 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, "panic", "panic_smp_self_stop", "rest_init", - "resume_play_dead", "rewind_stack_and_make_dead", "sev_es_terminate", "snp_abort", -- cgit v1.2.3 From 6245ce4ab670166efcdae843c35c14e4c0811aa3 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 18 Apr 2023 14:27:54 -0700 Subject: objtool: Move noreturn function list to separate file This makes it a little cleaner and easier to maintain. Suggested-by: Peter Zijlstra Reviewed-by: Miroslav Benes Link: https://lore.kernel.org/r/cecacf07a69a244c74474c18b7652627de67a528.1681853186.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/Documentation/objtool.txt | 5 ++-- tools/objtool/check.c | 44 +++----------------------------- tools/objtool/noreturns.h | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 44 deletions(-) create mode 100644 tools/objtool/noreturns.h (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/Documentation/objtool.txt b/tools/objtool/Documentation/objtool.txt index f9345e0ce740..fe39c2a8ef0d 100644 --- a/tools/objtool/Documentation/objtool.txt +++ b/tools/objtool/Documentation/objtool.txt @@ -306,9 +306,8 @@ the objtool maintainers. 3. file.o: warning: objtool: foo+0x48c: bar() is missing a __noreturn annotation The call from foo() to bar() doesn't return, but bar() is missing the - __noreturn annotation. NOTE: In addition to adding the __noreturn - annotation, the function name also needs to be added to - 'global_noreturns' in tools/objtool/check.c. + __noreturn annotation. NOTE: In addition to annotating the function + with __noreturn, please also add it to tools/objtool/noreturns.h. 4. file.o: warning: objtool: func(): can't find starting instruction or diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 8c2762de7ae3..a13c257f80dd 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -192,49 +192,11 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, struct instruction *insn; bool empty = true; - /* - * Unfortunately these have to be hard coded because the noreturn - * attribute isn't provided in ELF data. Keep 'em sorted. - */ +#define NORETURN(func) __stringify(func), static const char * const global_noreturns[] = { - "__invalid_creds", - "__module_put_and_kthread_exit", - "__reiserfs_panic", - "__stack_chk_fail", - "__ubsan_handle_builtin_unreachable", - "arch_call_rest_init", - "arch_cpu_idle_dead", - "btrfs_assertfail", - "cpu_bringup_and_idle", - "cpu_startup_entry", - "do_exit", - "do_group_exit", - "do_task_dead", - "ex_handler_msr_mce", - "fortify_panic", - "hlt_play_dead", - "hv_ghcb_terminate", - "kthread_complete_and_exit", - "kthread_exit", - "kunit_try_catch_throw", - "machine_real_restart", - "make_task_dead", - "mpt_halt_firmware", - "nmi_panic_self_stop", - "panic", - "panic_smp_self_stop", - "rest_init", - "rewind_stack_and_make_dead", - "sev_es_terminate", - "snp_abort", - "start_kernel", - "stop_this_cpu", - "usercopy_abort", - "x86_64_start_kernel", - "x86_64_start_reservations", - "xen_cpu_bringup_again", - "xen_start_kernel", +#include "noreturns.h" }; +#undef NORETURN if (!func) return false; diff --git a/tools/objtool/noreturns.h b/tools/objtool/noreturns.h new file mode 100644 index 000000000000..cede6068ddf6 --- /dev/null +++ b/tools/objtool/noreturns.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * This is a (sorted!) list of all known __noreturn functions in the kernel. + * It's needed for objtool to properly reverse-engineer the control flow graph. + * + * Yes, this is unfortunate. A better solution is in the works. + */ +NORETURN(__invalid_creds) +NORETURN(__module_put_and_kthread_exit) +NORETURN(__reiserfs_panic) +NORETURN(__stack_chk_fail) +NORETURN(__ubsan_handle_builtin_unreachable) +NORETURN(arch_call_rest_init) +NORETURN(arch_cpu_idle_dead) +NORETURN(btrfs_assertfail) +NORETURN(cpu_bringup_and_idle) +NORETURN(cpu_startup_entry) +NORETURN(do_exit) +NORETURN(do_group_exit) +NORETURN(do_task_dead) +NORETURN(ex_handler_msr_mce) +NORETURN(fortify_panic) +NORETURN(hlt_play_dead) +NORETURN(hv_ghcb_terminate) +NORETURN(kthread_complete_and_exit) +NORETURN(kthread_exit) +NORETURN(kunit_try_catch_throw) +NORETURN(machine_real_restart) +NORETURN(make_task_dead) +NORETURN(mpt_halt_firmware) +NORETURN(nmi_panic_self_stop) +NORETURN(panic) +NORETURN(panic_smp_self_stop) +NORETURN(rest_init) +NORETURN(rewind_stack_and_make_dead) +NORETURN(sev_es_terminate) +NORETURN(snp_abort) +NORETURN(start_kernel) +NORETURN(stop_this_cpu) +NORETURN(usercopy_abort) +NORETURN(x86_64_start_kernel) +NORETURN(x86_64_start_reservations) +NORETURN(xen_cpu_bringup_again) +NORETURN(xen_start_kernel) -- cgit v1.2.3 From d49d1666aab51ad3caf79f414aff6b641837a6ea Mon Sep 17 00:00:00 2001 From: Lu Hongfei Date: Tue, 30 May 2023 15:56:49 +0800 Subject: tools: Remove unnecessary variables There are several places where warnings variables are not needed, remove them and directly return 0. Signed-off-by: Lu Hongfei Link: https://lore.kernel.org/r/20230530075649.21661-1-luhongfei@vivo.com Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index a13c257f80dd..4b869de7e827 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3799,7 +3799,7 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec) static int validate_unret(struct objtool_file *file, struct instruction *insn) { struct instruction *next, *dest; - int ret, warnings = 0; + int ret; for (;;) { next = next_insn_to_validate(file, insn); @@ -3897,7 +3897,7 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn) insn = next; } - return warnings; + return 0; } /* @@ -4132,7 +4132,6 @@ static int add_prefix_symbols(struct objtool_file *file) { struct section *sec; struct symbol *func; - int warnings = 0; for_each_sec(file, sec) { if (!(sec->sh.sh_flags & SHF_EXECINSTR)) @@ -4146,7 +4145,7 @@ static int add_prefix_symbols(struct objtool_file *file) } } - return warnings; + return 0; } static int validate_symbol(struct objtool_file *file, struct section *sec, -- cgit v1.2.3 From 1e4b619185e83e54aca617cf5070c64a88fe936b Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 5 Jun 2023 09:12:21 -0700 Subject: objtool: Allow stack operations in UNWIND_HINT_UNDEFINED regions If the code specified UNWIND_HINT_UNDEFINED, skip the "undefined stack state" warning due to a stack operation. Just ignore the stack op and continue to propagate the undefined state. Link: https://lore.kernel.org/r/820c5b433f17c84e8761fb7465a8d319d706b1cf.1685981486.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 12 ++++++++++++ tools/objtool/include/objtool/cfi.h | 1 + 2 files changed, 13 insertions(+) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 4b869de7e827..b11c25a715ac 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -33,6 +33,7 @@ static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache; static struct cfi_init_state initial_func_cfi; static struct cfi_state init_cfi; static struct cfi_state func_cfi; +static struct cfi_state force_undefined_cfi; struct instruction *find_insn(struct objtool_file *file, struct section *sec, unsigned long offset) @@ -2240,6 +2241,11 @@ static int read_unwind_hints(struct objtool_file *file) insn->hint = true; + if (hint->type == UNWIND_HINT_TYPE_UNDEFINED) { + insn->cfi = &force_undefined_cfi; + continue; + } + if (hint->type == UNWIND_HINT_TYPE_SAVE) { insn->hint = false; insn->save = true; @@ -2793,6 +2799,10 @@ static int update_cfi_state(struct instruction *insn, struct cfi_reg *cfa = &cfi->cfa; struct cfi_reg *regs = cfi->regs; + /* ignore UNWIND_HINT_UNDEFINED regions */ + if (cfi->force_undefined) + return 0; + /* stack operations don't make sense with an undefined CFA */ if (cfa->base == CFI_UNDEFINED) { if (insn_func(insn)) { @@ -4607,6 +4617,8 @@ int check(struct objtool_file *file) init_cfi_state(&init_cfi); init_cfi_state(&func_cfi); set_func_state(&func_cfi); + init_cfi_state(&force_undefined_cfi); + force_undefined_cfi.force_undefined = true; if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) goto out; diff --git a/tools/objtool/include/objtool/cfi.h b/tools/objtool/include/objtool/cfi.h index b1258e79a1b7..c8a6bec4f6b9 100644 --- a/tools/objtool/include/objtool/cfi.h +++ b/tools/objtool/include/objtool/cfi.h @@ -36,6 +36,7 @@ struct cfi_state { bool drap; bool signal; bool end; + bool force_undefined; }; #endif /* _OBJTOOL_CFI_H */ -- cgit v1.2.3 From 2707579dfa615a5dda4aabb92e433f03a87b5ec5 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:20:54 -0700 Subject: objtool: Remove flags argument from elf_create_section() Simplify the elf_create_section() interface a bit by removing the flags argument. Most callers don't care about changing the section header flags. If needed, they can be modified afterwards, just like any other section header field. Link: https://lore.kernel.org/r/515235d9cf62637a14bee37bfa9169ef20065471.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 17 ++++++++++------- tools/objtool/elf.c | 10 +++++----- tools/objtool/include/objtool/elf.h | 2 +- tools/objtool/orc_gen.c | 4 ++-- 4 files changed, 18 insertions(+), 15 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index b11c25a715ac..eaf681557096 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -677,11 +677,14 @@ static int create_static_call_sections(struct objtool_file *file) list_for_each_entry(insn, &file->static_call_list, call_node) idx++; - sec = elf_create_section(file->elf, ".static_call_sites", SHF_WRITE, + sec = elf_create_section(file->elf, ".static_call_sites", sizeof(struct static_call_site), idx); if (!sec) return -1; + /* Allow modules to set the low bits of static_call_site::key */ + sec->sh.sh_flags |= SHF_WRITE; + idx = 0; list_for_each_entry(insn, &file->static_call_list, call_node) { @@ -763,7 +766,7 @@ static int create_retpoline_sites_sections(struct objtool_file *file) if (!idx) return 0; - sec = elf_create_section(file->elf, ".retpoline_sites", 0, + sec = elf_create_section(file->elf, ".retpoline_sites", sizeof(int), idx); if (!sec) { WARN("elf_create_section: .retpoline_sites"); @@ -809,7 +812,7 @@ static int create_return_sites_sections(struct objtool_file *file) if (!idx) return 0; - sec = elf_create_section(file->elf, ".return_sites", 0, + sec = elf_create_section(file->elf, ".return_sites", sizeof(int), idx); if (!sec) { WARN("elf_create_section: .return_sites"); @@ -861,7 +864,7 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file) if (!idx) return 0; - sec = elf_create_section(file->elf, ".ibt_endbr_seal", 0, + sec = elf_create_section(file->elf, ".ibt_endbr_seal", sizeof(int), idx); if (!sec) { WARN("elf_create_section: .ibt_endbr_seal"); @@ -920,7 +923,7 @@ static int create_cfi_sections(struct objtool_file *file) idx++; } - sec = elf_create_section(file->elf, ".cfi_sites", 0, sizeof(unsigned int), idx); + sec = elf_create_section(file->elf, ".cfi_sites", sizeof(unsigned int), idx); if (!sec) return -1; @@ -968,7 +971,7 @@ static int create_mcount_loc_sections(struct objtool_file *file) list_for_each_entry(insn, &file->mcount_loc_list, call_node) idx++; - sec = elf_create_section(file->elf, "__mcount_loc", 0, addrsize, idx); + sec = elf_create_section(file->elf, "__mcount_loc", addrsize, idx); if (!sec) return -1; @@ -1013,7 +1016,7 @@ static int create_direct_call_sections(struct objtool_file *file) list_for_each_entry(insn, &file->call_list, call_node) idx++; - sec = elf_create_section(file->elf, ".call_sites", 0, sizeof(unsigned int), idx); + sec = elf_create_section(file->elf, ".call_sites", sizeof(unsigned int), idx); if (!sec) return -1; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 500e92979a31..7598c0a2633d 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -1059,7 +1059,7 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str) } struct section *elf_create_section(struct elf *elf, const char *name, - unsigned int sh_flags, size_t entsize, int nr) + size_t entsize, int nr) { struct section *sec, *shstrtab; size_t size = entsize * nr; @@ -1117,7 +1117,7 @@ struct section *elf_create_section(struct elf *elf, const char *name, sec->sh.sh_entsize = entsize; sec->sh.sh_type = SHT_PROGBITS; sec->sh.sh_addralign = 1; - sec->sh.sh_flags = SHF_ALLOC | sh_flags; + sec->sh.sh_flags = SHF_ALLOC; /* Add section name to .shstrtab (or .strtab for Clang) */ shstrtab = find_section_by_name(elf, ".shstrtab"); @@ -1153,7 +1153,7 @@ static struct section *elf_create_rel_reloc_section(struct elf *elf, struct sect strcpy(relocname, ".rel"); strcat(relocname, base->name); - sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0); + sec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0); free(relocname); if (!sec) return NULL; @@ -1185,9 +1185,9 @@ static struct section *elf_create_rela_reloc_section(struct elf *elf, struct sec strcat(relocname, base->name); if (addrsize == sizeof(u32)) - sec = elf_create_section(elf, relocname, 0, sizeof(Elf32_Rela), 0); + sec = elf_create_section(elf, relocname, sizeof(Elf32_Rela), 0); else - sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0); + sec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0); free(relocname); if (!sec) return NULL; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index b24f83e7ca34..2c28aeeb3cb2 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -109,7 +109,7 @@ struct elf { }; struct elf *elf_open_read(const char *name, int flags); -struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr); +struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr); struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size); diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 48efd1e2f00d..d5f750be7d7d 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -237,12 +237,12 @@ int orc_create(struct objtool_file *file) WARN("file already has .orc_unwind section, skipping"); return -1; } - orc_sec = elf_create_section(file->elf, ".orc_unwind", 0, + orc_sec = elf_create_section(file->elf, ".orc_unwind", sizeof(struct orc_entry), nr); if (!orc_sec) return -1; - sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), nr); + sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), nr); if (!sec) return -1; -- cgit v1.2.3 From a5bd623653231bce8657978e9d2c2ebfaf19e297 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:20:55 -0700 Subject: objtool: Improve reloc naming - The term "reloc" is overloaded to mean both "an instance of struct reloc" and "a reloc section". Change the latter to "rsec". - For variable names, use "sec" for regular sections and "rsec" for rela sections to prevent them getting mixed up. - For struct reloc variables, use "reloc" instead of "rel" everywhere for consistency. Link: https://lore.kernel.org/r/8b790e403df46f445c21003e7893b8f53b99a6f3.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 134 ++++++++++++++--------------- tools/objtool/elf.c | 164 ++++++++++++++++++------------------ tools/objtool/include/objtool/elf.h | 2 +- 3 files changed, 151 insertions(+), 149 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index eaf681557096..f4c52a2c8d5b 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -494,7 +494,7 @@ static int add_pv_ops(struct objtool_file *file, const char *symname) { struct symbol *sym, *func; unsigned long off, end; - struct reloc *rel; + struct reloc *reloc; int idx; sym = find_symbol_by_name(file->elf, symname); @@ -504,19 +504,19 @@ static int add_pv_ops(struct objtool_file *file, const char *symname) off = sym->offset; end = off + sym->len; for (;;) { - rel = find_reloc_by_dest_range(file->elf, sym->sec, off, end - off); - if (!rel) + reloc = find_reloc_by_dest_range(file->elf, sym->sec, off, end - off); + if (!reloc) break; - func = rel->sym; + func = reloc->sym; if (func->type == STT_SECTION) - func = find_symbol_by_offset(rel->sym->sec, rel->addend); + func = find_symbol_by_offset(reloc->sym->sec, reloc->addend); - idx = (rel->offset - sym->offset) / sizeof(unsigned long); + idx = (reloc->offset - sym->offset) / sizeof(unsigned long); objtool_pv_add(file, idx, func); - off = rel->offset + 1; + off = reloc->offset + 1; if (off > end) break; } @@ -581,20 +581,20 @@ static struct instruction *find_last_insn(struct objtool_file *file, */ static int add_dead_ends(struct objtool_file *file) { - struct section *sec; + struct section *rsec; struct reloc *reloc; struct instruction *insn; /* * Check for manually annotated dead ends. */ - sec = find_section_by_name(file->elf, ".rela.discard.unreachable"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.unreachable"); + if (!rsec) goto reachable; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { if (reloc->sym->type != STT_SECTION) { - WARN("unexpected relocation symbol type in %s", sec->name); + WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } insn = find_insn(file, reloc->sym->sec, reloc->addend); @@ -623,13 +623,13 @@ reachable: * GCC doesn't know the "ud2" is fatal, so it generates code as if it's * not a dead end. */ - sec = find_section_by_name(file->elf, ".rela.discard.reachable"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.reachable"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { if (reloc->sym->type != STT_SECTION) { - WARN("unexpected relocation symbol type in %s", sec->name); + WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } insn = find_insn(file, reloc->sym->sec, reloc->addend); @@ -1044,15 +1044,15 @@ static int create_direct_call_sections(struct objtool_file *file) static void add_ignores(struct objtool_file *file) { struct instruction *insn; - struct section *sec; + struct section *rsec; struct symbol *func; struct reloc *reloc; - sec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard"); + if (!rsec) return; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { switch (reloc->sym->type) { case STT_FUNC: func = reloc->sym; @@ -1065,7 +1065,8 @@ static void add_ignores(struct objtool_file *file) break; default: - WARN("unexpected relocation symbol type in %s: %d", sec->name, reloc->sym->type); + WARN("unexpected relocation symbol type in %s: %d", + rsec->name, reloc->sym->type); continue; } @@ -1284,17 +1285,17 @@ static void add_uaccess_safe(struct objtool_file *file) */ static int add_ignore_alternatives(struct objtool_file *file) { - struct section *sec; + struct section *rsec; struct reloc *reloc; struct instruction *insn; - sec = find_section_by_name(file->elf, ".rela.discard.ignore_alts"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.ignore_alts"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { if (reloc->sym->type != STT_SECTION) { - WARN("unexpected relocation symbol type in %s", sec->name); + WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } @@ -2204,7 +2205,7 @@ static void set_func_state(struct cfi_state *state) static int read_unwind_hints(struct objtool_file *file) { struct cfi_state cfi = init_cfi; - struct section *sec, *relocsec; + struct section *sec; struct unwind_hint *hint; struct instruction *insn; struct reloc *reloc; @@ -2214,8 +2215,7 @@ static int read_unwind_hints(struct objtool_file *file) if (!sec) return 0; - relocsec = sec->reloc; - if (!relocsec) { + if (!sec->rsec) { WARN("missing .rela.discard.unwind_hints section"); return -1; } @@ -2295,15 +2295,15 @@ static int read_unwind_hints(struct objtool_file *file) static int read_noendbr_hints(struct objtool_file *file) { - struct section *sec; struct instruction *insn; + struct section *rsec; struct reloc *reloc; - sec = find_section_by_name(file->elf, ".rela.discard.noendbr"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.noendbr"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { insn = find_insn(file, reloc->sym->sec, reloc->sym->offset + reloc->addend); if (!insn) { WARN("bad .discard.noendbr entry"); @@ -2318,17 +2318,17 @@ static int read_noendbr_hints(struct objtool_file *file) static int read_retpoline_hints(struct objtool_file *file) { - struct section *sec; + struct section *rsec; struct instruction *insn; struct reloc *reloc; - sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { if (reloc->sym->type != STT_SECTION) { - WARN("unexpected relocation symbol type in %s", sec->name); + WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } @@ -2354,17 +2354,17 @@ static int read_retpoline_hints(struct objtool_file *file) static int read_instr_hints(struct objtool_file *file) { - struct section *sec; + struct section *rsec; struct instruction *insn; struct reloc *reloc; - sec = find_section_by_name(file->elf, ".rela.discard.instr_end"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.instr_end"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { if (reloc->sym->type != STT_SECTION) { - WARN("unexpected relocation symbol type in %s", sec->name); + WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } @@ -2377,13 +2377,13 @@ static int read_instr_hints(struct objtool_file *file) insn->instr--; } - sec = find_section_by_name(file->elf, ".rela.discard.instr_begin"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.instr_begin"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { if (reloc->sym->type != STT_SECTION) { - WARN("unexpected relocation symbol type in %s", sec->name); + WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } @@ -2401,17 +2401,17 @@ static int read_instr_hints(struct objtool_file *file) static int read_validate_unret_hints(struct objtool_file *file) { - struct section *sec; + struct section *rsec; struct instruction *insn; struct reloc *reloc; - sec = find_section_by_name(file->elf, ".rela.discard.validate_unret"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.validate_unret"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { if (reloc->sym->type != STT_SECTION) { - WARN("unexpected relocation symbol type in %s", sec->name); + WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } @@ -2430,19 +2430,19 @@ static int read_validate_unret_hints(struct objtool_file *file) static int read_intra_function_calls(struct objtool_file *file) { struct instruction *insn; - struct section *sec; + struct section *rsec; struct reloc *reloc; - sec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls"); - if (!sec) + rsec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls"); + if (!rsec) return 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { unsigned long dest_off; if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", - sec->name); + rsec->name); return -1; } @@ -3342,15 +3342,15 @@ static inline bool func_uaccess_safe(struct symbol *func) static inline const char *call_dest_name(struct instruction *insn) { static char pvname[19]; - struct reloc *rel; + struct reloc *reloc; int idx; if (insn_call_dest(insn)) return insn_call_dest(insn)->name; - rel = insn_reloc(NULL, insn); - if (rel && !strcmp(rel->sym->name, "pv_ops")) { - idx = (rel->addend / sizeof(void *)); + reloc = insn_reloc(NULL, insn); + if (reloc && !strcmp(reloc->sym->name, "pv_ops")) { + idx = (reloc->addend / sizeof(void *)); snprintf(pvname, sizeof(pvname), "pv_ops[%d]", idx); return pvname; } @@ -3361,14 +3361,14 @@ static inline const char *call_dest_name(struct instruction *insn) static bool pv_call_dest(struct objtool_file *file, struct instruction *insn) { struct symbol *target; - struct reloc *rel; + struct reloc *reloc; int idx; - rel = insn_reloc(file, insn); - if (!rel || strcmp(rel->sym->name, "pv_ops")) + reloc = insn_reloc(file, insn); + if (!reloc || strcmp(reloc->sym->name, "pv_ops")) return false; - idx = (arch_dest_reloc_offset(rel->addend) / sizeof(void *)); + idx = (arch_dest_reloc_offset(reloc->addend) / sizeof(void *)); if (file->pv_ops[idx].clean) return true; @@ -4410,7 +4410,7 @@ static int validate_ibt(struct objtool_file *file) if (sec->sh.sh_flags & SHF_EXECINSTR) continue; - if (!sec->reloc) + if (!sec->rsec) continue; /* @@ -4437,7 +4437,7 @@ static int validate_ibt(struct objtool_file *file) strstr(sec->name, "__patchable_function_entries")) continue; - list_for_each_entry(reloc, &sec->reloc->reloc_list, list) + list_for_each_entry(reloc, &sec->rsec->reloc_list, list) warnings += validate_ibt_data_reloc(file, reloc); } diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 7598c0a2633d..86ae62dfdba2 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -233,17 +233,17 @@ struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *se unsigned long offset, unsigned int len) { struct reloc *reloc, *r = NULL; + struct section *rsec; unsigned long o; - if (!sec->reloc) + rsec = sec->rsec; + if (!rsec) return NULL; - sec = sec->reloc; - for_offset_range(o, offset, offset + len) { elf_hash_for_each_possible(reloc, reloc, hash, - sec_offset_hash(sec, o)) { - if (reloc->sec != sec) + sec_offset_hash(rsec, o)) { + if (reloc->sec != rsec) continue; if (reloc->offset >= offset && reloc->offset < offset + len) { @@ -534,7 +534,7 @@ err: } static struct section *elf_create_reloc_section(struct elf *elf, - struct section *base, + struct section *sec, int reltype); int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, @@ -542,7 +542,7 @@ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, { struct reloc *reloc; - if (!sec->reloc && !elf_create_reloc_section(elf, sec, SHT_RELA)) + if (!sec->rsec && !elf_create_reloc_section(elf, sec, SHT_RELA)) return -1; reloc = malloc(sizeof(*reloc)); @@ -552,18 +552,18 @@ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, } memset(reloc, 0, sizeof(*reloc)); - reloc->sec = sec->reloc; + reloc->sec = sec->rsec; reloc->offset = offset; reloc->type = type; reloc->sym = sym; reloc->addend = addend; list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list); - list_add_tail(&reloc->list, &sec->reloc->reloc_list); + list_add_tail(&reloc->list, &sec->rsec->reloc_list); elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); - sec->reloc->sh.sh_size += sec->reloc->sh.sh_entsize; - sec->reloc->changed = true; + sec->rsec->sh.sh_size += sec->rsec->sh.sh_entsize; + sec->rsec->changed = true; return 0; } @@ -865,9 +865,9 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, return elf_add_reloc(elf, sec, offset, type, sym, addend); } -static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx) +static int read_rel_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx) { - if (!gelf_getrel(sec->data, i, &reloc->rel)) { + if (!gelf_getrel(rsec->data, i, &reloc->rel)) { WARN_ELF("gelf_getrel"); return -1; } @@ -878,9 +878,9 @@ static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsig return 0; } -static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx) +static int read_rela_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx) { - if (!gelf_getrela(sec->data, i, &reloc->rela)) { + if (!gelf_getrela(rsec->data, i, &reloc->rela)) { WARN_ELF("gelf_getrela"); return -1; } @@ -894,7 +894,7 @@ static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsi static int read_relocs(struct elf *elf) { unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0; - struct section *sec; + struct section *rsec; struct reloc *reloc; unsigned int symndx; struct symbol *sym; @@ -903,51 +903,52 @@ static int read_relocs(struct elf *elf) if (!elf_alloc_hash(reloc, elf->text_size / 16)) return -1; - list_for_each_entry(sec, &elf->sections, list) { - if ((sec->sh.sh_type != SHT_RELA) && - (sec->sh.sh_type != SHT_REL)) + list_for_each_entry(rsec, &elf->sections, list) { + if ((rsec->sh.sh_type != SHT_RELA) && + (rsec->sh.sh_type != SHT_REL)) continue; - sec->base = find_section_by_index(elf, sec->sh.sh_info); - if (!sec->base) { + rsec->base = find_section_by_index(elf, rsec->sh.sh_info); + if (!rsec->base) { WARN("can't find base section for reloc section %s", - sec->name); + rsec->name); return -1; } - sec->base->reloc = sec; + rsec->base->rsec = rsec; nr_reloc = 0; - sec->reloc_data = calloc(sec->sh.sh_size / sec->sh.sh_entsize, sizeof(*reloc)); - if (!sec->reloc_data) { + rsec->reloc_data = calloc(rsec->sh.sh_size / rsec->sh.sh_entsize, + sizeof(*reloc)); + if (!rsec->reloc_data) { perror("calloc"); return -1; } - for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { - reloc = &sec->reloc_data[i]; - switch (sec->sh.sh_type) { + for (i = 0; i < rsec->sh.sh_size / rsec->sh.sh_entsize; i++) { + reloc = &rsec->reloc_data[i]; + switch (rsec->sh.sh_type) { case SHT_REL: - if (read_rel_reloc(sec, i, reloc, &symndx)) + if (read_rel_reloc(rsec, i, reloc, &symndx)) return -1; break; case SHT_RELA: - if (read_rela_reloc(sec, i, reloc, &symndx)) + if (read_rela_reloc(rsec, i, reloc, &symndx)) return -1; break; default: return -1; } - reloc->sec = sec; + reloc->sec = rsec; reloc->idx = i; reloc->sym = sym = find_symbol_by_index(elf, symndx); if (!reloc->sym) { WARN("can't find reloc entry symbol %d for %s", - symndx, sec->name); + symndx, rsec->name); return -1; } list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list); - list_add_tail(&reloc->list, &sec->reloc_list); + list_add_tail(&reloc->list, &rsec->reloc_list); elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); nr_reloc++; @@ -1140,40 +1141,41 @@ struct section *elf_create_section(struct elf *elf, const char *name, return sec; } -static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base) +static struct section *elf_create_rel_reloc_section(struct elf *elf, + struct section *sec) { char *relocname; - struct section *sec; + struct section *rsec; - relocname = malloc(strlen(base->name) + strlen(".rel") + 1); + relocname = malloc(strlen(sec->name) + strlen(".rel") + 1); if (!relocname) { perror("malloc"); return NULL; } strcpy(relocname, ".rel"); - strcat(relocname, base->name); + strcat(relocname, sec->name); - sec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0); + rsec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0); free(relocname); - if (!sec) + if (!rsec) return NULL; - base->reloc = sec; - sec->base = base; + sec->rsec = rsec; + rsec->base = sec; - sec->sh.sh_type = SHT_REL; - sec->sh.sh_addralign = 8; - sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; - sec->sh.sh_info = base->idx; - sec->sh.sh_flags = SHF_INFO_LINK; + rsec->sh.sh_type = SHT_REL; + rsec->sh.sh_addralign = 8; + rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; + rsec->sh.sh_info = sec->idx; + rsec->sh.sh_flags = SHF_INFO_LINK; - return sec; + return rsec; } static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base) { char *relocname; - struct section *sec; + struct section *rsec; int addrsize = elf_class_addrsize(elf); relocname = malloc(strlen(base->name) + strlen(".rela") + 1); @@ -1185,23 +1187,23 @@ static struct section *elf_create_rela_reloc_section(struct elf *elf, struct sec strcat(relocname, base->name); if (addrsize == sizeof(u32)) - sec = elf_create_section(elf, relocname, sizeof(Elf32_Rela), 0); + rsec = elf_create_section(elf, relocname, sizeof(Elf32_Rela), 0); else - sec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0); + rsec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0); free(relocname); - if (!sec) + if (!rsec) return NULL; - base->reloc = sec; - sec->base = base; + base->rsec = rsec; + rsec->base = base; - sec->sh.sh_type = SHT_RELA; - sec->sh.sh_addralign = addrsize; - sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; - sec->sh.sh_info = base->idx; - sec->sh.sh_flags = SHF_INFO_LINK; + rsec->sh.sh_type = SHT_RELA; + rsec->sh.sh_addralign = addrsize; + rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; + rsec->sh.sh_info = base->idx; + rsec->sh.sh_flags = SHF_INFO_LINK; - return sec; + return rsec; } static struct section *elf_create_reloc_section(struct elf *elf, @@ -1215,28 +1217,28 @@ static struct section *elf_create_reloc_section(struct elf *elf, } } -static int elf_rebuild_rel_reloc_section(struct section *sec) +static int elf_rebuild_rel_reloc_section(struct section *rsec) { struct reloc *reloc; int idx = 0; void *buf; /* Allocate a buffer for relocations */ - buf = malloc(sec->sh.sh_size); + buf = malloc(rsec->sh.sh_size); if (!buf) { perror("malloc"); return -1; } - sec->data->d_buf = buf; - sec->data->d_size = sec->sh.sh_size; - sec->data->d_type = ELF_T_REL; + rsec->data->d_buf = buf; + rsec->data->d_size = rsec->sh.sh_size; + rsec->data->d_type = ELF_T_REL; idx = 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { reloc->rel.r_offset = reloc->offset; reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - if (!gelf_update_rel(sec->data, idx, &reloc->rel)) { + if (!gelf_update_rel(rsec->data, idx, &reloc->rel)) { WARN_ELF("gelf_update_rel"); return -1; } @@ -1246,29 +1248,29 @@ static int elf_rebuild_rel_reloc_section(struct section *sec) return 0; } -static int elf_rebuild_rela_reloc_section(struct section *sec) +static int elf_rebuild_rela_reloc_section(struct section *rsec) { struct reloc *reloc; int idx = 0; void *buf; /* Allocate a buffer for relocations with addends */ - buf = malloc(sec->sh.sh_size); + buf = malloc(rsec->sh.sh_size); if (!buf) { perror("malloc"); return -1; } - sec->data->d_buf = buf; - sec->data->d_size = sec->sh.sh_size; - sec->data->d_type = ELF_T_RELA; + rsec->data->d_buf = buf; + rsec->data->d_size = rsec->sh.sh_size; + rsec->data->d_type = ELF_T_RELA; idx = 0; - list_for_each_entry(reloc, &sec->reloc_list, list) { + list_for_each_entry(reloc, &rsec->reloc_list, list) { reloc->rela.r_offset = reloc->offset; reloc->rela.r_addend = reloc->addend; reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - if (!gelf_update_rela(sec->data, idx, &reloc->rela)) { + if (!gelf_update_rela(rsec->data, idx, &reloc->rela)) { WARN_ELF("gelf_update_rela"); return -1; } @@ -1278,11 +1280,11 @@ static int elf_rebuild_rela_reloc_section(struct section *sec) return 0; } -static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec) +static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec) { - switch (sec->sh.sh_type) { - case SHT_REL: return elf_rebuild_rel_reloc_section(sec); - case SHT_RELA: return elf_rebuild_rela_reloc_section(sec); + switch (rsec->sh.sh_type) { + case SHT_REL: return elf_rebuild_rel_reloc_section(rsec); + case SHT_RELA: return elf_rebuild_rela_reloc_section(rsec); default: return -1; } } @@ -1308,13 +1310,13 @@ int elf_write_insn(struct elf *elf, struct section *sec, int elf_write_reloc(struct elf *elf, struct reloc *reloc) { - struct section *sec = reloc->sec; + struct section *rsec = reloc->sec; - if (sec->sh.sh_type == SHT_REL) { + if (rsec->sh.sh_type == SHT_REL) { reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); reloc->rel.r_offset = reloc->offset; - if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) { + if (!gelf_update_rel(rsec->data, reloc->idx, &reloc->rel)) { WARN_ELF("gelf_update_rel"); return -1; } @@ -1323,7 +1325,7 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc) reloc->rela.r_addend = reloc->addend; reloc->rela.r_offset = reloc->offset; - if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) { + if (!gelf_update_rela(rsec->data, reloc->idx, &reloc->rela)) { WARN_ELF("gelf_update_rela"); return -1; } diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 2c28aeeb3cb2..a4e43a69f922 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -33,7 +33,7 @@ struct section { struct rb_root_cached symbol_tree; struct list_head symbol_list; struct list_head reloc_list; - struct section *base, *reloc; + struct section *base, *rsec; struct symbol *sym; Elf_Data *data; char *name; -- cgit v1.2.3 From 53257a977a69b5eabbaafb64dcd767d2a4fef2b3 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:20:56 -0700 Subject: objtool: Consolidate rel/rela handling The GElf_Rel[a] structs have more similarities than differences. It's safe to hard-code the assumptions about their shared fields as they will never change. Consolidate their handling where possible, getting rid of duplicated code. Also, at least for now we only ever create rela sections, so simplify the relocation creation code to be rela-only. Link: https://lore.kernel.org/r/dcabf6df400ca500ea929f1e4284f5e5ec0b27c8.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 12 +-- tools/objtool/elf.c | 202 ++++++++++-------------------------- tools/objtool/include/objtool/elf.h | 13 ++- 3 files changed, 68 insertions(+), 159 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f4c52a2c8d5b..2ab8699bbd76 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -952,7 +952,7 @@ static int create_cfi_sections(struct objtool_file *file) static int create_mcount_loc_sections(struct objtool_file *file) { - int addrsize = elf_class_addrsize(file->elf); + size_t addr_size = elf_addr_size(file->elf); struct instruction *insn; struct section *sec; int idx; @@ -971,25 +971,25 @@ static int create_mcount_loc_sections(struct objtool_file *file) list_for_each_entry(insn, &file->mcount_loc_list, call_node) idx++; - sec = elf_create_section(file->elf, "__mcount_loc", addrsize, idx); + sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx); if (!sec) return -1; - sec->sh.sh_addralign = addrsize; + sec->sh.sh_addralign = addr_size; idx = 0; list_for_each_entry(insn, &file->mcount_loc_list, call_node) { void *loc; loc = sec->data->d_buf + idx; - memset(loc, 0, addrsize); + memset(loc, 0, addr_size); if (elf_add_reloc_to_insn(file->elf, sec, idx, - addrsize == sizeof(u64) ? R_ABS64 : R_ABS32, + addr_size == sizeof(u64) ? R_ABS64 : R_ABS32, insn->sec, insn->offset)) return -1; - idx += addrsize; + idx += addr_size; } return 0; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 86ae62dfdba2..4bbdd8e6df2c 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -533,16 +533,15 @@ err: return -1; } -static struct section *elf_create_reloc_section(struct elf *elf, - struct section *sec, - int reltype); +static struct section *elf_create_rela_section(struct elf *elf, + struct section *sec); int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, unsigned int type, struct symbol *sym, s64 addend) { struct reloc *reloc; - if (!sec->rsec && !elf_create_reloc_section(elf, sec, SHT_RELA)) + if (!sec->rsec && !elf_create_rela_section(elf, sec)) return -1; reloc = malloc(sizeof(*reloc)); @@ -865,29 +864,25 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, return elf_add_reloc(elf, sec, offset, type, sym, addend); } -static int read_rel_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx) +static int read_reloc(struct section *rsec, int i, struct reloc *reloc) { - if (!gelf_getrel(rsec->data, i, &reloc->rel)) { - WARN_ELF("gelf_getrel"); - return -1; - } - reloc->type = GELF_R_TYPE(reloc->rel.r_info); - reloc->addend = 0; - reloc->offset = reloc->rel.r_offset; - *symndx = GELF_R_SYM(reloc->rel.r_info); - return 0; -} + bool rela = rsec->sh.sh_type == SHT_RELA; + void *retp; -static int read_rela_reloc(struct section *rsec, int i, struct reloc *reloc, unsigned int *symndx) -{ - if (!gelf_getrela(rsec->data, i, &reloc->rela)) { + if (rela) + retp = gelf_getrela(rsec->data, i, &reloc->rela); + else + retp = gelf_getrel(rsec->data, i, &reloc->rel); + + if (!retp) { WARN_ELF("gelf_getrela"); return -1; } - reloc->type = GELF_R_TYPE(reloc->rela.r_info); - reloc->addend = reloc->rela.r_addend; - reloc->offset = reloc->rela.r_offset; - *symndx = GELF_R_SYM(reloc->rela.r_info); + + reloc->offset = reloc->rel.r_offset; + reloc->type = GELF_R_TYPE(reloc->rel.r_info); + reloc->addend = rela ? reloc->rela.r_addend : 0; + return 0; } @@ -926,20 +921,13 @@ static int read_relocs(struct elf *elf) } for (i = 0; i < rsec->sh.sh_size / rsec->sh.sh_entsize; i++) { reloc = &rsec->reloc_data[i]; - switch (rsec->sh.sh_type) { - case SHT_REL: - if (read_rel_reloc(rsec, i, reloc, &symndx)) - return -1; - break; - case SHT_RELA: - if (read_rela_reloc(rsec, i, reloc, &symndx)) - return -1; - break; - default: return -1; - } + + if (read_reloc(rsec, i, reloc)) + return -1; reloc->sec = rsec; reloc->idx = i; + symndx = GELF_R_SYM(reloc->rel.r_info); reloc->sym = sym = find_symbol_by_index(elf, symndx); if (!reloc->sym) { WARN("can't find reloc entry symbol %d for %s", @@ -1141,86 +1129,42 @@ struct section *elf_create_section(struct elf *elf, const char *name, return sec; } -static struct section *elf_create_rel_reloc_section(struct elf *elf, - struct section *sec) +static struct section *elf_create_rela_section(struct elf *elf, + struct section *sec) { - char *relocname; struct section *rsec; + char *rsec_name; - relocname = malloc(strlen(sec->name) + strlen(".rel") + 1); - if (!relocname) { + rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1); + if (!rsec_name) { perror("malloc"); return NULL; } - strcpy(relocname, ".rel"); - strcat(relocname, sec->name); + strcpy(rsec_name, ".rela"); + strcat(rsec_name, sec->name); - rsec = elf_create_section(elf, relocname, sizeof(GElf_Rel), 0); - free(relocname); + rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0); + free(rsec_name); if (!rsec) return NULL; sec->rsec = rsec; rsec->base = sec; - rsec->sh.sh_type = SHT_REL; - rsec->sh.sh_addralign = 8; - rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; - rsec->sh.sh_info = sec->idx; - rsec->sh.sh_flags = SHF_INFO_LINK; - - return rsec; -} - -static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base) -{ - char *relocname; - struct section *rsec; - int addrsize = elf_class_addrsize(elf); - - relocname = malloc(strlen(base->name) + strlen(".rela") + 1); - if (!relocname) { - perror("malloc"); - return NULL; - } - strcpy(relocname, ".rela"); - strcat(relocname, base->name); - - if (addrsize == sizeof(u32)) - rsec = elf_create_section(elf, relocname, sizeof(Elf32_Rela), 0); - else - rsec = elf_create_section(elf, relocname, sizeof(GElf_Rela), 0); - free(relocname); - if (!rsec) - return NULL; - - base->rsec = rsec; - rsec->base = base; - rsec->sh.sh_type = SHT_RELA; - rsec->sh.sh_addralign = addrsize; + rsec->sh.sh_addralign = elf_addr_size(elf); rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; - rsec->sh.sh_info = base->idx; + rsec->sh.sh_info = sec->idx; rsec->sh.sh_flags = SHF_INFO_LINK; return rsec; } -static struct section *elf_create_reloc_section(struct elf *elf, - struct section *base, - int reltype) -{ - switch (reltype) { - case SHT_REL: return elf_create_rel_reloc_section(elf, base); - case SHT_RELA: return elf_create_rela_reloc_section(elf, base); - default: return NULL; - } -} - -static int elf_rebuild_rel_reloc_section(struct section *rsec) +static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec) { + bool rela = rsec->sh.sh_type == SHT_RELA; struct reloc *reloc; - int idx = 0; + int idx = 0, ret; void *buf; /* Allocate a buffer for relocations */ @@ -1232,46 +1176,20 @@ static int elf_rebuild_rel_reloc_section(struct section *rsec) rsec->data->d_buf = buf; rsec->data->d_size = rsec->sh.sh_size; - rsec->data->d_type = ELF_T_REL; + rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL; idx = 0; list_for_each_entry(reloc, &rsec->reloc_list, list) { reloc->rel.r_offset = reloc->offset; reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - if (!gelf_update_rel(rsec->data, idx, &reloc->rel)) { - WARN_ELF("gelf_update_rel"); - return -1; + if (rela) { + reloc->rela.r_addend = reloc->addend; + ret = gelf_update_rela(rsec->data, idx, &reloc->rela); + } else { + ret = gelf_update_rel(rsec->data, idx, &reloc->rel); } - idx++; - } - - return 0; -} - -static int elf_rebuild_rela_reloc_section(struct section *rsec) -{ - struct reloc *reloc; - int idx = 0; - void *buf; - - /* Allocate a buffer for relocations with addends */ - buf = malloc(rsec->sh.sh_size); - if (!buf) { - perror("malloc"); - return -1; - } - - rsec->data->d_buf = buf; - rsec->data->d_size = rsec->sh.sh_size; - rsec->data->d_type = ELF_T_RELA; - - idx = 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { - reloc->rela.r_offset = reloc->offset; - reloc->rela.r_addend = reloc->addend; - reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - if (!gelf_update_rela(rsec->data, idx, &reloc->rela)) { - WARN_ELF("gelf_update_rela"); + if (!ret) { + WARN_ELF("gelf_update_rel"); return -1; } idx++; @@ -1280,15 +1198,6 @@ static int elf_rebuild_rela_reloc_section(struct section *rsec) return 0; } -static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec) -{ - switch (rsec->sh.sh_type) { - case SHT_REL: return elf_rebuild_rel_reloc_section(rsec); - case SHT_RELA: return elf_rebuild_rela_reloc_section(rsec); - default: return -1; - } -} - int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset, unsigned int len, const char *insn) @@ -1311,24 +1220,21 @@ int elf_write_insn(struct elf *elf, struct section *sec, int elf_write_reloc(struct elf *elf, struct reloc *reloc) { struct section *rsec = reloc->sec; + int ret; - if (rsec->sh.sh_type == SHT_REL) { - reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - reloc->rel.r_offset = reloc->offset; + reloc->rel.r_offset = reloc->offset; + reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - if (!gelf_update_rel(rsec->data, reloc->idx, &reloc->rel)) { - WARN_ELF("gelf_update_rel"); - return -1; - } - } else { - reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); + if (rsec->sh.sh_type == SHT_RELA) { reloc->rela.r_addend = reloc->addend; - reloc->rela.r_offset = reloc->offset; + ret = gelf_update_rela(rsec->data, reloc->idx, &reloc->rela); + } else { + ret = gelf_update_rel(rsec->data, reloc->idx, &reloc->rel); + } - if (!gelf_update_rela(rsec->data, reloc->idx, &reloc->rela)) { - WARN_ELF("gelf_update_rela"); - return -1; - } + if (!ret) { + WARN_ELF("gelf_update_rela"); + return -1; } elf->changed = true; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index a4e43a69f922..6f82f2515d6b 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef LIBELF_USE_DEPRECATED # define elf_getshdrnum elf_getshnum @@ -147,12 +148,14 @@ static inline bool has_multiple_files(struct elf *elf) return elf->num_files > 1; } -static inline int elf_class_addrsize(struct elf *elf) +static inline size_t elf_addr_size(struct elf *elf) { - if (elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32) - return sizeof(u32); - else - return sizeof(u64); + return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; +} + +static inline size_t elf_rela_size(struct elf *elf) +{ + return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela); } #define for_each_sec(file, sec) \ -- cgit v1.2.3 From 6342a20efbd8b70d169c325b2c27a8a8f96388d5 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:20:59 -0700 Subject: objtool: Add elf_create_section_pair() When creating an annotation section, allocate the reloc section data at the beginning. This simplifies the data model a bit and also saves memory due to the removal of malloc() in elf_rebuild_reloc_section(). With allyesconfig + CONFIG_DEBUG_INFO: - Before: peak heap memory consumption: 53.49G - After: peak heap memory consumption: 49.02G Link: https://lore.kernel.org/r/048e908f3ede9b66c15e44672b6dda992b1dae3e.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/powerpc/include/arch/elf.h | 11 +- tools/objtool/arch/x86/include/arch/elf.h | 11 +- tools/objtool/check.c | 129 ++++++++-------------- tools/objtool/elf.c | 151 ++++++++++++++++---------- tools/objtool/include/objtool/elf.h | 33 +++++- tools/objtool/orc_gen.c | 6 +- 6 files changed, 184 insertions(+), 157 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/arch/powerpc/include/arch/elf.h b/tools/objtool/arch/powerpc/include/arch/elf.h index 73f9ae172fe5..66814fa28024 100644 --- a/tools/objtool/arch/powerpc/include/arch/elf.h +++ b/tools/objtool/arch/powerpc/include/arch/elf.h @@ -1,10 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ - #ifndef _OBJTOOL_ARCH_ELF #define _OBJTOOL_ARCH_ELF -#define R_NONE R_PPC_NONE -#define R_ABS64 R_PPC64_ADDR64 -#define R_ABS32 R_PPC_ADDR32 +#define R_NONE R_PPC_NONE +#define R_ABS64 R_PPC64_ADDR64 +#define R_ABS32 R_PPC_ADDR32 +#define R_DATA32 R_PPC_REL32 +#define R_DATA64 R_PPC64_REL64 +#define R_TEXT32 R_PPC_REL32 +#define R_TEXT64 R_PPC64_REL32 #endif /* _OBJTOOL_ARCH_ELF */ diff --git a/tools/objtool/arch/x86/include/arch/elf.h b/tools/objtool/arch/x86/include/arch/elf.h index ac14987cf687..7131f7f51a4e 100644 --- a/tools/objtool/arch/x86/include/arch/elf.h +++ b/tools/objtool/arch/x86/include/arch/elf.h @@ -1,8 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef _OBJTOOL_ARCH_ELF #define _OBJTOOL_ARCH_ELF -#define R_NONE R_X86_64_NONE -#define R_ABS64 R_X86_64_64 -#define R_ABS32 R_X86_64_32 +#define R_NONE R_X86_64_NONE +#define R_ABS32 R_X86_64_32 +#define R_ABS64 R_X86_64_64 +#define R_DATA32 R_X86_64_PC32 +#define R_DATA64 R_X86_64_PC32 +#define R_TEXT32 R_X86_64_PC32 +#define R_TEXT64 R_X86_64_PC32 #endif /* _OBJTOOL_ARCH_ELF */ diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 2ab8699bbd76..3bc97c2b4f01 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -656,8 +655,8 @@ reachable: static int create_static_call_sections(struct objtool_file *file) { - struct section *sec; struct static_call_site *site; + struct section *sec; struct instruction *insn; struct symbol *key_sym; char *key_name, *tmp; @@ -677,25 +676,21 @@ static int create_static_call_sections(struct objtool_file *file) list_for_each_entry(insn, &file->static_call_list, call_node) idx++; - sec = elf_create_section(file->elf, ".static_call_sites", - sizeof(struct static_call_site), idx); + sec = elf_create_section_pair(file->elf, ".static_call_sites", + sizeof(*site), idx, idx * 2); if (!sec) return -1; - /* Allow modules to set the low bits of static_call_site::key */ + /* Allow modules to modify the low bits of static_call_site::key */ sec->sh.sh_flags |= SHF_WRITE; idx = 0; list_for_each_entry(insn, &file->static_call_list, call_node) { - site = (struct static_call_site *)sec->data->d_buf + idx; - memset(site, 0, sizeof(struct static_call_site)); - /* populate reloc for 'addr' */ - if (elf_add_reloc_to_insn(file->elf, sec, - idx * sizeof(struct static_call_site), - R_X86_64_PC32, - insn->sec, insn->offset)) + if (!elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(*site), idx * 2, + insn->sec, insn->offset)) return -1; /* find key symbol */ @@ -735,10 +730,10 @@ static int create_static_call_sections(struct objtool_file *file) free(key_name); /* populate reloc for 'key' */ - if (elf_add_reloc(file->elf, sec, - idx * sizeof(struct static_call_site) + 4, - R_X86_64_PC32, key_sym, - is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) + if (!elf_init_reloc_data_sym(file->elf, sec, + idx * sizeof(*site) + 4, + (idx * 2) + 1, key_sym, + is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) return -1; idx++; @@ -766,26 +761,18 @@ static int create_retpoline_sites_sections(struct objtool_file *file) if (!idx) return 0; - sec = elf_create_section(file->elf, ".retpoline_sites", - sizeof(int), idx); - if (!sec) { - WARN("elf_create_section: .retpoline_sites"); + sec = elf_create_section_pair(file->elf, ".retpoline_sites", + sizeof(int), idx, idx); + if (!sec) return -1; - } idx = 0; list_for_each_entry(insn, &file->retpoline_call_list, call_node) { - int *site = (int *)sec->data->d_buf + idx; - *site = 0; - - if (elf_add_reloc_to_insn(file->elf, sec, - idx * sizeof(int), - R_X86_64_PC32, - insn->sec, insn->offset)) { - WARN("elf_add_reloc_to_insn: .retpoline_sites"); + if (!elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(int), idx, + insn->sec, insn->offset)) return -1; - } idx++; } @@ -812,26 +799,18 @@ static int create_return_sites_sections(struct objtool_file *file) if (!idx) return 0; - sec = elf_create_section(file->elf, ".return_sites", - sizeof(int), idx); - if (!sec) { - WARN("elf_create_section: .return_sites"); + sec = elf_create_section_pair(file->elf, ".return_sites", + sizeof(int), idx, idx); + if (!sec) return -1; - } idx = 0; list_for_each_entry(insn, &file->return_thunk_list, call_node) { - int *site = (int *)sec->data->d_buf + idx; - *site = 0; - - if (elf_add_reloc_to_insn(file->elf, sec, - idx * sizeof(int), - R_X86_64_PC32, - insn->sec, insn->offset)) { - WARN("elf_add_reloc_to_insn: .return_sites"); + if (!elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(int), idx, + insn->sec, insn->offset)) return -1; - } idx++; } @@ -864,12 +843,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file) if (!idx) return 0; - sec = elf_create_section(file->elf, ".ibt_endbr_seal", - sizeof(int), idx); - if (!sec) { - WARN("elf_create_section: .ibt_endbr_seal"); + sec = elf_create_section_pair(file->elf, ".ibt_endbr_seal", + sizeof(int), idx, idx); + if (!sec) return -1; - } idx = 0; list_for_each_entry(insn, &file->endbr_list, call_node) { @@ -884,13 +861,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file) !strcmp(sym->name, "cleanup_module"))) WARN("%s(): not an indirect call target", sym->name); - if (elf_add_reloc_to_insn(file->elf, sec, - idx * sizeof(int), - R_X86_64_PC32, - insn->sec, insn->offset)) { - WARN("elf_add_reloc_to_insn: .ibt_endbr_seal"); + if (!elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(int), idx, + insn->sec, insn->offset)) return -1; - } idx++; } @@ -902,7 +876,6 @@ static int create_cfi_sections(struct objtool_file *file) { struct section *sec; struct symbol *sym; - unsigned int *loc; int idx; sec = find_section_by_name(file->elf, ".cfi_sites"); @@ -923,7 +896,8 @@ static int create_cfi_sections(struct objtool_file *file) idx++; } - sec = elf_create_section(file->elf, ".cfi_sites", sizeof(unsigned int), idx); + sec = elf_create_section_pair(file->elf, ".cfi_sites", + sizeof(unsigned int), idx, idx); if (!sec) return -1; @@ -935,13 +909,9 @@ static int create_cfi_sections(struct objtool_file *file) if (strncmp(sym->name, "__cfi_", 6)) continue; - loc = (unsigned int *)sec->data->d_buf + idx; - memset(loc, 0, sizeof(unsigned int)); - - if (elf_add_reloc_to_insn(file->elf, sec, - idx * sizeof(unsigned int), - R_X86_64_PC32, - sym->sec, sym->offset)) + if (!elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(unsigned int), idx, + sym->sec, sym->offset)) return -1; idx++; @@ -971,7 +941,8 @@ static int create_mcount_loc_sections(struct objtool_file *file) list_for_each_entry(insn, &file->mcount_loc_list, call_node) idx++; - sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx); + sec = elf_create_section_pair(file->elf, "__mcount_loc", addr_size, + idx, idx); if (!sec) return -1; @@ -979,17 +950,17 @@ static int create_mcount_loc_sections(struct objtool_file *file) idx = 0; list_for_each_entry(insn, &file->mcount_loc_list, call_node) { - void *loc; - loc = sec->data->d_buf + idx; - memset(loc, 0, addr_size); + struct reloc *reloc; - if (elf_add_reloc_to_insn(file->elf, sec, idx, - addr_size == sizeof(u64) ? R_ABS64 : R_ABS32, - insn->sec, insn->offset)) + reloc = elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx, + insn->sec, insn->offset); + if (!reloc) return -1; - idx += addr_size; + reloc->type = addr_size == 8 ? R_ABS64 : R_ABS32; + + idx++; } return 0; @@ -999,7 +970,6 @@ static int create_direct_call_sections(struct objtool_file *file) { struct instruction *insn; struct section *sec; - unsigned int *loc; int idx; sec = find_section_by_name(file->elf, ".call_sites"); @@ -1016,20 +986,17 @@ static int create_direct_call_sections(struct objtool_file *file) list_for_each_entry(insn, &file->call_list, call_node) idx++; - sec = elf_create_section(file->elf, ".call_sites", sizeof(unsigned int), idx); + sec = elf_create_section_pair(file->elf, ".call_sites", + sizeof(unsigned int), idx, idx); if (!sec) return -1; idx = 0; list_for_each_entry(insn, &file->call_list, call_node) { - loc = (unsigned int *)sec->data->d_buf + idx; - memset(loc, 0, sizeof(unsigned int)); - - if (elf_add_reloc_to_insn(file->elf, sec, - idx * sizeof(unsigned int), - R_X86_64_PC32, - insn->sec, insn->offset)) + if (!elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(unsigned int), idx, + insn->sec, insn->offset)) return -1; idx++; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 67967c231972..5cbc9d578a45 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -533,41 +533,6 @@ err: return -1; } -static struct section *elf_create_rela_section(struct elf *elf, - struct section *sec); - -int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, - unsigned int type, struct symbol *sym, s64 addend) -{ - struct reloc *reloc; - - if (!sec->rsec && !elf_create_rela_section(elf, sec)) - return -1; - - reloc = malloc(sizeof(*reloc)); - if (!reloc) { - perror("malloc"); - return -1; - } - memset(reloc, 0, sizeof(*reloc)); - - reloc->sec = sec->rsec; - reloc->offset = offset; - reloc->type = type; - reloc->sym = sym; - reloc->addend = addend; - - list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list); - list_add_tail(&reloc->list, &sec->rsec->reloc_list); - elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); - - sec->rsec->sh.sh_size += sec->rsec->sh.sh_entsize; - - mark_sec_changed(elf, sec->rsec, true); - - return 0; -} - /* * Ensure that any reloc section containing references to @sym is marked * changed such that it will get re-generated in elf_rebuild_reloc_sections() @@ -841,13 +806,57 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size) return sym; } -int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, - unsigned long offset, unsigned int type, - struct section *insn_sec, unsigned long insn_off) +static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, + unsigned int reloc_idx, + unsigned long offset, struct symbol *sym, + s64 addend, unsigned int type) +{ + struct reloc *reloc; + + if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) { + WARN("%s: bad reloc_idx %u for %s with size 0x%lx", + __func__, reloc_idx, rsec->name, rsec->sh.sh_size); + return NULL; + } + + reloc = malloc(sizeof(*reloc)); + if (!reloc) { + perror("malloc"); + return NULL; + } + memset(reloc, 0, sizeof(*reloc)); + + reloc->idx = reloc_idx; + reloc->sec = rsec; + reloc->offset = offset; + reloc->type = type; + reloc->sym = sym; + reloc->addend = addend; + + list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list); + list_add_tail(&reloc->list, &rsec->reloc_list); + elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); + + mark_sec_changed(elf, rsec, true); + + return reloc; +} + +struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, + unsigned long offset, + unsigned int reloc_idx, + struct section *insn_sec, + unsigned long insn_off) { struct symbol *sym = insn_sec->sym; int addend = insn_off; + if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) { + WARN("bad call to %s() for data symbol %s", + __func__, sym->name); + return NULL; + } + if (!sym) { /* * Due to how weak functions work, we must use section based @@ -857,12 +866,29 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, */ sym = elf_create_section_symbol(elf, insn_sec); if (!sym) - return -1; + return NULL; insn_sec->sym = sym; } - return elf_add_reloc(elf, sec, offset, type, sym, addend); + return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend, + elf_text_rela_type(elf)); +} + +struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec, + unsigned long offset, + unsigned int reloc_idx, + struct symbol *sym, + s64 addend) +{ + if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) { + WARN("bad call to %s() for text symbol %s", + __func__, sym->name); + return NULL; + } + + return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend, + elf_data_rela_type(elf)); } static int read_reloc(struct section *rsec, int i, struct reloc *reloc) @@ -1048,7 +1074,7 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str) } struct section *elf_create_section(struct elf *elf, const char *name, - size_t entsize, int nr) + size_t entsize, unsigned int nr) { struct section *sec, *shstrtab; size_t size = entsize * nr; @@ -1129,7 +1155,8 @@ struct section *elf_create_section(struct elf *elf, const char *name, } static struct section *elf_create_rela_section(struct elf *elf, - struct section *sec) + struct section *sec, + unsigned int reloc_nr) { struct section *rsec; char *rsec_name; @@ -1142,46 +1169,50 @@ static struct section *elf_create_rela_section(struct elf *elf, strcpy(rsec_name, ".rela"); strcat(rsec_name, sec->name); - rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0); + rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr); free(rsec_name); if (!rsec) return NULL; - sec->rsec = rsec; - rsec->base = sec; - + rsec->data->d_type = ELF_T_RELA; rsec->sh.sh_type = SHT_RELA; rsec->sh.sh_addralign = elf_addr_size(elf); rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; rsec->sh.sh_info = sec->idx; rsec->sh.sh_flags = SHF_INFO_LINK; + sec->rsec = rsec; + rsec->base = sec; + return rsec; } +struct section *elf_create_section_pair(struct elf *elf, const char *name, + size_t entsize, unsigned int nr, + unsigned int reloc_nr) +{ + struct section *sec; + + sec = elf_create_section(elf, name, entsize, nr); + if (!sec) + return NULL; + + if (!elf_create_rela_section(elf, sec, reloc_nr)) + return NULL; + + return sec; +} + static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec) { - bool rela = rsec->sh.sh_type == SHT_RELA; struct reloc *reloc; int idx = 0, ret; - void *buf; - - /* Allocate a buffer for relocations */ - buf = malloc(rsec->sh.sh_size); - if (!buf) { - perror("malloc"); - return -1; - } - - rsec->data->d_buf = buf; - rsec->data->d_size = rsec->sh.sh_size; - rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL; idx = 0; list_for_each_entry(reloc, &rsec->reloc_list, list) { reloc->rel.r_offset = reloc->offset; reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - if (rela) { + if (rsec->sh.sh_type == SHT_RELA) { reloc->rela.r_addend = reloc->addend; ret = gelf_update_rela(rsec->data, idx, &reloc->rela); } else { diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 56b66ff91943..74f63934afd3 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -111,15 +111,26 @@ struct elf { }; struct elf *elf_open_read(const char *name, int flags); -struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr); + +struct section *elf_create_section(struct elf *elf, const char *name, + size_t entsize, unsigned int nr); +struct section *elf_create_section_pair(struct elf *elf, const char *name, + size_t entsize, unsigned int nr, + unsigned int reloc_nr); struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size); -int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, - unsigned int type, struct symbol *sym, s64 addend); -int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, - unsigned long offset, unsigned int type, - struct section *insn_sec, unsigned long insn_off); +struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, + unsigned long offset, + unsigned int reloc_idx, + struct section *insn_sec, + unsigned long insn_off); + +struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec, + unsigned long offset, + unsigned int reloc_idx, + struct symbol *sym, + s64 addend); int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset, unsigned int len, @@ -159,6 +170,16 @@ static inline size_t elf_rela_size(struct elf *elf) return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela); } +static inline unsigned int elf_data_rela_type(struct elf *elf) +{ + return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64; +} + +static inline unsigned int elf_text_rela_type(struct elf *elf) +{ + return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64; +} + static inline bool is_reloc_sec(struct section *sec) { return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL; diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index d5f750be7d7d..bae343908867 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -118,8 +118,8 @@ static int write_orc_entry(struct elf *elf, struct section *orc_sec, orc->bp_offset = bswap_if_needed(elf, orc->bp_offset); /* populate reloc for ip */ - if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32, - insn_sec, insn_off)) + if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, + insn_sec, insn_off)) return -1; return 0; @@ -242,7 +242,7 @@ int orc_create(struct objtool_file *file) if (!orc_sec) return -1; - sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), nr); + sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr); if (!sec) return -1; -- cgit v1.2.3 From caa4a6b74b405ddaea40e2946cc3983aac96451d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:21:02 -0700 Subject: objtool: Add for_each_reloc() Link: https://lore.kernel.org/r/dbfcb1037d8b958e52d097b67829c4c6811c24bb.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 24 ++++++++++++------------ tools/objtool/include/objtool/elf.h | 6 ++++++ 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 3bc97c2b4f01..e21138d36e00 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -591,7 +591,7 @@ static int add_dead_ends(struct objtool_file *file) if (!rsec) goto reachable; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -626,7 +626,7 @@ reachable: if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -1019,7 +1019,7 @@ static void add_ignores(struct objtool_file *file) if (!rsec) return; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { switch (reloc->sym->type) { case STT_FUNC: func = reloc->sym; @@ -1260,7 +1260,7 @@ static int add_ignore_alternatives(struct objtool_file *file) if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -1991,7 +1991,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn, * Each @reloc is a switch table relocation which points to the target * instruction. */ - list_for_each_entry_from(reloc, &table->sec->reloc_list, list) { + for_each_reloc_from(table->sec, reloc) { /* Check for the end of the table: */ if (reloc != table && reloc->jump_table_start) @@ -2270,7 +2270,7 @@ static int read_noendbr_hints(struct objtool_file *file) if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { insn = find_insn(file, reloc->sym->sec, reloc->sym->offset + reloc->addend); if (!insn) { WARN("bad .discard.noendbr entry"); @@ -2293,7 +2293,7 @@ static int read_retpoline_hints(struct objtool_file *file) if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -2329,7 +2329,7 @@ static int read_instr_hints(struct objtool_file *file) if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -2348,7 +2348,7 @@ static int read_instr_hints(struct objtool_file *file) if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -2376,7 +2376,7 @@ static int read_validate_unret_hints(struct objtool_file *file) if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -2404,7 +2404,7 @@ static int read_intra_function_calls(struct objtool_file *file) if (!rsec) return 0; - list_for_each_entry(reloc, &rsec->reloc_list, list) { + for_each_reloc(rsec, reloc) { unsigned long dest_off; if (reloc->sym->type != STT_SECTION) { @@ -4404,7 +4404,7 @@ static int validate_ibt(struct objtool_file *file) strstr(sec->name, "__patchable_function_entries")) continue; - list_for_each_entry(reloc, &sec->rsec->reloc_list, list) + for_each_reloc(sec->rsec, reloc) warnings += validate_ibt_data_reloc(file, reloc); } diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 74f63934afd3..a938cb1d4172 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -209,6 +209,12 @@ static inline void mark_sec_changed(struct elf *elf, struct section *sec, for_each_sec(file, __sec) \ sec_for_each_sym(__sec, sym) +#define for_each_reloc(rsec, reloc) \ + list_for_each_entry(reloc, &rsec->reloc_list, list) + +#define for_each_reloc_from(rsec, reloc) \ + list_for_each_entry_from(reloc, &rsec->reloc_list, list) + #define OFFSET_STRIDE_BITS 4 #define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS) #define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1)) -- cgit v1.2.3 From e4cbb9b81f1f7519c7ae3abda09cb15794022952 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:21:06 -0700 Subject: objtool: Get rid of reloc->offset Get the offset from the embedded GElf_Rel[a] struct. With allyesconfig + CONFIG_DEBUG_INFO: - Before: peak heap memory consumption: 43.83G - After: peak heap memory consumption: 42.10G Link: https://lore.kernel.org/r/2b9ec01178baa346a99522710bf2e82159412e3a.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 14 +++++++------- tools/objtool/elf.c | 10 +++++----- tools/objtool/include/objtool/elf.h | 8 ++++++-- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index e21138d36e00..e06ffad5a93c 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -511,11 +511,11 @@ static int add_pv_ops(struct objtool_file *file, const char *symname) if (func->type == STT_SECTION) func = find_symbol_by_offset(reloc->sym->sec, reloc->addend); - idx = (reloc->offset - sym->offset) / sizeof(unsigned long); + idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); objtool_pv_add(file, idx, func); - off = reloc->offset + 1; + off = reloc_offset(reloc) + 1; if (off > end) break; } @@ -1998,7 +1998,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn, break; /* Make sure the table entries are consecutive: */ - if (prev_offset && reloc->offset != prev_offset + 8) + if (prev_offset && reloc_offset(reloc) != prev_offset + 8) break; /* Detect function pointers from contiguous objects: */ @@ -2023,7 +2023,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn, alt->insn = dest_insn; alt->next = insn->alts; insn->alts = alt; - prev_offset = reloc->offset; + prev_offset = reloc_offset(reloc); } if (!prev_offset) { @@ -4266,8 +4266,8 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn for (reloc = insn_reloc(file, insn); reloc; reloc = find_reloc_by_dest_range(file->elf, insn->sec, - reloc->offset + 1, - (insn->offset + insn->len) - (reloc->offset + 1))) { + reloc_offset(reloc) + 1, + (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) { /* * static_call_update() references the trampoline, which @@ -4350,7 +4350,7 @@ static int validate_ibt_data_reloc(struct objtool_file *file, return 0; WARN_FUNC("data relocation to !ENDBR: %s", - reloc->sec->base, reloc->offset, + reloc->sec->base, reloc_offset(reloc), offstr(dest->sec, dest->offset)); return 1; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 70c801254566..2b45460225d1 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -246,8 +246,9 @@ struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *se if (reloc->sec != rsec) continue; - if (reloc->offset >= offset && reloc->offset < offset + len) { - if (!r || reloc->offset < r->offset) + if (reloc_offset(reloc) >= offset && + reloc_offset(reloc) < offset + len) { + if (!r || reloc_offset(reloc) < reloc_offset(r)) r = reloc; } } @@ -830,11 +831,12 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, } reloc->sec = rsec; - reloc->offset = offset; reloc->type = type; reloc->sym = sym; reloc->addend = addend; + reloc->rel.r_offset = offset; + if (elf_write_reloc(elf, reloc)) return NULL; @@ -908,7 +910,6 @@ static int read_reloc(struct section *rsec, int i, struct reloc *reloc) return -1; } - reloc->offset = reloc->rel.r_offset; reloc->type = GELF_R_TYPE(reloc->rel.r_info); reloc->addend = rela ? reloc->rela.r_addend : 0; @@ -1230,7 +1231,6 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc) struct section *rsec = reloc->sec; int ret; - reloc->rel.r_offset = reloc->offset; reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); if (rsec->sh.sh_type == SHT_RELA) { diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 2a14da633d56..2070860a099e 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -75,7 +75,6 @@ struct reloc { struct section *sec; struct symbol *sym; struct list_head sym_reloc_entry; - unsigned long offset; s64 addend; unsigned int type; bool jump_table_start; @@ -204,6 +203,11 @@ static inline unsigned int reloc_idx(struct reloc *reloc) return reloc - reloc->sec->relocs; } +static inline unsigned long reloc_offset(struct reloc *reloc) +{ + return reloc->rel.r_offset; +} + #define for_each_sec(file, sec) \ list_for_each_entry(sec, &file->elf->sections, list) @@ -253,7 +257,7 @@ static inline u32 sec_offset_hash(struct section *sec, unsigned long offset) static inline u32 reloc_hash(struct reloc *reloc) { - return sec_offset_hash(reloc->sec, reloc->offset); + return sec_offset_hash(reloc->sec, reloc_offset(reloc)); } #endif /* _OBJTOOL_ELF_H */ -- cgit v1.2.3 From fcee899d2794319c9dbeb7b877b0c4ac92f5dd16 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:21:07 -0700 Subject: objtool: Get rid of reloc->type Get the type from the embedded GElf_Rel[a] struct. Link: https://lore.kernel.org/r/d1c1f8da31e4f052a2478aea585fcf355cacc53a.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/x86/decode.c | 2 +- tools/objtool/arch/x86/special.c | 4 ++-- tools/objtool/check.c | 11 ++++++----- tools/objtool/elf.c | 6 ++---- tools/objtool/include/objtool/elf.h | 11 ++++++++++- 5 files changed, 21 insertions(+), 13 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 9ef024fd648c..ffb12e83b238 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -84,7 +84,7 @@ bool arch_pc_relative_reloc(struct reloc *reloc) * All relocation types where P (the address of the target) * is included in the computation. */ - switch (reloc->type) { + switch (reloc_type(reloc)) { case R_X86_64_PC8: case R_X86_64_PC16: case R_X86_64_PC32: diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/special.c index 7c97b7391279..1a54a249cb50 100644 --- a/tools/objtool/arch/x86/special.c +++ b/tools/objtool/arch/x86/special.c @@ -108,7 +108,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file, table_offset = text_reloc->addend; table_sec = text_reloc->sym->sec; - if (text_reloc->type == R_X86_64_PC32) + if (reloc_type(text_reloc) == R_X86_64_PC32) table_offset += 4; /* @@ -138,7 +138,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file, * indicates a rare GCC quirk/bug which can leave dead * code behind. */ - if (text_reloc->type == R_X86_64_PC32) + if (reloc_type(text_reloc) == R_X86_64_PC32) file->ignore_unreachables = true; return rodata_reloc; diff --git a/tools/objtool/check.c b/tools/objtool/check.c index e06ffad5a93c..04b4152be206 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -958,7 +958,7 @@ static int create_mcount_loc_sections(struct objtool_file *file) if (!reloc) return -1; - reloc->type = addr_size == 8 ? R_ABS64 : R_ABS32; + set_reloc_type(reloc, addr_size == 8 ? R_ABS64 : R_ABS32); idx++; } @@ -1354,7 +1354,7 @@ static void annotate_call_site(struct objtool_file *file, */ if (opts.hack_noinstr && insn->sec->noinstr && sym->profiling_func) { if (reloc) { - reloc->type = R_NONE; + set_reloc_type(reloc, R_NONE); elf_write_reloc(file->elf, reloc); } @@ -1383,7 +1383,7 @@ static void annotate_call_site(struct objtool_file *file, WARN_INSN(insn, "tail call to __fentry__ !?!?"); if (opts.mnop) { if (reloc) { - reloc->type = R_NONE; + set_reloc_type(reloc, R_NONE); elf_write_reloc(file->elf, reloc); } @@ -1865,7 +1865,7 @@ static int handle_jump_alt(struct objtool_file *file, struct reloc *reloc = insn_reloc(file, orig_insn); if (reloc) { - reloc->type = R_NONE; + set_reloc_type(reloc, R_NONE); elf_write_reloc(file->elf, reloc); } elf_write_insn(file->elf, orig_insn->sec, @@ -4277,7 +4277,8 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn continue; off = reloc->sym->offset; - if (reloc->type == R_X86_64_PC32 || reloc->type == R_X86_64_PLT32) + if (reloc_type(reloc) == R_X86_64_PC32 || + reloc_type(reloc) == R_X86_64_PLT32) off += arch_dest_reloc_offset(reloc->addend); else off += reloc->addend; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 2b45460225d1..be9d24dcdf56 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -541,6 +541,7 @@ static int elf_update_sym_relocs(struct elf *elf, struct symbol *sym) struct reloc *reloc; list_for_each_entry(reloc, &sym->reloc_list, sym_reloc_entry) { + reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc_type(reloc)); if (elf_write_reloc(elf, reloc)) return -1; } @@ -831,11 +832,11 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, } reloc->sec = rsec; - reloc->type = type; reloc->sym = sym; reloc->addend = addend; reloc->rel.r_offset = offset; + reloc->rel.r_info = GELF_R_INFO(sym->idx, type); if (elf_write_reloc(elf, reloc)) return NULL; @@ -910,7 +911,6 @@ static int read_reloc(struct section *rsec, int i, struct reloc *reloc) return -1; } - reloc->type = GELF_R_TYPE(reloc->rel.r_info); reloc->addend = rela ? reloc->rela.r_addend : 0; return 0; @@ -1231,8 +1231,6 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc) struct section *rsec = reloc->sec; int ret; - reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); - if (rsec->sh.sh_type == SHT_RELA) { reloc->rela.r_addend = reloc->addend; ret = gelf_update_rela(rsec->data, reloc_idx(reloc), &reloc->rela); diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 2070860a099e..41d2149f8bb8 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -76,7 +76,6 @@ struct reloc { struct symbol *sym; struct list_head sym_reloc_entry; s64 addend; - unsigned int type; bool jump_table_start; }; @@ -208,6 +207,16 @@ static inline unsigned long reloc_offset(struct reloc *reloc) return reloc->rel.r_offset; } +static inline unsigned int reloc_type(struct reloc *reloc) +{ + return GELF_R_TYPE(reloc->rel.r_info); +} + +static inline void set_reloc_type(struct reloc *reloc, int type) +{ + reloc->rel.r_info = GELF_R_INFO(GELF_R_SYM(reloc->rel.r_info), type); +} + #define for_each_sec(file, sec) \ list_for_each_entry(sec, &file->elf->sections, list) -- cgit v1.2.3 From 0696b6e314dbe4bd2f24d5e749469f57ea095a9f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:21:08 -0700 Subject: objtool: Get rid of reloc->addend Get the addend from the embedded GElf_Rel[a] struct. With allyesconfig + CONFIG_DEBUG_INFO: - Before: peak heap memory consumption: 42.10G - After: peak heap memory consumption: 40.37G Link: https://lore.kernel.org/r/ad2354f95d9ddd86094e3f7687acfa0750657784.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/x86/decode.c | 4 +-- tools/objtool/arch/x86/special.c | 2 +- tools/objtool/check.c | 69 +++++++++++++++++++++---------------- tools/objtool/elf.c | 10 ++---- tools/objtool/include/objtool/elf.h | 6 +++- tools/objtool/special.c | 4 +-- 6 files changed, 53 insertions(+), 42 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index ffb12e83b238..2e1caabecb18 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -623,11 +623,11 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec if (!immr || strcmp(immr->sym->name, "pv_ops")) break; - idx = (immr->addend + 8) / sizeof(void *); + idx = (reloc_addend(immr) + 8) / sizeof(void *); func = disp->sym; if (disp->sym->type == STT_SECTION) - func = find_symbol_by_offset(disp->sym->sec, disp->addend); + func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp)); if (!func) { WARN("no func for pv_ops[]"); return -1; diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/special.c index 1a54a249cb50..65f48f35b97e 100644 --- a/tools/objtool/arch/x86/special.c +++ b/tools/objtool/arch/x86/special.c @@ -105,7 +105,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file, !text_reloc->sym->sec->rodata) return NULL; - table_offset = text_reloc->addend; + table_offset = reloc_addend(text_reloc); table_sec = text_reloc->sym->sec; if (reloc_type(text_reloc) == R_X86_64_PC32) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 04b4152be206..745487dda432 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -509,7 +509,8 @@ static int add_pv_ops(struct objtool_file *file, const char *symname) func = reloc->sym; if (func->type == STT_SECTION) - func = find_symbol_by_offset(reloc->sym->sec, reloc->addend); + func = find_symbol_by_offset(reloc->sym->sec, + reloc_addend(reloc)); idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); @@ -583,6 +584,7 @@ static int add_dead_ends(struct objtool_file *file) struct section *rsec; struct reloc *reloc; struct instruction *insn; + s64 addend; /* * Check for manually annotated dead ends. @@ -592,23 +594,27 @@ static int add_dead_ends(struct objtool_file *file) goto reachable; for_each_reloc(rsec, reloc) { + if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + + addend = reloc_addend(reloc); + + insn = find_insn(file, reloc->sym->sec, addend); if (insn) insn = prev_insn_same_sec(file, insn); - else if (reloc->addend == reloc->sym->sec->sh.sh_size) { + else if (addend == reloc->sym->sec->sh.sh_size) { insn = find_last_insn(file, reloc->sym->sec); if (!insn) { WARN("can't find unreachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, reloc->addend); + reloc->sym->sec->name, addend); return -1; } } else { WARN("can't find unreachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, reloc->addend); + reloc->sym->sec->name, addend); return -1; } @@ -627,23 +633,27 @@ reachable: return 0; for_each_reloc(rsec, reloc) { + if (reloc->sym->type != STT_SECTION) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + + addend = reloc_addend(reloc); + + insn = find_insn(file, reloc->sym->sec, addend); if (insn) insn = prev_insn_same_sec(file, insn); - else if (reloc->addend == reloc->sym->sec->sh.sh_size) { + else if (addend == reloc->sym->sec->sh.sh_size) { insn = find_last_insn(file, reloc->sym->sec); if (!insn) { WARN("can't find reachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, reloc->addend); + reloc->sym->sec->name, addend); return -1; } } else { WARN("can't find reachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, reloc->addend); + reloc->sym->sec->name, addend); return -1; } @@ -1026,7 +1036,7 @@ static void add_ignores(struct objtool_file *file) break; case STT_SECTION: - func = find_func_by_offset(reloc->sym->sec, reloc->addend); + func = find_func_by_offset(reloc->sym->sec, reloc_addend(reloc)); if (!func) continue; break; @@ -1266,7 +1276,7 @@ static int add_ignore_alternatives(struct objtool_file *file) return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!insn) { WARN("bad .discard.ignore_alts entry"); return -1; @@ -1542,7 +1552,7 @@ static int add_jump_destinations(struct objtool_file *file) dest_off = arch_jump_destination(insn); } else if (reloc->sym->type == STT_SECTION) { dest_sec = reloc->sym->sec; - dest_off = arch_dest_reloc_offset(reloc->addend); + dest_off = arch_dest_reloc_offset(reloc_addend(reloc)); } else if (reloc->sym->retpoline_thunk) { add_retpoline_call(file, insn); continue; @@ -1559,7 +1569,7 @@ static int add_jump_destinations(struct objtool_file *file) } else if (reloc->sym->sec->idx) { dest_sec = reloc->sym->sec; dest_off = reloc->sym->sym.st_value + - arch_dest_reloc_offset(reloc->addend); + arch_dest_reloc_offset(reloc_addend(reloc)); } else { /* non-func asm code jumping to another file */ continue; @@ -1676,7 +1686,7 @@ static int add_call_destinations(struct objtool_file *file) } } else if (reloc->sym->type == STT_SECTION) { - dest_off = arch_dest_reloc_offset(reloc->addend); + dest_off = arch_dest_reloc_offset(reloc_addend(reloc)); dest = find_call_destination(reloc->sym->sec, dest_off); if (!dest) { WARN_INSN(insn, "can't find call dest symbol at %s+0x%lx", @@ -2003,10 +2013,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn, /* Detect function pointers from contiguous objects: */ if (reloc->sym->sec == pfunc->sec && - reloc->addend == pfunc->offset) + reloc_addend(reloc) == pfunc->offset) break; - dest_insn = find_insn(file, reloc->sym->sec, reloc->addend); + dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!dest_insn) break; @@ -2067,7 +2077,7 @@ static struct reloc *find_jump_table(struct objtool_file *file, table_reloc = arch_find_switch_table(file, insn); if (!table_reloc) continue; - dest_insn = find_insn(file, table_reloc->sym->sec, table_reloc->addend); + dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc)); if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func) continue; @@ -2203,7 +2213,7 @@ static int read_unwind_hints(struct objtool_file *file) return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!insn) { WARN("can't find insn for unwind_hints[%d]", i); return -1; @@ -2271,7 +2281,8 @@ static int read_noendbr_hints(struct objtool_file *file) return 0; for_each_reloc(rsec, reloc) { - insn = find_insn(file, reloc->sym->sec, reloc->sym->offset + reloc->addend); + insn = find_insn(file, reloc->sym->sec, + reloc->sym->offset + reloc_addend(reloc)); if (!insn) { WARN("bad .discard.noendbr entry"); return -1; @@ -2299,7 +2310,7 @@ static int read_retpoline_hints(struct objtool_file *file) return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!insn) { WARN("bad .discard.retpoline_safe entry"); return -1; @@ -2335,7 +2346,7 @@ static int read_instr_hints(struct objtool_file *file) return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!insn) { WARN("bad .discard.instr_end entry"); return -1; @@ -2354,7 +2365,7 @@ static int read_instr_hints(struct objtool_file *file) return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!insn) { WARN("bad .discard.instr_begin entry"); return -1; @@ -2382,7 +2393,7 @@ static int read_validate_unret_hints(struct objtool_file *file) return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!insn) { WARN("bad .discard.instr_end entry"); return -1; @@ -2413,7 +2424,7 @@ static int read_intra_function_calls(struct objtool_file *file) return -1; } - insn = find_insn(file, reloc->sym->sec, reloc->addend); + insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); if (!insn) { WARN("bad .discard.intra_function_call entry"); return -1; @@ -3317,7 +3328,7 @@ static inline const char *call_dest_name(struct instruction *insn) reloc = insn_reloc(NULL, insn); if (reloc && !strcmp(reloc->sym->name, "pv_ops")) { - idx = (reloc->addend / sizeof(void *)); + idx = (reloc_addend(reloc) / sizeof(void *)); snprintf(pvname, sizeof(pvname), "pv_ops[%d]", idx); return pvname; } @@ -3335,7 +3346,7 @@ static bool pv_call_dest(struct objtool_file *file, struct instruction *insn) if (!reloc || strcmp(reloc->sym->name, "pv_ops")) return false; - idx = (arch_dest_reloc_offset(reloc->addend) / sizeof(void *)); + idx = (arch_dest_reloc_offset(reloc_addend(reloc)) / sizeof(void *)); if (file->pv_ops[idx].clean) return true; @@ -4279,9 +4290,9 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn off = reloc->sym->offset; if (reloc_type(reloc) == R_X86_64_PC32 || reloc_type(reloc) == R_X86_64_PLT32) - off += arch_dest_reloc_offset(reloc->addend); + off += arch_dest_reloc_offset(reloc_addend(reloc)); else - off += reloc->addend; + off += reloc_addend(reloc); dest = find_insn(file, reloc->sym->sec, off); if (!dest) @@ -4338,7 +4349,7 @@ static int validate_ibt_data_reloc(struct objtool_file *file, struct instruction *dest; dest = find_insn(file, reloc->sym->sec, - reloc->sym->offset + reloc->addend); + reloc->sym->offset + reloc_addend(reloc)); if (!dest) return 0; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index be9d24dcdf56..16e019a1762c 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -833,10 +833,10 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, reloc->sec = rsec; reloc->sym = sym; - reloc->addend = addend; reloc->rel.r_offset = offset; reloc->rel.r_info = GELF_R_INFO(sym->idx, type); + reloc->rela.r_addend = addend; if (elf_write_reloc(elf, reloc)) return NULL; @@ -911,8 +911,6 @@ static int read_reloc(struct section *rsec, int i, struct reloc *reloc) return -1; } - reloc->addend = rela ? reloc->rela.r_addend : 0; - return 0; } @@ -1231,12 +1229,10 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc) struct section *rsec = reloc->sec; int ret; - if (rsec->sh.sh_type == SHT_RELA) { - reloc->rela.r_addend = reloc->addend; + if (rsec->sh.sh_type == SHT_RELA) ret = gelf_update_rela(rsec->data, reloc_idx(reloc), &reloc->rela); - } else { + else ret = gelf_update_rel(rsec->data, reloc_idx(reloc), &reloc->rel); - } if (!ret) { WARN_ELF("gelf_update_rela"); diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 41d2149f8bb8..be08b32a93ee 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -75,7 +75,6 @@ struct reloc { struct section *sec; struct symbol *sym; struct list_head sym_reloc_entry; - s64 addend; bool jump_table_start; }; @@ -217,6 +216,11 @@ static inline void set_reloc_type(struct reloc *reloc, int type) reloc->rel.r_info = GELF_R_INFO(GELF_R_SYM(reloc->rel.r_info), type); } +static inline s64 reloc_addend(struct reloc *reloc) +{ + return reloc->rela.r_addend; +} + #define for_each_sec(file, sec) \ list_for_each_entry(sec, &file->elf->sections, list) diff --git a/tools/objtool/special.c b/tools/objtool/special.c index baa85c31526b..91b1950f5bd8 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c @@ -62,7 +62,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec, unsigned long *off) { *sec = reloc->sym->sec; - *off = reloc->sym->offset + reloc->addend; + *off = reloc->sym->offset + reloc_addend(reloc); } static int get_alt_entry(struct elf *elf, const struct special_entry *entry, @@ -126,7 +126,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry, sec, offset + entry->key); return -1; } - alt->key_addend = key_reloc->addend; + alt->key_addend = reloc_addend(key_reloc); } return 0; -- cgit v1.2.3 From be2f0b1e12644c956a347d7fde93c2ffe9cdb1af Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:21:09 -0700 Subject: objtool: Get rid of reloc->jump_table_start Rework the jump table logic slightly so 'jump_table_start' is no longer needed. With allyesconfig + CONFIG_DEBUG_INFO: - Before: peak heap memory consumption: 40.37G - After: peak heap memory consumption: 38.64G Link: https://lore.kernel.org/r/e1602ed8a6171ada3cfac0bd8449892ec82bd188.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 35 +++++++++++++++++++++++------------ tools/objtool/include/objtool/elf.h | 1 - 2 files changed, 23 insertions(+), 13 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 745487dda432..7fb6467178cb 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1989,13 +1989,14 @@ out: } static int add_jump_table(struct objtool_file *file, struct instruction *insn, - struct reloc *table) + struct reloc *next_table) { - struct reloc *reloc = table; - struct instruction *dest_insn; - struct alternative *alt; struct symbol *pfunc = insn_func(insn)->pfunc; + struct reloc *table = insn_jump_table(insn); + struct instruction *dest_insn; unsigned int prev_offset = 0; + struct reloc *reloc = table; + struct alternative *alt; /* * Each @reloc is a switch table relocation which points to the target @@ -2004,7 +2005,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn, for_each_reloc_from(table->sec, reloc) { /* Check for the end of the table: */ - if (reloc != table && reloc->jump_table_start) + if (reloc != table && reloc == next_table) break; /* Make sure the table entries are consecutive: */ @@ -2119,29 +2120,39 @@ static void mark_func_jump_tables(struct objtool_file *file, continue; reloc = find_jump_table(file, func, insn); - if (reloc) { - reloc->jump_table_start = true; + if (reloc) insn->_jump_table = reloc; - } } } static int add_func_jump_tables(struct objtool_file *file, struct symbol *func) { - struct instruction *insn; - int ret; + struct instruction *insn, *insn_t1 = NULL, *insn_t2; + int ret = 0; func_for_each_insn(file, func, insn) { if (!insn_jump_table(insn)) continue; - ret = add_jump_table(file, insn, insn_jump_table(insn)); + if (!insn_t1) { + insn_t1 = insn; + continue; + } + + insn_t2 = insn; + + ret = add_jump_table(file, insn_t1, insn_jump_table(insn_t2)); if (ret) return ret; + + insn_t1 = insn_t2; } - return 0; + if (insn_t1) + ret = add_jump_table(file, insn_t1, NULL); + + return ret; } /* diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index be08b32a93ee..60686f746c9e 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -75,7 +75,6 @@ struct reloc { struct section *sec; struct symbol *sym; struct list_head sym_reloc_entry; - bool jump_table_start; }; struct elf { -- cgit v1.2.3 From ec24b927c1fbfc91cf7a48276d9fd92072b17d3b Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:21:12 -0700 Subject: objtool: Get rid of reloc->rel[a] Get the relocation entry info from the underlying rsec->data. With allyesconfig + CONFIG_DEBUG_INFO: - Before: peak heap memory consumption: 35.12G - After: peak heap memory consumption: 29.93G Link: https://lore.kernel.org/r/2be32323de6d8cc73179ee0ff14b71f4e7cefaa0.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 20 +++----- tools/objtool/elf.c | 60 +++-------------------- tools/objtool/include/objtool/elf.h | 94 ++++++++++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 78 deletions(-) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 7fb6467178cb..47ff130a9460 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -968,7 +968,7 @@ static int create_mcount_loc_sections(struct objtool_file *file) if (!reloc) return -1; - set_reloc_type(reloc, addr_size == 8 ? R_ABS64 : R_ABS32); + set_reloc_type(file->elf, reloc, addr_size == 8 ? R_ABS64 : R_ABS32); idx++; } @@ -1363,10 +1363,8 @@ static void annotate_call_site(struct objtool_file *file, * noinstr text. */ if (opts.hack_noinstr && insn->sec->noinstr && sym->profiling_func) { - if (reloc) { - set_reloc_type(reloc, R_NONE); - elf_write_reloc(file->elf, reloc); - } + if (reloc) + set_reloc_type(file->elf, reloc, R_NONE); elf_write_insn(file->elf, insn->sec, insn->offset, insn->len, @@ -1392,10 +1390,8 @@ static void annotate_call_site(struct objtool_file *file, if (sibling) WARN_INSN(insn, "tail call to __fentry__ !?!?"); if (opts.mnop) { - if (reloc) { - set_reloc_type(reloc, R_NONE); - elf_write_reloc(file->elf, reloc); - } + if (reloc) + set_reloc_type(file->elf, reloc, R_NONE); elf_write_insn(file->elf, insn->sec, insn->offset, insn->len, @@ -1874,10 +1870,8 @@ static int handle_jump_alt(struct objtool_file *file, if (opts.hack_jump_label && special_alt->key_addend & 2) { struct reloc *reloc = insn_reloc(file, orig_insn); - if (reloc) { - set_reloc_type(reloc, R_NONE); - elf_write_reloc(file->elf, reloc); - } + if (reloc) + set_reloc_type(file->elf, reloc, R_NONE); elf_write_insn(file->elf, orig_insn->sec, orig_insn->offset, orig_insn->len, arch_nop_insn(orig_insn->len)); diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 04038b1324cf..54d182ddc4bb 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -575,11 +575,8 @@ static int elf_update_sym_relocs(struct elf *elf, struct symbol *sym) { struct reloc *reloc; - for (reloc = sym->relocs; reloc; reloc = reloc->sym_next_reloc) { - reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc_type(reloc)); - if (elf_write_reloc(elf, reloc)) - return -1; - } + for (reloc = sym->relocs; reloc; reloc = reloc->sym_next_reloc) + set_reloc_sym(elf, reloc, reloc->sym->idx); return 0; } @@ -869,12 +866,10 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, reloc->sec = rsec; reloc->sym = sym; - reloc->rel.r_offset = offset; - reloc->rel.r_info = GELF_R_INFO(sym->idx, type); - reloc->rela.r_addend = addend; - - if (elf_write_reloc(elf, reloc)) - return NULL; + set_reloc_offset(elf, reloc, offset); + set_reloc_sym(elf, reloc, sym->idx); + set_reloc_type(elf, reloc, type); + set_reloc_addend(elf, reloc, addend); elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); reloc->sym_next_reloc = sym->relocs; @@ -932,24 +927,6 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec, elf_data_rela_type(elf)); } -static int read_reloc(struct section *rsec, int i, struct reloc *reloc) -{ - bool rela = rsec->sh.sh_type == SHT_RELA; - void *retp; - - if (rela) - retp = gelf_getrela(rsec->data, i, &reloc->rela); - else - retp = gelf_getrel(rsec->data, i, &reloc->rel); - - if (!retp) { - WARN_ELF("gelf_getrela"); - return -1; - } - - return 0; -} - static int read_relocs(struct elf *elf) { unsigned long nr_reloc, max_reloc = 0; @@ -984,11 +961,8 @@ static int read_relocs(struct elf *elf) for (i = 0; i < sec_num_entries(rsec); i++) { reloc = &rsec->relocs[i]; - if (read_reloc(rsec, i, reloc)) - return -1; - reloc->sec = rsec; - symndx = GELF_R_SYM(reloc->rel.r_info); + symndx = reloc_sym(reloc); reloc->sym = sym = find_symbol_by_index(elf, symndx); if (!reloc->sym) { WARN("can't find reloc entry symbol %d for %s", @@ -1261,26 +1235,6 @@ int elf_write_insn(struct elf *elf, struct section *sec, return 0; } -int elf_write_reloc(struct elf *elf, struct reloc *reloc) -{ - struct section *rsec = reloc->sec; - int ret; - - if (rsec->sh.sh_type == SHT_RELA) - ret = gelf_update_rela(rsec->data, reloc_idx(reloc), &reloc->rela); - else - ret = gelf_update_rel(rsec->data, reloc_idx(reloc), &reloc->rel); - - if (!ret) { - WARN_ELF("gelf_update_rela"); - return -1; - } - - mark_sec_changed(elf, rsec, true); - - return 0; -} - /* * When Elf_Scn::sh_size is smaller than the combined Elf_Data::d_size * do you: diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 03a9040f696c..c532d70864dc 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -72,10 +72,6 @@ struct symbol { struct reloc { struct elf_hash_node hash; - union { - GElf_Rela rela; - GElf_Rel rel; - }; struct section *sec; struct symbol *sym; struct reloc *sym_next_reloc; @@ -132,7 +128,6 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec, int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset, unsigned int len, const char *insn); -int elf_write_reloc(struct elf *elf, struct reloc *reloc); int elf_write(struct elf *elf); void elf_close(struct elf *elf); @@ -204,24 +199,99 @@ static inline unsigned int reloc_idx(struct reloc *reloc) return reloc - reloc->sec->relocs; } -static inline unsigned long reloc_offset(struct reloc *reloc) +static inline void *reloc_rel(struct reloc *reloc) { - return reloc->rel.r_offset; + struct section *rsec = reloc->sec; + + return rsec->data->d_buf + (reloc_idx(reloc) * rsec->sh.sh_entsize); } -static inline unsigned int reloc_type(struct reloc *reloc) +static inline bool is_32bit_reloc(struct reloc *reloc) { - return GELF_R_TYPE(reloc->rel.r_info); + /* + * Elf32_Rel: 8 bytes + * Elf32_Rela: 12 bytes + * Elf64_Rel: 16 bytes + * Elf64_Rela: 24 bytes + */ + return reloc->sec->sh.sh_entsize < 16; } -static inline void set_reloc_type(struct reloc *reloc, int type) +#define __get_reloc_field(reloc, field) \ +({ \ + is_32bit_reloc(reloc) ? \ + ((Elf32_Rela *)reloc_rel(reloc))->field : \ + ((Elf64_Rela *)reloc_rel(reloc))->field; \ +}) + +#define __set_reloc_field(reloc, field, val) \ +({ \ + if (is_32bit_reloc(reloc)) \ + ((Elf32_Rela *)reloc_rel(reloc))->field = val; \ + else \ + ((Elf64_Rela *)reloc_rel(reloc))->field = val; \ +}) + +static inline u64 reloc_offset(struct reloc *reloc) { - reloc->rel.r_info = GELF_R_INFO(GELF_R_SYM(reloc->rel.r_info), type); + return __get_reloc_field(reloc, r_offset); +} + +static inline void set_reloc_offset(struct elf *elf, struct reloc *reloc, u64 offset) +{ + __set_reloc_field(reloc, r_offset, offset); + mark_sec_changed(elf, reloc->sec, true); } static inline s64 reloc_addend(struct reloc *reloc) { - return reloc->rela.r_addend; + return __get_reloc_field(reloc, r_addend); +} + +static inline void set_reloc_addend(struct elf *elf, struct reloc *reloc, s64 addend) +{ + __set_reloc_field(reloc, r_addend, addend); + mark_sec_changed(elf, reloc->sec, true); +} + + +static inline unsigned int reloc_sym(struct reloc *reloc) +{ + u64 info = __get_reloc_field(reloc, r_info); + + return is_32bit_reloc(reloc) ? + ELF32_R_SYM(info) : + ELF64_R_SYM(info); +} + +static inline unsigned int reloc_type(struct reloc *reloc) +{ + u64 info = __get_reloc_field(reloc, r_info); + + return is_32bit_reloc(reloc) ? + ELF32_R_TYPE(info) : + ELF64_R_TYPE(info); +} + +static inline void set_reloc_sym(struct elf *elf, struct reloc *reloc, unsigned int sym) +{ + u64 info = is_32bit_reloc(reloc) ? + ELF32_R_INFO(sym, reloc_type(reloc)) : + ELF64_R_INFO(sym, reloc_type(reloc)); + + __set_reloc_field(reloc, r_info, info); + + mark_sec_changed(elf, reloc->sec, true); +} +static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned int type) +{ + u64 info = is_32bit_reloc(reloc) ? + ELF32_R_INFO(reloc_sym(reloc), type) : + ELF64_R_INFO(reloc_sym(reloc), type); + + __set_reloc_field(reloc, r_info, info); + + mark_sec_changed(elf, reloc->sec, true); } #define for_each_sec(file, sec) \ -- cgit v1.2.3 From d93b5935fd47007597aed5105a902a10204bc30e Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 30 May 2023 10:21:13 -0700 Subject: objtool: Free insns when done Free the decoded instructions as they're no longer needed after this point. This frees up a big chunk of heap, which will come handy when skipping the reading of DWARF section data. Link: https://lore.kernel.org/r/4d4bca1a0f869de020dac80d91f9acbf6df77eab.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'tools/objtool/check.c') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 47ff130a9460..8936a05f0e5a 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4596,6 +4596,34 @@ static int disas_warned_funcs(struct objtool_file *file) return 0; } +struct insn_chunk { + void *addr; + struct insn_chunk *next; +}; + +/* + * Reduce peak RSS usage by freeing insns memory before writing the ELF file, + * which can trigger more allocations for .debug_* sections whose data hasn't + * been read yet. + */ +static void free_insns(struct objtool_file *file) +{ + struct instruction *insn; + struct insn_chunk *chunks = NULL, *chunk; + + for_each_insn(file, insn) { + if (!insn->idx) { + chunk = malloc(sizeof(*chunk)); + chunk->addr = insn; + chunk->next = chunks; + chunks = chunk; + } + } + + for (chunk = chunks; chunk; chunk = chunk->next) + free(chunk->addr); +} + int check(struct objtool_file *file) { int ret, warnings = 0; @@ -4742,6 +4770,8 @@ int check(struct objtool_file *file) warnings += ret; } + free_insns(file); + if (opts.verbose) disas_warned_funcs(file); -- cgit v1.2.3