From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754979AbeARO6A (ORCPT ); Thu, 18 Jan 2018 09:58:00 -0500 Received: from bombadil.infradead.org ([65.50.211.133]:43883 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754223AbeARO55 (ORCPT ); Thu, 18 Jan 2018 09:57:57 -0500 Message-Id: <20180118140152.536715831@infradead.org> User-Agent: quilt/0.63-1 Date: Thu, 18 Jan 2018 14:48:18 +0100 From: Peter Zijlstra From: Peter Zijlstra To: David Woodhouse , Thomas Gleixner , Josh Poimboeuf Cc: linux-kernel@vger.kernel.org, Dave Hansen , Ashok Raj , Tim Chen , Andy Lutomirski , Linus Torvalds , Greg KH , Andrea Arcangeli , Andi Kleen , Arjan Van De Ven , Dan Williams , Paolo Bonzini , Jun Nakajima , Asit Mallick , Jason Baron , Peter Zijlstra Subject: [PATCH 18/35] objtool: Another static block fail References: <20180118134800.711245485@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline; filename=peterz-objtool-more-clever-3.patch Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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) --- tools/objtool/check.c | 33 +++++++++++++++++++++++++++++++-- tools/objtool/check.h | 3 ++- 2 files changed, 33 insertions(+), 3 deletions(-) --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -521,7 +521,7 @@ static int add_jump_destinations(struct return -1; } - insn->jump_dest->branch_target = true; + insn->jump_dest->branch_target++; } return 0; @@ -1207,6 +1207,8 @@ static int read_retpoline_hints(struct o 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, bool ign_bt) { @@ -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->jump_dest); insn->static_jump_dest = true; return false; @@ -1238,6 +1241,32 @@ static bool __grow_static_block(struct o return true; } +static void jmp_grow_static_block(struct objtool_file *file, struct instruction *insn) +{ + bool ignore = true; + + /* !jump_dest */ + if (!insn) + return; + + /* more than a single site jumps here, can't be certain */ + if (insn->branch_target > 1) + return; + + for (; &insn->list != &file->insn_list; + insn = list_next_entry(insn, list)) { + + /* + * Per definition the first insn of a jump is a branch target, + * don't terminate because of that. + */ + if (!__grow_static_block(file, insn, ignore)) + break; + + ignore = false; + } +} + static int grow_static_blocks(struct objtool_file *file) { bool static_block = false; --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -45,7 +45,8 @@ struct instruction { unsigned char type; unsigned long immediate; bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; - bool static_jump_dest, retpoline_safe, branch_target; + bool static_jump_dest, retpoline_safe; + int branch_target; struct symbol *call_dest; struct instruction *jump_dest; struct list_head alts;