Skip to content

Commit 753da41

Browse files
jpoimboePeter Zijlstra
authored andcommitted
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 <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Miroslav Benes <[email protected]> Link: https://lkml.kernel.org/r/dcd3ceffd15a54822c6183e5766d21ad06082b45.1650300597.git.jpoimboe@redhat.com
1 parent 489e355 commit 753da41

File tree

7 files changed

+70
-39
lines changed

7 files changed

+70
-39
lines changed

scripts/Makefile.build

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,15 @@ objtool := $(objtree)/tools/objtool/objtool
229229
objtool_args = \
230230
$(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \
231231
$(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr) \
232-
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
232+
$(if $(CONFIG_X86_KERNEL_IBT), --ibt) \
233233
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
234234
$(if $(CONFIG_UNWINDER_ORC), --orc) \
235235
$(if $(CONFIG_RETPOLINE), --retpoline) \
236236
$(if $(CONFIG_SLS), --sls) \
237237
$(if $(CONFIG_STACK_VALIDATION), --stackval) \
238238
$(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call) \
239239
$(if $(CONFIG_X86_SMAP), --uaccess) \
240+
$(if $(linked-object), --link) \
240241
$(if $(part-of-module), --module) \
241242
$(if $(CONFIG_GCOV_KERNEL), --no-unreachable)
242243

@@ -306,6 +307,7 @@ quiet_cmd_cc_prelink_modules = LD [M] $@
306307
# modules into native code
307308
$(obj)/%.prelink.o: objtool-enabled = y
308309
$(obj)/%.prelink.o: part-of-module := y
310+
$(obj)/%.prelink.o: linked-object := y
309311

310312
$(obj)/%.prelink.o: $(obj)/%.o FORCE
311313
$(call if_changed,cc_prelink_modules)

scripts/link-vmlinux.sh

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ objtool_link()
114114

115115
if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then
116116

117-
# Don't perform vmlinux validation unless explicitly requested,
118-
# but run objtool on vmlinux.o now that we have an object file.
117+
# For LTO and IBT, objtool doesn't run on individual
118+
# translation units. Run everything on vmlinux instead.
119119

120120
if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
121121
objtoolopt="${objtoolopt} --hacks=jump_label"
@@ -156,8 +156,6 @@ objtool_link()
156156
if is_enabled CONFIG_X86_SMAP; then
157157
objtoolopt="${objtoolopt} --uaccess"
158158
fi
159-
160-
objtoolopt="${objtoolopt} --lto"
161159
fi
162160

163161
if is_enabled CONFIG_NOINSTR_VALIDATION; then
@@ -170,7 +168,7 @@ objtool_link()
170168
objtoolopt="${objtoolopt} --no-unreachable"
171169
fi
172170

173-
objtoolopt="${objtoolopt} --vmlinux"
171+
objtoolopt="${objtoolopt} --link"
174172

175173
info OBJTOOL ${1}
176174
tools/objtool/objtool ${objtoolopt} ${1}

tools/objtool/builtin-check.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
#include <objtool/builtin.h>
1010
#include <objtool/objtool.h>
1111

12+
#define ERROR(format, ...) \
13+
fprintf(stderr, \
14+
"error: objtool: " format "\n", \
15+
##__VA_ARGS__)
16+
1217
struct opts opts;
1318

1419
static const char * const check_usage[] = {
@@ -73,12 +78,11 @@ const struct option check_options[] = {
7378
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
7479
OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),
7580
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
76-
OPT_BOOLEAN(0, "lto", &opts.lto, "whole-archive like runs"),
81+
OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
7782
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
7883
OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
7984
OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
8085
OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
81-
OPT_BOOLEAN(0, "vmlinux", &opts.vmlinux, "vmlinux.o validation"),
8286

8387
OPT_END(),
8488
};
@@ -124,7 +128,7 @@ static bool opts_valid(void)
124128
opts.static_call ||
125129
opts.uaccess) {
126130
if (opts.dump_orc) {
127-
fprintf(stderr, "--dump can't be combined with other options\n");
131+
ERROR("--dump can't be combined with other options");
128132
return false;
129133
}
130134

@@ -134,10 +138,34 @@ static bool opts_valid(void)
134138
if (opts.dump_orc)
135139
return true;
136140

137-
fprintf(stderr, "At least one command required\n");
141+
ERROR("At least one command required");
138142
return false;
139143
}
140144

145+
static bool link_opts_valid(struct objtool_file *file)
146+
{
147+
if (opts.link)
148+
return true;
149+
150+
if (has_multiple_files(file->elf)) {
151+
ERROR("Linked object detected, forcing --link");
152+
opts.link = true;
153+
return true;
154+
}
155+
156+
if (opts.noinstr) {
157+
ERROR("--noinstr requires --link");
158+
return false;
159+
}
160+
161+
if (opts.ibt) {
162+
ERROR("--ibt requires --link");
163+
return false;
164+
}
165+
166+
return true;
167+
}
168+
141169
int objtool_run(int argc, const char **argv)
142170
{
143171
const char *objname;
@@ -157,6 +185,9 @@ int objtool_run(int argc, const char **argv)
157185
if (!file)
158186
return 1;
159187

188+
if (!link_opts_valid(file))
189+
return 1;
190+
160191
ret = check(file);
161192
if (ret)
162193
return ret;

tools/objtool/check.c

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ static void init_cfi_state(struct cfi_state *cfi)
263263
cfi->drap_offset = -1;
264264
}
265265

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)
267268
{
268269
memset(state, 0, sizeof(*state));
269270
init_cfi_state(&state->cfi);
@@ -273,7 +274,7 @@ static void init_insn_state(struct insn_state *state, struct section *sec)
273274
* not correctly determine insn->call_dest->sec (external symbols do
274275
* not have a section).
275276
*/
276-
if (opts.vmlinux && opts.noinstr && sec)
277+
if (opts.link && opts.noinstr && sec)
277278
state->noinstr = sec->noinstr;
278279
}
279280

@@ -3405,7 +3406,7 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
34053406
if (!file->hints)
34063407
return 0;
34073408

3408-
init_insn_state(&state, sec);
3409+
init_insn_state(file, &state, sec);
34093410

34103411
if (sec) {
34113412
insn = find_insn(file, sec, 0);
@@ -3491,14 +3492,14 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
34913492
return true;
34923493

34933494
/*
3494-
* Whole archive runs might encounder dead code from weak symbols.
3495+
* Whole archive runs might encounter dead code from weak symbols.
34953496
* This is where the linker will have dropped the weak symbol in
34963497
* favour of a regular symbol, but leaves the code in place.
34973498
*
34983499
* In this case we'll find a piece of code (whole function) that is not
34993500
* covered by a !section symbol. Ignore them.
35003501
*/
3501-
if (!insn->func && opts.lto) {
3502+
if (opts.link && !insn->func) {
35023503
int size = find_symbol_hole_containing(insn->sec, insn->offset);
35033504
unsigned long end = insn->offset + size;
35043505

@@ -3620,7 +3621,7 @@ static int validate_section(struct objtool_file *file, struct section *sec)
36203621
if (func->type != STT_FUNC)
36213622
continue;
36223623

3623-
init_insn_state(&state, sec);
3624+
init_insn_state(file, &state, sec);
36243625
set_func_state(&state.cfi);
36253626

36263627
warnings += validate_symbol(file, sec, func, &state);
@@ -3629,7 +3630,7 @@ static int validate_section(struct objtool_file *file, struct section *sec)
36293630
return warnings;
36303631
}
36313632

3632-
static int validate_vmlinux_functions(struct objtool_file *file)
3633+
static int validate_noinstr_sections(struct objtool_file *file)
36333634
{
36343635
struct section *sec;
36353636
int warnings = 0;
@@ -3890,16 +3891,6 @@ int check(struct objtool_file *file)
38903891
{
38913892
int ret, warnings = 0;
38923893

3893-
if (opts.lto && !(opts.vmlinux || opts.module)) {
3894-
fprintf(stderr, "--lto requires: --vmlinux or --module\n");
3895-
return 1;
3896-
}
3897-
3898-
if (opts.ibt && !opts.lto) {
3899-
fprintf(stderr, "--ibt requires: --lto\n");
3900-
return 1;
3901-
}
3902-
39033894
arch_initial_func_cfi_state(&initial_func_cfi);
39043895
init_cfi_state(&init_cfi);
39053896
init_cfi_state(&func_cfi);
@@ -3920,15 +3911,6 @@ int check(struct objtool_file *file)
39203911
if (list_empty(&file->insn_list))
39213912
goto out;
39223913

3923-
if (opts.vmlinux && !opts.lto) {
3924-
ret = validate_vmlinux_functions(file);
3925-
if (ret < 0)
3926-
goto out;
3927-
3928-
warnings += ret;
3929-
goto out;
3930-
}
3931-
39323914
if (opts.retpoline) {
39333915
ret = validate_retpoline(file);
39343916
if (ret < 0)
@@ -3953,6 +3935,12 @@ int check(struct objtool_file *file)
39533935
goto out;
39543936
warnings += ret;
39553937
}
3938+
3939+
} else if (opts.noinstr) {
3940+
ret = validate_noinstr_sections(file);
3941+
if (ret < 0)
3942+
goto out;
3943+
warnings += ret;
39563944
}
39573945

39583946
if (opts.ibt) {

tools/objtool/elf.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,9 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)
377377
sym->type = GELF_ST_TYPE(sym->sym.st_info);
378378
sym->bind = GELF_ST_BIND(sym->sym.st_info);
379379

380+
if (sym->type == STT_FILE)
381+
elf->num_files++;
382+
380383
sym->offset = sym->sym.st_value;
381384
sym->len = sym->sym.st_size;
382385

tools/objtool/include/objtool/builtin.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,11 @@ struct opts {
2828
bool backtrace;
2929
bool backup;
3030
bool dryrun;
31-
bool lto;
31+
bool link;
3232
bool module;
3333
bool no_unreachable;
3434
bool sec_address;
3535
bool stats;
36-
bool vmlinux;
3736
};
3837

3938
extern struct opts opts;

tools/objtool/include/objtool/elf.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ struct elf {
8686
int fd;
8787
bool changed;
8888
char *name;
89-
unsigned int text_size;
89+
unsigned int text_size, num_files;
9090
struct list_head sections;
9191

9292
int symbol_bits;
@@ -131,6 +131,16 @@ static inline u32 reloc_hash(struct reloc *reloc)
131131
return sec_offset_hash(reloc->sec, reloc->offset);
132132
}
133133

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;
142+
}
143+
134144
struct elf *elf_open_read(const char *name, int flags);
135145
struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);
136146

0 commit comments

Comments
 (0)