Skip to content

Commit c0a6790

Browse files
achartrePeter Zijlstra
authored andcommitted
objtool: Trim trailing NOPs in alternative
When disassembling alternatives replace trailing NOPs with a single indication of the number of bytes covered with NOPs. Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Josh Poimboeuf <jpoimboe@kernel.org> Link: https://patch.msgid.link/20251121095340.464045-31-alexandre.chartre@oracle.com
1 parent aff95e0 commit c0a6790

1 file changed

Lines changed: 73 additions & 5 deletions

File tree

tools/objtool/disas.c

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct disas_alt {
5252
struct {
5353
char *str; /* instruction string */
5454
int offset; /* instruction offset */
55+
int nops; /* number of nops */
5556
} insn[DISAS_ALT_INSN_MAX]; /* alternative instructions */
5657
int insn_idx; /* index of the next instruction to print */
5758
};
@@ -727,7 +728,7 @@ static int disas_alt_init(struct disas_alt *dalt,
727728
}
728729

729730
static int disas_alt_add_insn(struct disas_alt *dalt, int index, char *insn_str,
730-
int offset)
731+
int offset, int nops)
731732
{
732733
int len;
733734

@@ -740,6 +741,7 @@ static int disas_alt_add_insn(struct disas_alt *dalt, int index, char *insn_str,
740741
len = strlen(insn_str);
741742
dalt->insn[index].str = insn_str;
742743
dalt->insn[index].offset = offset;
744+
dalt->insn[index].nops = nops;
743745
if (len > dalt->width)
744746
dalt->width = len;
745747

@@ -752,6 +754,7 @@ static int disas_alt_jump(struct disas_alt *dalt)
752754
struct instruction *dest_insn;
753755
char suffix[2] = { 0 };
754756
char *str;
757+
int nops;
755758

756759
orig_insn = dalt->orig_insn;
757760
dest_insn = dalt->alt->insn;
@@ -762,14 +765,16 @@ static int disas_alt_jump(struct disas_alt *dalt)
762765
str = strfmt("jmp%-3s %lx <%s+0x%lx>", suffix,
763766
dest_insn->offset, dest_insn->sym->name,
764767
dest_insn->offset - dest_insn->sym->offset);
768+
nops = 0;
765769
} else {
766770
str = strfmt("nop%d", orig_insn->len);
771+
nops = orig_insn->len;
767772
}
768773

769774
if (!str)
770775
return -1;
771776

772-
disas_alt_add_insn(dalt, 0, str, 0);
777+
disas_alt_add_insn(dalt, 0, str, 0, nops);
773778

774779
return 1;
775780
}
@@ -789,7 +794,7 @@ static int disas_alt_extable(struct disas_alt *dalt)
789794
if (!str)
790795
return -1;
791796

792-
disas_alt_add_insn(dalt, 0, str, 0);
797+
disas_alt_add_insn(dalt, 0, str, 0, 0);
793798

794799
return 1;
795800
}
@@ -805,11 +810,13 @@ static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt)
805810
int offset;
806811
char *str;
807812
int count;
813+
int nops;
808814
int err;
809815

810816
file = dctx->file;
811817
count = 0;
812818
offset = 0;
819+
nops = 0;
813820

814821
alt_for_each_insn(file, DALT_GROUP(dalt), insn) {
815822

@@ -818,7 +825,8 @@ static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt)
818825
if (!str)
819826
return -1;
820827

821-
err = disas_alt_add_insn(dalt, count, str, offset);
828+
nops = insn->type == INSN_NOP ? insn->len : 0;
829+
err = disas_alt_add_insn(dalt, count, str, offset, nops);
822830
if (err)
823831
break;
824832
offset += insn->len;
@@ -834,6 +842,7 @@ static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt)
834842
static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt)
835843
{
836844
char *str;
845+
int nops;
837846
int err;
838847

839848
if (DALT_GROUP(dalt))
@@ -849,7 +858,8 @@ static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt)
849858
str = strdup(disas_result(dctx));
850859
if (!str)
851860
return -1;
852-
err = disas_alt_add_insn(dalt, 0, str, 0);
861+
nops = dalt->orig_insn->type == INSN_NOP ? dalt->orig_insn->len : 0;
862+
err = disas_alt_add_insn(dalt, 0, str, 0, nops);
853863
if (err)
854864
return -1;
855865

@@ -995,6 +1005,62 @@ static void disas_alt_print_compact(char *alt_name, struct disas_alt *dalts,
9951005
}
9961006
}
9971007

1008+
/*
1009+
* Trim NOPs in alternatives. This replaces trailing NOPs in alternatives
1010+
* with a single indication of the number of bytes covered with NOPs.
1011+
*
1012+
* Return the maximum numbers of instructions in all alternatives after
1013+
* trailing NOPs have been trimmed.
1014+
*/
1015+
static int disas_alt_trim_nops(struct disas_alt *dalts, int alt_count,
1016+
int insn_count)
1017+
{
1018+
struct disas_alt *dalt;
1019+
int nops_count;
1020+
const char *s;
1021+
int offset;
1022+
int count;
1023+
int nops;
1024+
int i, j;
1025+
1026+
count = 0;
1027+
for (i = 0; i < alt_count; i++) {
1028+
offset = 0;
1029+
nops = 0;
1030+
nops_count = 0;
1031+
dalt = &dalts[i];
1032+
for (j = insn_count - 1; j >= 0; j--) {
1033+
if (!dalt->insn[j].str || !dalt->insn[j].nops)
1034+
break;
1035+
offset = dalt->insn[j].offset;
1036+
free(dalt->insn[j].str);
1037+
dalt->insn[j].offset = 0;
1038+
dalt->insn[j].str = NULL;
1039+
nops += dalt->insn[j].nops;
1040+
nops_count++;
1041+
}
1042+
1043+
/*
1044+
* All trailing NOPs have been removed. If there was a single
1045+
* NOP instruction then re-add it. If there was a block of
1046+
* NOPs then indicate the number of bytes than the block
1047+
* covers (nop*<number-of-bytes>).
1048+
*/
1049+
if (nops_count) {
1050+
s = nops_count == 1 ? "" : "*";
1051+
dalt->insn[j + 1].str = strfmt("nop%s%d", s, nops);
1052+
dalt->insn[j + 1].offset = offset;
1053+
dalt->insn[j + 1].nops = nops;
1054+
j++;
1055+
}
1056+
1057+
if (j > count)
1058+
count = j;
1059+
}
1060+
1061+
return count + 1;
1062+
}
1063+
9981064
/*
9991065
* Disassemble an alternative.
10001066
*
@@ -1083,6 +1149,8 @@ static void *disas_alt(struct disas_context *dctx,
10831149
* Print default and non-default alternatives.
10841150
*/
10851151

1152+
insn_count = disas_alt_trim_nops(dalts, alt_count, insn_count);
1153+
10861154
if (opts.wide)
10871155
disas_alt_print_wide(alt_name, dalts, alt_count, insn_count);
10881156
else

0 commit comments

Comments
 (0)