From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Google-Smtp-Source: AH8x225Q/xpXiWSc+dF/rKwEZVFknIwDWBB8h75fcSfOJFzEtJuZ0NLwkyQQ4mGW0TSOb6/IyMAz ARC-Seal: i=1; a=rsa-sha256; t=1516721589; cv=none; d=google.com; s=arc-20160816; b=DC3aHZsIaZV7Mizurq5uN/dIZLpl5wyX7ZLrQEY67s8jwN1zO8X0qv/jly77vJjnbu oilMCL6C23YqFIOiyyWWMzEWXkqSHNgrg7FROTYONmPS/nNPkZ+ikciBSayEAE5ALiAX 5FpeOeTKDmy+GfYeDrOQg0oTu1CzO+wjaZ4uDGV/qhSGDlU1WWa6EmTHZUlNDfK/C2of hJIyvEIW54tAptpoP3g2bQk5luWguSRK7XJPjf/BW61M0v7KJ6uqDWF93XoLPcbJlrGe bXpiKJEQ/xFep8wZnx47vnIPY6vGJqrqvDK/ku9+Um2c02bW99t1L1yvOW5sPIStXTAN hmXQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-disposition:mime-version:references:subject:cc:to:from:date :user-agent:message-id:dkim-signature:arc-authentication-results; bh=hSptd7F3rixw60+3QLL50cBtl6OlWc3EGEMa3TL8Npk=; b=TZcYnpaHu/gnA7TrndwwbBnUYtBTEDISuMzezKmAixPdJeZJfD6OkL5T3XFU4u83/Y 6xdMiTlZD4wx2ceofDHtDaJOfeojTlV/mmat3vRXI8Y614V3fTCdGLXGIf3ZHB9F6dTA +gsM/HBCHXllTiuGUb5rAEzEECQVpmzNGZ0hyTTaMeAXWb/gbQiA2GmPs75otaVm2fjm K8TmBpahNpkQWV+5ZlhP9lzgIakecr4+OdhCmw7ROy9HxgVjne4ktkVdXhFYusQAweC5 dVBMSt1eWq9HMzDHhi4f9Js1CRqCza/D7SmmPqLOZlfCeFvsZmFbnw/cYUMKtIPfK/bM 13uw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@infradead.org header.s=merlin.20170209 header.b=GriVmmW4; spf=pass (google.com: best guess record for domain of peterz@infradead.org designates 205.233.59.134 as permitted sender) smtp.mailfrom=peterz@infradead.org Authentication-Results: mx.google.com; dkim=pass header.i=@infradead.org header.s=merlin.20170209 header.b=GriVmmW4; spf=pass (google.com: best guess record for domain of peterz@infradead.org designates 205.233.59.134 as permitted sender) smtp.mailfrom=peterz@infradead.org Message-Id: <20180123152639.110978794@infradead.org> User-Agent: quilt/0.63-1 Date: Tue, 23 Jan 2018 16:25:58 +0100 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 19/24] objtool: Even more complex static block checks References: <20180123152539.374360046@infradead.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline; filename=peterz-objtool-more-clever.patch X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: =?utf-8?q?1590397857398741682?= X-GMAIL-MSGID: =?utf-8?q?1590397857398741682?= X-Mailing-List: linux-kernel@vger.kernel.org List-ID: 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. Limit to static functions and do not apply recursive. Signed-off-by: Peter Zijlstra (Intel) --- tools/objtool/check.c | 84 +++++++++++++++++++++++++++++++++++++------------- tools/objtool/elf.h | 1 2 files changed, 64 insertions(+), 21 deletions(-) --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1207,36 +1207,78 @@ static int assert_static_jumps(struct ob return 0; } +static bool __grow_static_block(struct objtool_file *file, + struct instruction *insn) +{ + /* if a !static jump can come in here, terminate */ + if (insn->branch_target && !insn->static_jump_dest) + return false; + + switch (insn->type) { + case INSN_JUMP_UNCONDITIONAL: + /* mark this instruction, terminate this section */ + insn->static_jump_dest = true; + return false; + + /* these disturb unconditional code flow, terminate */ + case INSN_JUMP_CONDITIONAL: + case INSN_JUMP_DYNAMIC: + case INSN_RETURN: + case INSN_BUG: + return false; + + /* these return right back and don't disturb the code flow */ + case INSN_CALL: + case INSN_CALL_DYNAMIC: + break; + } + + /* mark this insn, and continue the section */ + insn->static_jump_dest = true; + return true; +} + 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; + if (static_block || insn->static_jump_dest) + static_block = __grow_static_block(file, insn); - if (insn->static_jump_dest) { - static_block = true; - continue; + if (insn->type == INSN_CALL) { + func = insn->call_dest; + if (!func) + continue; + + if (static_block) + func->static_call = true; + else + func->non_static_call = true; } + } - 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; + for_each_sec(file, sec) { + list_for_each_entry_safe(func, tmp, &sec->symbol_list, list) { + if (func->bind != STB_LOCAL) + continue; + + if (!func->static_call) + continue; + + if (func->non_static_call) + continue; + + /* static && !non_static -- only static callers */ + + func_for_each_insn(file, func, insn) { + if (!__grow_static_block(file, insn)) + break; + } } - - insn->static_jump_dest = static_block; } 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 {