From: Alexandre Chartre Date: Fri, 21 Nov 2025 09:53:40 +0000 (+0100) Subject: objtool: Trim trailing NOPs in alternative X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c0a67900dc129825c48d3638480297aa00f39c00;p=thirdparty%2Fkernel%2Flinux.git 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 Signed-off-by: Peter Zijlstra (Intel) Acked-by: Josh Poimboeuf Link: https://patch.msgid.link/20251121095340.464045-31-alexandre.chartre@oracle.com --- diff --git a/tools/objtool/disas.c b/tools/objtool/disas.c index f04bc14bef39e..441b9306eafcc 100644 --- a/tools/objtool/disas.c +++ b/tools/objtool/disas.c @@ -52,6 +52,7 @@ struct disas_alt { struct { char *str; /* instruction string */ int offset; /* instruction offset */ + int nops; /* number of nops */ } insn[DISAS_ALT_INSN_MAX]; /* alternative instructions */ int insn_idx; /* index of the next instruction to print */ }; @@ -727,7 +728,7 @@ static int disas_alt_init(struct disas_alt *dalt, } static int disas_alt_add_insn(struct disas_alt *dalt, int index, char *insn_str, - int offset) + int offset, int nops) { int len; @@ -740,6 +741,7 @@ static int disas_alt_add_insn(struct disas_alt *dalt, int index, char *insn_str, len = strlen(insn_str); dalt->insn[index].str = insn_str; dalt->insn[index].offset = offset; + dalt->insn[index].nops = nops; if (len > dalt->width) dalt->width = len; @@ -752,6 +754,7 @@ static int disas_alt_jump(struct disas_alt *dalt) struct instruction *dest_insn; char suffix[2] = { 0 }; char *str; + int nops; orig_insn = dalt->orig_insn; dest_insn = dalt->alt->insn; @@ -762,14 +765,16 @@ static int disas_alt_jump(struct disas_alt *dalt) str = strfmt("jmp%-3s %lx <%s+0x%lx>", suffix, dest_insn->offset, dest_insn->sym->name, dest_insn->offset - dest_insn->sym->offset); + nops = 0; } else { str = strfmt("nop%d", orig_insn->len); + nops = orig_insn->len; } if (!str) return -1; - disas_alt_add_insn(dalt, 0, str, 0); + disas_alt_add_insn(dalt, 0, str, 0, nops); return 1; } @@ -789,7 +794,7 @@ static int disas_alt_extable(struct disas_alt *dalt) if (!str) return -1; - disas_alt_add_insn(dalt, 0, str, 0); + disas_alt_add_insn(dalt, 0, str, 0, 0); return 1; } @@ -805,11 +810,13 @@ static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt) int offset; char *str; int count; + int nops; int err; file = dctx->file; count = 0; offset = 0; + nops = 0; alt_for_each_insn(file, DALT_GROUP(dalt), insn) { @@ -818,7 +825,8 @@ static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt) if (!str) return -1; - err = disas_alt_add_insn(dalt, count, str, offset); + nops = insn->type == INSN_NOP ? insn->len : 0; + err = disas_alt_add_insn(dalt, count, str, offset, nops); if (err) break; offset += insn->len; @@ -834,6 +842,7 @@ static int disas_alt_group(struct disas_context *dctx, struct disas_alt *dalt) static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt) { char *str; + int nops; int err; if (DALT_GROUP(dalt)) @@ -849,7 +858,8 @@ static int disas_alt_default(struct disas_context *dctx, struct disas_alt *dalt) str = strdup(disas_result(dctx)); if (!str) return -1; - err = disas_alt_add_insn(dalt, 0, str, 0); + nops = dalt->orig_insn->type == INSN_NOP ? dalt->orig_insn->len : 0; + err = disas_alt_add_insn(dalt, 0, str, 0, nops); if (err) return -1; @@ -995,6 +1005,62 @@ static void disas_alt_print_compact(char *alt_name, struct disas_alt *dalts, } } +/* + * Trim NOPs in alternatives. This replaces trailing NOPs in alternatives + * with a single indication of the number of bytes covered with NOPs. + * + * Return the maximum numbers of instructions in all alternatives after + * trailing NOPs have been trimmed. + */ +static int disas_alt_trim_nops(struct disas_alt *dalts, int alt_count, + int insn_count) +{ + struct disas_alt *dalt; + int nops_count; + const char *s; + int offset; + int count; + int nops; + int i, j; + + count = 0; + for (i = 0; i < alt_count; i++) { + offset = 0; + nops = 0; + nops_count = 0; + dalt = &dalts[i]; + for (j = insn_count - 1; j >= 0; j--) { + if (!dalt->insn[j].str || !dalt->insn[j].nops) + break; + offset = dalt->insn[j].offset; + free(dalt->insn[j].str); + dalt->insn[j].offset = 0; + dalt->insn[j].str = NULL; + nops += dalt->insn[j].nops; + nops_count++; + } + + /* + * All trailing NOPs have been removed. If there was a single + * NOP instruction then re-add it. If there was a block of + * NOPs then indicate the number of bytes than the block + * covers (nop*). + */ + if (nops_count) { + s = nops_count == 1 ? "" : "*"; + dalt->insn[j + 1].str = strfmt("nop%s%d", s, nops); + dalt->insn[j + 1].offset = offset; + dalt->insn[j + 1].nops = nops; + j++; + } + + if (j > count) + count = j; + } + + return count + 1; +} + /* * Disassemble an alternative. * @@ -1083,6 +1149,8 @@ static void *disas_alt(struct disas_context *dctx, * Print default and non-default alternatives. */ + insn_count = disas_alt_trim_nops(dalts, alt_count, insn_count); + if (opts.wide) disas_alt_print_wide(alt_name, dalts, alt_count, insn_count); else