Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Remove --lto and --vmlinux in favor of --link

The '--lto' option is a confusing way of telling objtool to do stack
validation despite it being a linked object. It's no longer needed now
that an explicit '--stackval' option exists. The '--vmlinux' option is
also redundant.

Remove both options in favor of a straightforward '--link' option which
identifies a linked object.

Also, implicitly set '--link' with a warning if the user forgets to do
so and we can tell that it's a linked object. This makes it easier for
manual vmlinux runs.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Link: https://lkml.kernel.org/r/dcd3ceffd15a54822c6183e5766d21ad06082b45.1650300597.git.jpoimboe@redhat.com

authored by

Josh Poimboeuf and committed by
Peter Zijlstra
753da417 489e355b

+70 -39
+3 -1
scripts/Makefile.build
··· 229 229 objtool_args = \ 230 230 $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \ 231 231 $(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr) \ 232 - $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \ 232 + $(if $(CONFIG_X86_KERNEL_IBT), --ibt) \ 233 233 $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \ 234 234 $(if $(CONFIG_UNWINDER_ORC), --orc) \ 235 235 $(if $(CONFIG_RETPOLINE), --retpoline) \ ··· 237 237 $(if $(CONFIG_STACK_VALIDATION), --stackval) \ 238 238 $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call) \ 239 239 $(if $(CONFIG_X86_SMAP), --uaccess) \ 240 + $(if $(linked-object), --link) \ 240 241 $(if $(part-of-module), --module) \ 241 242 $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) 242 243 ··· 307 306 # modules into native code 308 307 $(obj)/%.prelink.o: objtool-enabled = y 309 308 $(obj)/%.prelink.o: part-of-module := y 309 + $(obj)/%.prelink.o: linked-object := y 310 310 311 311 $(obj)/%.prelink.o: $(obj)/%.o FORCE 312 312 $(call if_changed,cc_prelink_modules)
+35 -4
tools/objtool/builtin-check.c
··· 9 9 #include <objtool/builtin.h> 10 10 #include <objtool/objtool.h> 11 11 12 + #define ERROR(format, ...) \ 13 + fprintf(stderr, \ 14 + "error: objtool: " format "\n", \ 15 + ##__VA_ARGS__) 16 + 12 17 struct opts opts; 13 18 14 19 static const char * const check_usage[] = { ··· 78 73 OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), 79 74 OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"), 80 75 OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), 81 - OPT_BOOLEAN(0, "lto", &opts.lto, "whole-archive like runs"), 76 + OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"), 82 77 OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"), 83 78 OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"), 84 79 OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"), 85 80 OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), 86 - OPT_BOOLEAN(0, "vmlinux", &opts.vmlinux, "vmlinux.o validation"), 87 81 88 82 OPT_END(), 89 83 }; ··· 128 124 opts.static_call || 129 125 opts.uaccess) { 130 126 if (opts.dump_orc) { 131 - fprintf(stderr, "--dump can't be combined with other options\n"); 127 + ERROR("--dump can't be combined with other options"); 132 128 return false; 133 129 } 134 130 ··· 138 134 if (opts.dump_orc) 139 135 return true; 140 136 141 - fprintf(stderr, "At least one command required\n"); 137 + ERROR("At least one command required"); 142 138 return false; 139 + } 140 + 141 + static bool link_opts_valid(struct objtool_file *file) 142 + { 143 + if (opts.link) 144 + return true; 145 + 146 + if (has_multiple_files(file->elf)) { 147 + ERROR("Linked object detected, forcing --link"); 148 + opts.link = true; 149 + return true; 150 + } 151 + 152 + if (opts.noinstr) { 153 + ERROR("--noinstr requires --link"); 154 + return false; 155 + } 156 + 157 + if (opts.ibt) { 158 + ERROR("--ibt requires --link"); 159 + return false; 160 + } 161 + 162 + return true; 143 163 } 144 164 145 165 int objtool_run(int argc, const char **argv) ··· 183 155 184 156 file = objtool_open_read(objname); 185 157 if (!file) 158 + return 1; 159 + 160 + if (!link_opts_valid(file)) 186 161 return 1; 187 162 188 163 ret = check(file);
+14 -26
tools/objtool/check.c
··· 263 263 cfi->drap_offset = -1; 264 264 } 265 265 266 - static void init_insn_state(struct insn_state *state, struct section *sec) 266 + static void init_insn_state(struct objtool_file *file, struct insn_state *state, 267 + struct section *sec) 267 268 { 268 269 memset(state, 0, sizeof(*state)); 269 270 init_cfi_state(&state->cfi); ··· 274 273 * not correctly determine insn->call_dest->sec (external symbols do 275 274 * not have a section). 276 275 */ 277 - if (opts.vmlinux && opts.noinstr && sec) 276 + if (opts.link && opts.noinstr && sec) 278 277 state->noinstr = sec->noinstr; 279 278 } 280 279 ··· 3406 3405 if (!file->hints) 3407 3406 return 0; 3408 3407 3409 - init_insn_state(&state, sec); 3408 + init_insn_state(file, &state, sec); 3410 3409 3411 3410 if (sec) { 3412 3411 insn = find_insn(file, sec, 0); ··· 3492 3491 return true; 3493 3492 3494 3493 /* 3495 - * Whole archive runs might encounder dead code from weak symbols. 3494 + * Whole archive runs might encounter dead code from weak symbols. 3496 3495 * This is where the linker will have dropped the weak symbol in 3497 3496 * favour of a regular symbol, but leaves the code in place. 3498 3497 * 3499 3498 * In this case we'll find a piece of code (whole function) that is not 3500 3499 * covered by a !section symbol. Ignore them. 3501 3500 */ 3502 - if (!insn->func && opts.lto) { 3501 + if (opts.link && !insn->func) { 3503 3502 int size = find_symbol_hole_containing(insn->sec, insn->offset); 3504 3503 unsigned long end = insn->offset + size; 3505 3504 ··· 3621 3620 if (func->type != STT_FUNC) 3622 3621 continue; 3623 3622 3624 - init_insn_state(&state, sec); 3623 + init_insn_state(file, &state, sec); 3625 3624 set_func_state(&state.cfi); 3626 3625 3627 3626 warnings += validate_symbol(file, sec, func, &state); ··· 3630 3629 return warnings; 3631 3630 } 3632 3631 3633 - static int validate_vmlinux_functions(struct objtool_file *file) 3632 + static int validate_noinstr_sections(struct objtool_file *file) 3634 3633 { 3635 3634 struct section *sec; 3636 3635 int warnings = 0; ··· 3891 3890 { 3892 3891 int ret, warnings = 0; 3893 3892 3894 - if (opts.lto && !(opts.vmlinux || opts.module)) { 3895 - fprintf(stderr, "--lto requires: --vmlinux or --module\n"); 3896 - return 1; 3897 - } 3898 - 3899 - if (opts.ibt && !opts.lto) { 3900 - fprintf(stderr, "--ibt requires: --lto\n"); 3901 - return 1; 3902 - } 3903 - 3904 3893 arch_initial_func_cfi_state(&initial_func_cfi); 3905 3894 init_cfi_state(&init_cfi); 3906 3895 init_cfi_state(&func_cfi); ··· 3910 3919 3911 3920 if (list_empty(&file->insn_list)) 3912 3921 goto out; 3913 - 3914 - if (opts.vmlinux && !opts.lto) { 3915 - ret = validate_vmlinux_functions(file); 3916 - if (ret < 0) 3917 - goto out; 3918 - 3919 - warnings += ret; 3920 - goto out; 3921 - } 3922 3922 3923 3923 if (opts.retpoline) { 3924 3924 ret = validate_retpoline(file); ··· 3935 3953 goto out; 3936 3954 warnings += ret; 3937 3955 } 3956 + 3957 + } else if (opts.noinstr) { 3958 + ret = validate_noinstr_sections(file); 3959 + if (ret < 0) 3960 + goto out; 3961 + warnings += ret; 3938 3962 } 3939 3963 3940 3964 if (opts.ibt) {
+3
tools/objtool/elf.c
··· 377 377 sym->type = GELF_ST_TYPE(sym->sym.st_info); 378 378 sym->bind = GELF_ST_BIND(sym->sym.st_info); 379 379 380 + if (sym->type == STT_FILE) 381 + elf->num_files++; 382 + 380 383 sym->offset = sym->sym.st_value; 381 384 sym->len = sym->sym.st_size; 382 385
+1 -2
tools/objtool/include/objtool/builtin.h
··· 28 28 bool backtrace; 29 29 bool backup; 30 30 bool dryrun; 31 - bool lto; 31 + bool link; 32 32 bool module; 33 33 bool no_unreachable; 34 34 bool sec_address; 35 35 bool stats; 36 - bool vmlinux; 37 36 }; 38 37 39 38 extern struct opts opts;
+11 -1
tools/objtool/include/objtool/elf.h
··· 86 86 int fd; 87 87 bool changed; 88 88 char *name; 89 - unsigned int text_size; 89 + unsigned int text_size, num_files; 90 90 struct list_head sections; 91 91 92 92 int symbol_bits; ··· 129 129 static inline u32 reloc_hash(struct reloc *reloc) 130 130 { 131 131 return sec_offset_hash(reloc->sec, reloc->offset); 132 + } 133 + 134 + /* 135 + * Try to see if it's a whole archive (vmlinux.o or module). 136 + * 137 + * Note this will miss the case where a module only has one source file. 138 + */ 139 + static inline bool has_multiple_files(struct elf *elf) 140 + { 141 + return elf->num_files > 1; 132 142 } 133 143 134 144 struct elf *elf_open_read(const char *name, int flags);