[RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself

Julien Thierry jthierry at redhat.com
Thu Jan 9 08:02:15 PST 2020


Alternatives can contain instructions that jump to another instruction
in the same alternative group. This is actually a common pattern on
arm64.

Keep track of instructions jumping within their own alternative group
and carry on validating such branches.

Signed-off-by: Julien Thierry <jthierry at redhat.com>
---
 tools/objtool/check.c | 48 ++++++++++++++++++++++++++++++++++---------
 tools/objtool/check.h |  1 +
 2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 8f2ff030936d..c7b3f1e2a628 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -722,6 +722,14 @@ static int handle_group_alt(struct objtool_file *file,
 	sec_for_each_insn_from(file, insn) {
 		if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
 			break;
+		/* Is insn a jump to an instruction within the alt_group */
+		if (insn->jump_dest && insn->sec == insn->jump_dest->sec &&
+		    (insn->type == INSN_JUMP_CONDITIONAL ||
+		     insn->type == INSN_JUMP_UNCONDITIONAL)) {
+			dest_off = insn->jump_dest->offset;
+			insn->intra_group_jump = special_alt->orig_off <= dest_off &&
+				dest_off < special_alt->orig_off + special_alt->orig_len;
+		}
 
 		insn->alt_group = true;
 		last_orig_insn = insn;
@@ -1853,14 +1861,33 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
 	return validate_call(insn, state);
 }
 
+static int validate_branch_alt_safe(struct objtool_file *file,
+				    struct symbol *func,
+				    struct instruction *first,
+				    struct insn_state state);
+
+static int validate_branch(struct objtool_file *file, struct symbol *func,
+			   struct instruction *first, struct insn_state state)
+{
+	if (first->alt_group && list_empty(&first->alts)) {
+		WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
+			  first->sec, first->offset);
+		return 1;
+	}
+
+	return validate_branch_alt_safe(file, func, first, state);
+}
+
 /*
  * Follow the branch starting at the given instruction, and recursively follow
  * any other branches (jumps).  Meanwhile, track the frame pointer state at
  * each instruction and validate all the rules described in
  * tools/objtool/Documentation/stack-validation.txt.
  */
-static int validate_branch(struct objtool_file *file, struct symbol *func,
-			   struct instruction *first, struct insn_state state)
+static int validate_branch_alt_safe(struct objtool_file *file,
+				    struct symbol *func,
+				    struct instruction *first,
+				    struct insn_state state)
 {
 	struct alternative *alt;
 	struct instruction *insn, *next_insn;
@@ -1871,12 +1898,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 	insn = first;
 	sec = insn->sec;
 
-	if (insn->alt_group && list_empty(&insn->alts)) {
-		WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
-			  sec, insn->offset);
-		return 1;
-	}
-
 	while (1) {
 		next_insn = next_insn_same_sec(file, insn);
 
@@ -2023,8 +2044,15 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 					return ret;
 
 			} else if (insn->jump_dest) {
-				ret = validate_branch(file, func,
-						      insn->jump_dest, state);
+				if (insn->intra_group_jump)
+					ret = validate_branch_alt_safe(file,
+								       func,
+								       insn->jump_dest,
+								       state);
+				else
+					ret = validate_branch(file, func,
+							      insn->jump_dest,
+							      state);
 				if (ret) {
 					if (backtrace)
 						BT_FUNC("(branch)", insn);
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index af87b55db454..d13ee02f28a4 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -46,6 +46,7 @@ struct instruction {
 	struct stack_op stack_op;
 	struct insn_state state;
 	struct orc_entry orc;
+	bool intra_group_jump;
 };
 
 struct objtool_file {
-- 
2.21.0




More information about the linux-arm-kernel mailing list