Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Move the IRET hack into the arch decoder

Quoting Julien:

"And the other suggestion is my other email was that you don't even
need to add INSN_EXCEPTION_RETURN. You can keep IRET as
INSN_CONTEXT_SWITCH by default and x86 decoder lookups the symbol
conaining an iret. If it's a function symbol, it can just set the type
to INSN_OTHER so that it caries on to the next instruction after
having handled the stack_op."

Suggested-by: Julien Thierry <jthierry@redhat.com>
Signed-off-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lkml.kernel.org/r/20200428191659.913283807@infradead.org

authored by

Miroslav Benes and committed by
Peter Zijlstra
b490f453 b09fb65e

+21 -25
-1
tools/objtool/arch.h
··· 19 19 INSN_CALL, 20 20 INSN_CALL_DYNAMIC, 21 21 INSN_RETURN, 22 - INSN_EXCEPTION_RETURN, 23 22 INSN_CONTEXT_SWITCH, 24 23 INSN_BUG, 25 24 INSN_NOP,
+18 -10
tools/objtool/arch/x86/decode.c
··· 94 94 rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, 95 95 modrm_reg = 0, sib = 0; 96 96 struct stack_op *op = NULL; 97 + struct symbol *sym; 97 98 98 99 x86_64 = is_x86_64(elf); 99 100 if (x86_64 == -1) ··· 470 469 break; 471 470 472 471 case 0xcf: /* iret */ 473 - *type = INSN_EXCEPTION_RETURN; 474 - 475 - ADD_OP(op) { 476 - /* add $40, %rsp */ 477 - op->src.type = OP_SRC_ADD; 478 - op->src.reg = CFI_SP; 479 - op->src.offset = 5*8; 480 - op->dest.type = OP_DEST_REG; 481 - op->dest.reg = CFI_SP; 472 + /* 473 + * Handle sync_core(), which has an IRET to self. 474 + * All other IRET are in STT_NONE entry code. 475 + */ 476 + sym = find_symbol_containing(sec, offset); 477 + if (sym && sym->type == STT_FUNC) { 478 + ADD_OP(op) { 479 + /* add $40, %rsp */ 480 + op->src.type = OP_SRC_ADD; 481 + op->src.reg = CFI_SP; 482 + op->src.offset = 5*8; 483 + op->dest.type = OP_DEST_REG; 484 + op->dest.reg = CFI_SP; 485 + } 486 + break; 482 487 } 483 - break; 488 + 489 + /* fallthrough */ 484 490 485 491 case 0xca: /* retf */ 486 492 case 0xcb: /* retf */
-11
tools/objtool/check.c
··· 2320 2320 2321 2321 break; 2322 2322 2323 - case INSN_EXCEPTION_RETURN: 2324 - /* 2325 - * This handles x86's sync_core() case, where we use an 2326 - * IRET to self. All 'normal' IRET instructions are in 2327 - * STT_NOTYPE entry symbols. 2328 - */ 2329 - if (func) 2330 - break; 2331 - 2332 - return 0; 2333 - 2334 2323 case INSN_CONTEXT_SWITCH: 2335 2324 if (func && (!next_insn || !next_insn->hint)) { 2336 2325 WARN_FUNC("unsupported instruction in callable function",
+2 -2
tools/objtool/elf.c
··· 61 61 rb_insert_color(node, tree); 62 62 } 63 63 64 - static struct rb_node *rb_find_first(struct rb_root *tree, const void *key, 64 + static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key, 65 65 int (*cmp)(const void *key, const struct rb_node *)) 66 66 { 67 67 struct rb_node *node = tree->rb_node; ··· 189 189 return NULL; 190 190 } 191 191 192 - struct symbol *find_symbol_containing(struct section *sec, unsigned long offset) 192 + struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset) 193 193 { 194 194 struct rb_node *node; 195 195
+1 -1
tools/objtool/elf.h
··· 124 124 struct symbol *find_func_by_offset(struct section *sec, unsigned long offset); 125 125 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); 126 126 struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); 127 - struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); 127 + struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); 128 128 struct rela *find_rela_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); 129 129 struct rela *find_rela_by_dest_range(const struct elf *elf, struct section *sec, 130 130 unsigned long offset, unsigned int len);