lkml.org 
[lkml]   [2018]   [Jan]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH 20/24] objtool: Another static block fail
I've observed GCC generate:

sym:
NOP/JMP 1f (static_branch)
JMP 2f
1: /* crud */
JMP 3f
2: /* other crud */

3: RETQ


This means we need to follow unconditional jumps; be conservative and
only follow if its a unique jump.

(I've not yet figured out which CONFIG option is responsible for this,
a normal defconfig build does not generate crap like this)

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
tools/objtool/check.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++---
tools/objtool/elf.h | 2 -
2 files changed, 51 insertions(+), 4 deletions(-)

--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1207,6 +1207,8 @@ static int assert_static_jumps(struct ob
return 0;
}

+static void jmp_grow_static_block(struct objtool_file *file, struct instruction *insn);
+
static bool __grow_static_block(struct objtool_file *file,
struct instruction *insn)
{
@@ -1216,7 +1218,8 @@ static bool __grow_static_block(struct o

switch (insn->type) {
case INSN_JUMP_UNCONDITIONAL:
- /* mark this instruction, terminate this section */
+ /* follow the jump, mark this instruction, terminate this section */
+ jmp_grow_static_block(file, insn);
insn->static_jump_dest = true;
return false;

@@ -1238,6 +1241,50 @@ static bool __grow_static_block(struct o
return true;
}

+static void jmp_grow_static_block(struct objtool_file *file, struct instruction *insn)
+{
+ struct instruction *dest = insn->jump_dest;
+ bool old_sjd, static_block;
+
+ if (!dest)
+ return;
+
+ /* more than a single site jumps here, can't be certain */
+ if (dest->branch_target > 1)
+ return;
+
+ /* mark the destination, so we can continue there */
+ old_sjd = dest->static_jump_dest;
+ dest->static_jump_dest = true;
+
+ if (dest->offset > insn->offset) {
+ /* fwd jump, the main iteration will still get there. */
+ return;
+ }
+
+ /* backwards jump, we need to revisit the instructions */
+ do {
+ static_block = __grow_static_block(file, dest);
+
+ if (insn->type == INSN_CALL && !old_sjd && dest->static_jump_dest) {
+ struct symbol *func = insn->call_dest;
+ if (!func || func->bind != STB_LOCAL)
+ goto next;
+
+ /*
+ * we flipped the call to static, update the stats.
+ */
+ if (insn->static_jump_dest) {
+ func->non_static_call--;
+ func->static_call++;
+ }
+ }
+next:
+ dest = list_next_entry(dest, list);
+ old_sjd = dest->static_jump_dest;
+ } while (static_block && dest != insn);
+}
+
static int grow_static_blocks(struct objtool_file *file)
{
bool static_block = false;
@@ -1255,9 +1302,9 @@ static int grow_static_blocks(struct obj
continue;

if (static_block)
- func->static_call = true;
+ func->static_call++;
else
- func->non_static_call = true;
+ func->non_static_call++;
}
}

--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -61,7 +61,7 @@ struct symbol {
unsigned char bind, type;
unsigned long offset;
unsigned int len;
- bool static_call, non_static_call;
+ unsigned int static_call, non_static_call;
};

struct rela {

\
 
 \ /
  Last update: 2018-01-23 16:41    [W:0.441 / U:0.116 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site