summaryrefslogtreecommitdiff
path: root/tools/objtool
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@kernel.org>2026-03-06 09:35:06 -0800
committerJosh Poimboeuf <jpoimboe@kernel.org>2026-03-09 08:45:10 -0700
commit7fdaa640c810cb42090a182c33f905bcc47a616a (patch)
treee5bd0269fc4677d89ecc064112b026533be390af /tools/objtool
parent1fd1dc41724319406b0aff221a352a400b0ddfc5 (diff)
objtool: Handle Clang RSP musical chairs
For no apparent reason (possibly related to CONFIG_KMSAN), Clang can randomly pass the value of RSP to other registers and then back again to RSP. Handle that accordingly. Fixes the following warnings: drivers/input/misc/uinput.o: warning: objtool: uinput_str_to_user+0x165: undefined stack state drivers/input/misc/uinput.o: warning: objtool: uinput_str_to_user+0x165: unknown CFA base reg -1 Reported-by: Arnd Bergmann <arnd@arndb.de> Closes: https://lore.kernel.org/90956545-2066-46e3-b547-10c884582eb0@app.fastmail.com Link: https://patch.msgid.link/240e6a172cc73292499334a3724d02ccb3247fc7.1772818491.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Diffstat (limited to 'tools/objtool')
-rw-r--r--tools/objtool/arch/x86/decode.c62
-rw-r--r--tools/objtool/check.c14
2 files changed, 37 insertions, 39 deletions
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index 73bfea220d1b..c5817829cdfa 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -395,52 +395,36 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
if (!rex_w)
break;
- if (modrm_reg == CFI_SP) {
-
- if (mod_is_reg()) {
- /* mov %rsp, reg */
- ADD_OP(op) {
- op->src.type = OP_SRC_REG;
- op->src.reg = CFI_SP;
- op->dest.type = OP_DEST_REG;
- op->dest.reg = modrm_rm;
- }
- break;
-
- } else {
- /* skip RIP relative displacement */
- if (is_RIP())
- break;
-
- /* skip nontrivial SIB */
- if (have_SIB()) {
- modrm_rm = sib_base;
- if (sib_index != CFI_SP)
- break;
- }
-
- /* mov %rsp, disp(%reg) */
- ADD_OP(op) {
- op->src.type = OP_SRC_REG;
- op->src.reg = CFI_SP;
- op->dest.type = OP_DEST_REG_INDIRECT;
- op->dest.reg = modrm_rm;
- op->dest.offset = ins.displacement.value;
- }
- break;
+ if (mod_is_reg()) {
+ /* mov reg, reg */
+ ADD_OP(op) {
+ op->src.type = OP_SRC_REG;
+ op->src.reg = modrm_reg;
+ op->dest.type = OP_DEST_REG;
+ op->dest.reg = modrm_rm;
}
-
break;
}
- if (rm_is_reg(CFI_SP)) {
+ /* skip RIP relative displacement */
+ if (is_RIP())
+ break;
- /* mov reg, %rsp */
+ /* skip nontrivial SIB */
+ if (have_SIB()) {
+ modrm_rm = sib_base;
+ if (sib_index != CFI_SP)
+ break;
+ }
+
+ /* mov %rsp, disp(%reg) */
+ if (modrm_reg == CFI_SP) {
ADD_OP(op) {
op->src.type = OP_SRC_REG;
- op->src.reg = modrm_reg;
- op->dest.type = OP_DEST_REG;
- op->dest.reg = CFI_SP;
+ op->src.reg = CFI_SP;
+ op->dest.type = OP_DEST_REG_INDIRECT;
+ op->dest.reg = modrm_rm;
+ op->dest.offset = ins.displacement.value;
}
break;
}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index a30379e4ff97..786b2f2adbab 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3000,6 +3000,20 @@ static int update_cfi_state(struct instruction *insn,
cfi->stack_size += 8;
}
+ else if (cfi->vals[op->src.reg].base == CFI_CFA) {
+ /*
+ * Clang RSP musical chairs:
+ *
+ * mov %rsp, %rdx [handled above]
+ * ...
+ * mov %rdx, %rbx [handled here]
+ * ...
+ * mov %rbx, %rsp [handled above]
+ */
+ cfi->vals[op->dest.reg].base = CFI_CFA;
+ cfi->vals[op->dest.reg].offset = cfi->vals[op->src.reg].offset;
+ }
+
break;