From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751956AbeAPTt3 (ORCPT + 1 other); Tue, 16 Jan 2018 14:49:29 -0500 Received: from bombadil.infradead.org ([65.50.211.133]:51689 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751844AbeAPTt2 (ORCPT ); Tue, 16 Jan 2018 14:49:28 -0500 Date: Tue, 16 Jan 2018 20:49:17 +0100 From: Peter Zijlstra To: David Woodhouse , Josh Poimboeuf Cc: linux-kernel@vger.kernel.org, Dave Hansen , Ashok Raj , Thomas Gleixner , Tim Chen , Andy Lutomirski , Linus Torvalds , Greg KH , Andrea Arcangeli , Andi Kleen , Arjan Van De Ven , Dan Williams , Paolo Bonzini , Jun Nakajima , Asit Mallick Subject: [PATCH v2 11/10] objtool: Even more complex static block checks Message-ID: <20180116194917.GH2228@hirez.programming.kicks-ass.net> References: <20180116142825.376986833@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180116142825.376986833@infradead.org> User-Agent: Mutt/1.9.2 (2017-12-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Return-Path: Subject: objtool: Even more complex static block checks From: Peter Zijlstra Date: Tue Jan 16 20:17:01 CET 2018 I've observed GCC transform: f() { if (!static_branch_unlikely()) return; static_assert(); A; } g() { f(); } Into: f() { static_assert(); A; } g() { if (static_branch_unlikely()) f(); } Which results in the assertion landing at f+0. The transformation is valid and useful; it avoids a pointless CALL+RET sequence, so we'll have to teach objtool how to deal with this. Do this by marking all CALL destinations with static_call when called from a static_block and non_static_call when called outside a static_block. This allows us to identify functions called exclusively from a static_block and start them with a static_block. Signed-off-by: Peter Zijlstra (Intel) --- tools/objtool/check.c | 77 ++++++++++++++++++++++++++++++++++++-------------- tools/objtool/elf.h | 1 2 files changed, 57 insertions(+), 21 deletions(-) --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1199,36 +1199,71 @@ static int read_retpoline_hints(struct o return 0; } +static void __grow_static_block(struct instruction *insn, bool *state) +{ + if (!*state && !insn->static_jump_dest) + return; + + if (insn->static_jump_dest) { + *state = true; + return; + } + + if (insn->branch_target) { + *state = false; + return; + + } else switch (insn->type) { + case INSN_JUMP_CONDITIONAL: + case INSN_JUMP_UNCONDITIONAL: + case INSN_JUMP_DYNAMIC: + case INSN_CALL_DYNAMIC: + case INSN_RETURN: + case INSN_BUG: + *state = false; + return; + } + + insn->static_jump_dest = *state; +} + static int grow_static_blocks(struct objtool_file *file) { - struct instruction *insn; bool static_block = false; + struct symbol *func, *tmp; + struct instruction *insn; + struct section *sec; for_each_insn(file, insn) { - if (!static_block && !insn->static_jump_dest) - continue; + __grow_static_block(insn, &static_block); - if (insn->static_jump_dest) { - static_block = true; - continue; - } + if (insn->type == INSN_CALL) { + func = insn->call_dest; - if (insn->branch_target) { - static_block = false; - continue; - } else switch (insn->type) { - case INSN_JUMP_CONDITIONAL: - case INSN_JUMP_UNCONDITIONAL: - case INSN_JUMP_DYNAMIC: - case INSN_CALL: - case INSN_CALL_DYNAMIC: - case INSN_RETURN: - case INSN_BUG: - static_block = false; - continue; + if (static_block) + func->static_call = true; + else + func->non_static_call = true; } + } + + for_each_sec(file, sec) { + list_for_each_entry_safe(func, tmp, &sec->symbol_list, list) { + if (!func->static_call) + continue; - insn->static_jump_dest = static_block; + if (func->non_static_call) + continue; + + /* static && !non_static -- only static callers */ + + static_block = true; + func_for_each_insn(file, func, insn) { + __grow_static_block(insn, &static_block); + if (!static_block) + break; + } + } } return 0; --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -61,6 +61,7 @@ struct symbol { unsigned char bind, type; unsigned long offset; unsigned int len; + bool static_call, non_static_call; }; struct rela {