On Fri, Oct 28, 2022 at 09:40:26PM +0200, Peter Zijlstra wrote:
> 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>
> ---
> tools/objtool/builtin-check.c | 1 +
> tools/objtool/check.c | 27 +++++++++++++++++++++++++++
> tools/objtool/elf.c | 30 ++++++++++++++++++++++++++++++
> tools/objtool/include/objtool/builtin.h | 1 +
> tools/objtool/include/objtool/elf.h | 2 ++
> 5 files changed, 61 insertions(+)
>
> --- a/tools/objtool/builtin-check.c
> +++ b/tools/objtool/builtin-check.c
> @@ -75,6 +75,7 @@ const struct option check_options[] = {
> OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
> OPT_BOOLEAN(0, "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
> OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"),
> + OPT_INTEGER(0, "prefix", &opts.prefix, "generate prefix symbols"),
"generate prefix symbols for function padding with size 'n' bytes" ?
@@ -75,6 +75,7 @@ const struct option check_options[] = {
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
OPT_BOOLEAN(0, "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"),
+ OPT_INTEGER(0, "prefix", &opts.prefix, "generate prefix symbols"),
OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
@@ -3972,6 +3972,31 @@ static bool ignore_unreachable_insn(stru
return false;
}
+static int add_prefix_symbol(struct objtool_file *file, struct symbol *func,
+ struct instruction *insn)
+{
+ if (!opts.prefix)
+ return 0;
+
+ for (;;) {
+ struct instruction *prev = list_prev_entry(insn, list);
+
+ if (&prev->list == &file->insn_list)
+ break;
+
+ if (prev->type != INSN_NOP)
+ break;
+
+ insn = prev;
+ if (func->offset - prev->offset == opts.prefix) {
+ elf_create_prefix_symbol(file->elf, func, -opts.prefix);
+ break;
+ }
+ }
+
+ return 0;
+}
+
static int validate_symbol(struct objtool_file *file, struct section *sec,
struct symbol *sym, struct insn_state *state)
{
@@ -3990,6 +4015,8 @@ static int validate_symbol(struct objtoo
if (!insn || insn->ignore || insn->visited)
return 0;
+ add_prefix_symbol(file, sym, insn);
+
state->uaccess = sym->uaccess_safe;
ret = validate_branch(file, insn_func(insn), insn, *state);
@@ -819,6 +819,36 @@ elf_create_section_symbol(struct elf *el
return sym;
}
+static int elf_add_string(struct elf *elf, struct section *strtab, char *str);
+
+struct symbol *
+elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long addend)
+{
+ struct symbol *sym = calloc(1, sizeof(*sym));
+ size_t namelen = strlen(orig->name) + sizeof("__pfx_");
+ char *name = malloc(namelen);
+
+ if (!sym || !name) {
+ perror("malloc");
+ return NULL;
+ }
+
+ snprintf(name, namelen, "__pfx_%s", orig->name);
+
+ sym->name = name;
+ sym->sec = orig->sec;
+
+ sym->sym.st_name = elf_add_string(elf, NULL, name);
+ sym->sym.st_info = orig->sym.st_info;
+ sym->sym.st_value = orig->sym.st_value + addend;
+
+ sym = __elf_create_symbol(elf, sym);
+ if (sym)
+ elf_add_symbol(elf, sym);
+
+ 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)
@@ -26,6 +26,7 @@ struct opts {
bool stackval;
bool static_call;
bool uaccess;
+ int prefix;
/* options: */
bool backtrace;
@@ -146,6 +146,8 @@ static inline bool has_multiple_files(st
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 symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long addend);
+
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,