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) <pet...@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;
 };
 


Reply via email to