objtool_args =                                                         \
        $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label)        \
        $(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr)              \
-       $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt)                     \
+       $(if $(CONFIG_X86_KERNEL_IBT), --ibt)                           \
        $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount)             \
        $(if $(CONFIG_UNWINDER_ORC), --orc)                             \
        $(if $(CONFIG_RETPOLINE), --retpoline)                          \
        $(if $(CONFIG_STACK_VALIDATION), --stackval)                    \
        $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call)          \
        $(if $(CONFIG_X86_SMAP), --uaccess)                             \
+       $(if $(linked-object), --link)                                  \
        $(if $(part-of-module), --module)                               \
        $(if $(CONFIG_GCOV_KERNEL), --no-unreachable)
 
 # modules into native code
 $(obj)/%.prelink.o: objtool-enabled = y
 $(obj)/%.prelink.o: part-of-module := y
+$(obj)/%.prelink.o: linked-object := y
 
 $(obj)/%.prelink.o: $(obj)/%.o FORCE
        $(call if_changed,cc_prelink_modules)
 
 
        if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then
 
-               # Don't perform vmlinux validation unless explicitly requested,
-               # but run objtool on vmlinux.o now that we have an object file.
+               # For LTO and IBT, objtool doesn't run on individual
+               # translation units.  Run everything on vmlinux instead.
 
                if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
                        objtoolopt="${objtoolopt} --hacks=jump_label"
                if is_enabled CONFIG_X86_SMAP; then
                        objtoolopt="${objtoolopt} --uaccess"
                fi
-
-               objtoolopt="${objtoolopt} --lto"
        fi
 
        if is_enabled CONFIG_NOINSTR_VALIDATION; then
                        objtoolopt="${objtoolopt} --no-unreachable"
                fi
 
-               objtoolopt="${objtoolopt} --vmlinux"
+               objtoolopt="${objtoolopt} --link"
 
                info OBJTOOL ${1}
                tools/objtool/objtool ${objtoolopt} ${1}
 
 #include <objtool/builtin.h>
 #include <objtool/objtool.h>
 
+#define ERROR(format, ...)                             \
+       fprintf(stderr,                                 \
+               "error: objtool: " format "\n",         \
+               ##__VA_ARGS__)
+
 struct opts opts;
 
 static const char * const check_usage[] = {
        OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
        OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),
        OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
-       OPT_BOOLEAN(0, "lto", &opts.lto, "whole-archive like runs"),
+       OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
        OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
        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(0, "vmlinux", &opts.vmlinux, "vmlinux.o validation"),
 
        OPT_END(),
 };
            opts.static_call            ||
            opts.uaccess) {
                if (opts.dump_orc) {
-                       fprintf(stderr, "--dump can't be combined with other options\n");
+                       ERROR("--dump can't be combined with other options");
                        return false;
                }
 
        if (opts.dump_orc)
                return true;
 
-       fprintf(stderr, "At least one command required\n");
+       ERROR("At least one command required");
        return false;
 }
 
+static bool link_opts_valid(struct objtool_file *file)
+{
+       if (opts.link)
+               return true;
+
+       if (has_multiple_files(file->elf)) {
+               ERROR("Linked object detected, forcing --link");
+               opts.link = true;
+               return true;
+       }
+
+       if (opts.noinstr) {
+               ERROR("--noinstr requires --link");
+               return false;
+       }
+
+       if (opts.ibt) {
+               ERROR("--ibt requires --link");
+               return false;
+       }
+
+       return true;
+}
+
 int objtool_run(int argc, const char **argv)
 {
        const char *objname;
        if (!file)
                return 1;
 
+       if (!link_opts_valid(file))
+               return 1;
+
        ret = check(file);
        if (ret)
                return ret;
 
        cfi->drap_offset = -1;
 }
 
-static void init_insn_state(struct insn_state *state, struct section *sec)
+static void init_insn_state(struct objtool_file *file, struct insn_state *state,
+                           struct section *sec)
 {
        memset(state, 0, sizeof(*state));
        init_cfi_state(&state->cfi);
         * not correctly determine insn->call_dest->sec (external symbols do
         * not have a section).
         */
-       if (opts.vmlinux && opts.noinstr && sec)
+       if (opts.link && opts.noinstr && sec)
                state->noinstr = sec->noinstr;
 }
 
        if (!file->hints)
                return 0;
 
-       init_insn_state(&state, sec);
+       init_insn_state(file, &state, sec);
 
        if (sec) {
                insn = find_insn(file, sec, 0);
                return true;
 
        /*
-        * Whole archive runs might encounder dead code from weak symbols.
+        * Whole archive runs might encounter dead code from weak symbols.
         * This is where the linker will have dropped the weak symbol in
         * favour of a regular symbol, but leaves the code in place.
         *
         * In this case we'll find a piece of code (whole function) that is not
         * covered by a !section symbol. Ignore them.
         */
-       if (!insn->func && opts.lto) {
+       if (opts.link && !insn->func) {
                int size = find_symbol_hole_containing(insn->sec, insn->offset);
                unsigned long end = insn->offset + size;
 
                if (func->type != STT_FUNC)
                        continue;
 
-               init_insn_state(&state, sec);
+               init_insn_state(file, &state, sec);
                set_func_state(&state.cfi);
 
                warnings += validate_symbol(file, sec, func, &state);
        return warnings;
 }
 
-static int validate_vmlinux_functions(struct objtool_file *file)
+static int validate_noinstr_sections(struct objtool_file *file)
 {
        struct section *sec;
        int warnings = 0;
 {
        int ret, warnings = 0;
 
-       if (opts.lto && !(opts.vmlinux || opts.module)) {
-               fprintf(stderr, "--lto requires: --vmlinux or --module\n");
-               return 1;
-       }
-
-       if (opts.ibt && !opts.lto) {
-               fprintf(stderr, "--ibt requires: --lto\n");
-               return 1;
-       }
-
        arch_initial_func_cfi_state(&initial_func_cfi);
        init_cfi_state(&init_cfi);
        init_cfi_state(&func_cfi);
        if (list_empty(&file->insn_list))
                goto out;
 
-       if (opts.vmlinux && !opts.lto) {
-               ret = validate_vmlinux_functions(file);
-               if (ret < 0)
-                       goto out;
-
-               warnings += ret;
-               goto out;
-       }
-
        if (opts.retpoline) {
                ret = validate_retpoline(file);
                if (ret < 0)
                                goto out;
                        warnings += ret;
                }
+
+       } else if (opts.noinstr) {
+               ret = validate_noinstr_sections(file);
+               if (ret < 0)
+                       goto out;
+               warnings += ret;
        }
 
        if (opts.ibt) {
 
        sym->type = GELF_ST_TYPE(sym->sym.st_info);
        sym->bind = GELF_ST_BIND(sym->sym.st_info);
 
+       if (sym->type == STT_FILE)
+               elf->num_files++;
+
        sym->offset = sym->sym.st_value;
        sym->len = sym->sym.st_size;
 
 
        bool backtrace;
        bool backup;
        bool dryrun;
-       bool lto;
+       bool link;
        bool module;
        bool no_unreachable;
        bool sec_address;
        bool stats;
-       bool vmlinux;
 };
 
 extern struct opts opts;
 
        int fd;
        bool changed;
        char *name;
-       unsigned int text_size;
+       unsigned int text_size, num_files;
        struct list_head sections;
 
        int symbol_bits;
        return sec_offset_hash(reloc->sec, reloc->offset);
 }
 
+/*
+ * Try to see if it's a whole archive (vmlinux.o or module).
+ *
+ * Note this will miss the case where a module only has one source file.
+ */
+static inline bool has_multiple_files(struct elf *elf)
+{
+       return elf->num_files > 1;
+}
+
 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);