Commit b23cc71c authored by Josh Poimboeuf's avatar Josh Poimboeuf

objtool: Add 'alt_group' struct

Create a new struct associated with each group of alternatives
instructions.  This will help with the removal of fake jumps, and more
importantly with adding support for stack layout changes in
alternatives.
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
parent ab4e0744
...@@ -992,20 +992,28 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -992,20 +992,28 @@ static int handle_group_alt(struct objtool_file *file,
struct instruction *orig_insn, struct instruction *orig_insn,
struct instruction **new_insn) struct instruction **new_insn)
{ {
static unsigned int alt_group_next_index = 1;
struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL;
unsigned int alt_group = alt_group_next_index++; struct alt_group *orig_alt_group, *new_alt_group;
unsigned long dest_off; unsigned long dest_off;
orig_alt_group = malloc(sizeof(*orig_alt_group));
if (!orig_alt_group) {
WARN("malloc failed");
return -1;
}
last_orig_insn = NULL; last_orig_insn = NULL;
insn = orig_insn; insn = orig_insn;
sec_for_each_insn_from(file, insn) { sec_for_each_insn_from(file, insn) {
if (insn->offset >= special_alt->orig_off + special_alt->orig_len) if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
break; break;
insn->alt_group = alt_group; insn->alt_group = orig_alt_group;
last_orig_insn = insn; last_orig_insn = insn;
} }
orig_alt_group->orig_group = NULL;
orig_alt_group->first_insn = orig_insn;
orig_alt_group->last_insn = last_orig_insn;
if (next_insn_same_sec(file, last_orig_insn)) { if (next_insn_same_sec(file, last_orig_insn)) {
fake_jump = malloc(sizeof(*fake_jump)); fake_jump = malloc(sizeof(*fake_jump));
...@@ -1036,8 +1044,13 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -1036,8 +1044,13 @@ static int handle_group_alt(struct objtool_file *file,
return 0; return 0;
} }
new_alt_group = malloc(sizeof(*new_alt_group));
if (!new_alt_group) {
WARN("malloc failed");
return -1;
}
last_new_insn = NULL; last_new_insn = NULL;
alt_group = alt_group_next_index++;
insn = *new_insn; insn = *new_insn;
sec_for_each_insn_from(file, insn) { sec_for_each_insn_from(file, insn) {
struct reloc *alt_reloc; struct reloc *alt_reloc;
...@@ -1049,7 +1062,7 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -1049,7 +1062,7 @@ static int handle_group_alt(struct objtool_file *file,
insn->ignore = orig_insn->ignore_alts; insn->ignore = orig_insn->ignore_alts;
insn->func = orig_insn->func; insn->func = orig_insn->func;
insn->alt_group = alt_group; insn->alt_group = new_alt_group;
/* /*
* Since alternative replacement code is copy/pasted by the * Since alternative replacement code is copy/pasted by the
...@@ -1098,6 +1111,10 @@ static int handle_group_alt(struct objtool_file *file, ...@@ -1098,6 +1111,10 @@ static int handle_group_alt(struct objtool_file *file,
return -1; return -1;
} }
new_alt_group->orig_group = orig_alt_group;
new_alt_group->first_insn = *new_insn;
new_alt_group->last_insn = last_new_insn;
if (fake_jump) if (fake_jump)
list_add(&fake_jump->list, &last_new_insn->list); list_add(&fake_jump->list, &last_new_insn->list);
...@@ -2451,7 +2468,7 @@ static int validate_return(struct symbol *func, struct instruction *insn, struct ...@@ -2451,7 +2468,7 @@ static int validate_return(struct symbol *func, struct instruction *insn, struct
static void fill_alternative_cfi(struct objtool_file *file, struct instruction *insn) static void fill_alternative_cfi(struct objtool_file *file, struct instruction *insn)
{ {
struct instruction *first_insn = insn; struct instruction *first_insn = insn;
int alt_group = insn->alt_group; struct alt_group *alt_group = insn->alt_group;
sec_for_each_insn_continue(file, insn) { sec_for_each_insn_continue(file, insn) {
if (insn->alt_group != alt_group) if (insn->alt_group != alt_group)
......
...@@ -19,6 +19,17 @@ struct insn_state { ...@@ -19,6 +19,17 @@ struct insn_state {
s8 instr; s8 instr;
}; };
struct alt_group {
/*
* Pointer from a replacement group to the original group. NULL if it
* *is* the original group.
*/
struct alt_group *orig_group;
/* First and last instructions in the group */
struct instruction *first_insn, *last_insn;
};
struct instruction { struct instruction {
struct list_head list; struct list_head list;
struct hlist_node hash; struct hlist_node hash;
...@@ -34,7 +45,7 @@ struct instruction { ...@@ -34,7 +45,7 @@ struct instruction {
s8 instr; s8 instr;
u8 visited; u8 visited;
u8 ret_offset; u8 ret_offset;
int alt_group; struct alt_group *alt_group;
struct symbol *call_dest; struct symbol *call_dest;
struct instruction *jump_dest; struct instruction *jump_dest;
struct instruction *first_jump_src; struct instruction *first_jump_src;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment