[PATCH 4/6] objtool: Replace STACK_FRAME_NON_STANDARD annotation

Peter Zijlstra
2019-02-25T12:53:17Z

Replace the existing STACK_FRAME_NON_STANDARD annotation with a
'better' scheme.

The old annotation works by taking the address of a function; this
is visible to the compiler and might affect code generation (the
function pointer escapes). The new annotation simply stores the
function name and has objtool do a symtab lookup.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
include/linux/frame.h | 19 +++++++++++++---
tools/objtool/check.c | 58 +++++++++++++++++++++-----------------------------
tools/objtool/check.h | 1
3 files changed, 41 insertions(+), 37 deletions(-)

--- a/include/linux/frame.h
+++ b/include/linux/frame.h
@@ -11,9 +11,22 @@
*
* For more information, see tools/objtool/Documentation/stack-validation.txt.
*/
-#define STACK_FRAME_NON_STANDARD(func) \
- static void __used __section(.discard.func_stack_frame_non_standard) \
- *__func_stack_frame_non_standard_##func = func
+#define STACK_FRAME_NON_STANDARD(func) \
+ asm (".pushsection .discard.nonstd_frame_strtab, \"S\", @3\n\t" \
+ "999: .ascii \"" #func "\"\n\t" \
+ " .byte 0\n\t" \
+ ".popsection\n\t" \
+ ".pushsection .discard.nonstd_frame\n\t" \
+ ".long 999b - .\n\t" \
+ ".popsection\n\t")
+
+/*
+ * SHT_STRTAB(@3) sections should start with a \0 byte such that the 0 offset
+ * encodes the NULL string.
+ */
+asm (".pushsection .discard.nonstd_frame_strtab, \"S\", @3\n\t"
+ ".byte 0\n\t"
+ ".popsection\n\t");

#else /* !CONFIG_STACK_VALIDATION */

--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -105,29 +105,6 @@ static struct instruction *next_insn_sam
insn = next_insn_same_sec(file, insn))

/*
- * Check if the function has been manually whitelisted with the
- * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted
- * due to its use of a context switching instruction.
- */
-static bool ignore_func(struct objtool_file *file, struct symbol *func)
-{
- struct rela *rela;
-
- /* check for STACK_FRAME_NON_STANDARD */
- if (file->whitelist && file->whitelist->rela)
- list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) {
- if (rela->sym->type == STT_SECTION &&
- rela->sym->sec == func->sec &&
- rela->addend == func->offset)
- return true;
- if (rela->sym->type == STT_FUNC && rela->sym == func)
- return true;
- }
-
- return false;
-}
-
-/*
* This checks to see if the given function is a "noreturn" function.
*
* For global functions which are outside the scope of this object file, we
@@ -434,21 +411,37 @@ static int add_dead_ends(struct objtool_
static void add_ignores(struct objtool_file *file)
{
struct instruction *insn;
- struct section *sec;
+ struct section *strtab_sec, *sec;
struct symbol *func;
+ struct rela *rela;
+ const char *name;

- for_each_sec(file, sec) {
- list_for_each_entry(func, &sec->symbol_list, list) {
- if (func->type != STT_FUNC)
- continue;
+ sec = find_section_by_name(file->elf, ".rela.discard.nonstd_frame");
+ if (!sec)
+ return;

- if (!ignore_func(file, func))
- continue;
+ strtab_sec = find_section_by_name(file->elf, ".discard.nonstd_frame_strtab");
+ if (!strtab_sec) {
+ WARN("missing nonstd_frame strtab");
+ return;
+ }

- func_for_each_insn_all(file, func, insn)
- insn->ignore = true;
+ list_for_each_entry(rela, &sec->rela_list, list) {
+ if (rela->sym->type != STT_SECTION) {
+ WARN("unexpected relocation symbol type in %s", sec->name);
+ return;
}
+
+ name = elf_strptr(file->elf->elf, strtab_sec->idx, rela->addend);
+ func = find_symbol_by_name(file->elf, name);
+ if (!func)
+ continue;
+
+ func_for_each_insn_all(file, func, insn)
+ insn->ignore = true;
}
+
+ return;
}

/*
@@ -2198,7 +2191,6 @@ int check(const char *_objname, bool orc

INIT_LIST_HEAD(&file.insn_list);
hash_init(file.insn_hash);
- file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard");
file.c_file = find_section_by_name(file.elf, ".comment");
file.ignore_unreachables = no_unreachable;
file.hints = false;
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -60,7 +60,6 @@ struct objtool_file {
struct elf *elf;
struct list_head insn_list;
DECLARE_HASHTABLE(insn_hash, 16);
- struct section *whitelist;
bool ignore_unreachables, c_file, hints, rodata;
};