Skip to content

Commit 9f2899f

Browse files
author
Peter Zijlstra
committed
objtool: Add option to generate prefix symbols
When code is compiled with: -fpatchable-function-entry=${PADDING_BYTES},${PADDING_BYTES} functions will have PADDING_BYTES of NOP in front of them. Unwinders and other things that symbolize code locations will typically attribute these bytes to the preceding function. Given that these bytes nominally belong to the following symbol this mis-attribution is confusing. Inspired by the fact that CFI_CLANG emits __cfi_##name symbols to claim these bytes, allow objtool to emit __pfx_##name symbols to do the same. Therefore add the objtool --prefix=N argument, to conditionally place a __pfx_##name symbol at N bytes ahead of symbol 'name' when: all these preceding bytes are NOP and name-N is an instruction boundary. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Tested-by: Yujie Liu <yujie.liu@intel.com> Link: https://lkml.kernel.org/r/20221028194453.526899822@infradead.org
1 parent 13f60e8 commit 9f2899f

File tree

5 files changed

+67
-1
lines changed

5 files changed

+67
-1
lines changed

tools/objtool/builtin-check.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const struct option check_options[] = {
7575
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
7676
OPT_BOOLEAN(0, "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
7777
OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"),
78+
OPT_INTEGER(0, "prefix", &opts.prefix, "generate prefix symbols"),
7879
OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
7980
OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
8081
OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),

tools/objtool/check.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3417,7 +3417,8 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
34173417

34183418
if (func && insn_func(insn) && func != insn_func(insn)->pfunc) {
34193419
/* Ignore KCFI type preambles, which always fall through */
3420-
if (!strncmp(func->name, "__cfi_", 6))
3420+
if (!strncmp(func->name, "__cfi_", 6) ||
3421+
!strncmp(func->name, "__pfx_", 6))
34213422
return 0;
34223423

34233424
WARN("%s() falls through to next function %s()",
@@ -3972,6 +3973,34 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
39723973
return false;
39733974
}
39743975

3976+
static int add_prefix_symbol(struct objtool_file *file, struct symbol *func,
3977+
struct instruction *insn)
3978+
{
3979+
if (!opts.prefix)
3980+
return 0;
3981+
3982+
for (;;) {
3983+
struct instruction *prev = list_prev_entry(insn, list);
3984+
u64 offset;
3985+
3986+
if (&prev->list == &file->insn_list)
3987+
break;
3988+
3989+
if (prev->type != INSN_NOP)
3990+
break;
3991+
3992+
offset = func->offset - prev->offset;
3993+
if (offset >= opts.prefix) {
3994+
if (offset == opts.prefix)
3995+
elf_create_prefix_symbol(file->elf, func, opts.prefix);
3996+
break;
3997+
}
3998+
insn = prev;
3999+
}
4000+
4001+
return 0;
4002+
}
4003+
39754004
static int validate_symbol(struct objtool_file *file, struct section *sec,
39764005
struct symbol *sym, struct insn_state *state)
39774006
{
@@ -3990,6 +4019,8 @@ static int validate_symbol(struct objtool_file *file, struct section *sec,
39904019
if (!insn || insn->ignore || insn->visited)
39914020
return 0;
39924021

4022+
add_prefix_symbol(file, sym, insn);
4023+
39934024
state->uaccess = sym->uaccess_safe;
39944025

39954026
ret = validate_branch(file, insn_func(insn), insn, *state);

tools/objtool/elf.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,37 @@ elf_create_section_symbol(struct elf *elf, struct section *sec)
819819
return sym;
820820
}
821821

822+
static int elf_add_string(struct elf *elf, struct section *strtab, char *str);
823+
824+
struct symbol *
825+
elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
826+
{
827+
struct symbol *sym = calloc(1, sizeof(*sym));
828+
size_t namelen = strlen(orig->name) + sizeof("__pfx_");
829+
char *name = malloc(namelen);
830+
831+
if (!sym || !name) {
832+
perror("malloc");
833+
return NULL;
834+
}
835+
836+
snprintf(name, namelen, "__pfx_%s", orig->name);
837+
838+
sym->name = name;
839+
sym->sec = orig->sec;
840+
841+
sym->sym.st_name = elf_add_string(elf, NULL, name);
842+
sym->sym.st_info = orig->sym.st_info;
843+
sym->sym.st_value = orig->sym.st_value - size;
844+
sym->sym.st_size = size;
845+
846+
sym = __elf_create_symbol(elf, sym);
847+
if (sym)
848+
elf_add_symbol(elf, sym);
849+
850+
return sym;
851+
}
852+
822853
int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
823854
unsigned long offset, unsigned int type,
824855
struct section *insn_sec, unsigned long insn_off)

tools/objtool/include/objtool/builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct opts {
2626
bool stackval;
2727
bool static_call;
2828
bool uaccess;
29+
int prefix;
2930

3031
/* options: */
3132
bool backtrace;

tools/objtool/include/objtool/elf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ static inline bool has_multiple_files(struct elf *elf)
146146
struct elf *elf_open_read(const char *name, int flags);
147147
struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);
148148

149+
struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
150+
149151
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
150152
unsigned int type, struct symbol *sym, s64 addend);
151153
int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,

0 commit comments

Comments
 (0)