From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2A673CE7B1F for ; Fri, 14 Nov 2025 15:15:29 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 88BD78E002B; Fri, 14 Nov 2025 10:15:28 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 83B778E0002; Fri, 14 Nov 2025 10:15:28 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 703CF8E002B; Fri, 14 Nov 2025 10:15:28 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 53C648E0002 for ; Fri, 14 Nov 2025 10:15:28 -0500 (EST) Received: from smtpin10.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id E456312DF6C for ; Fri, 14 Nov 2025 15:15:27 +0000 (UTC) X-FDA: 84109561494.10.E295F3A Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by imf15.hostedemail.com (Postfix) with ESMTP id 31B7DA001A for ; Fri, 14 Nov 2025 15:15:26 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=KDlcYp+s; spf=pass (imf15.hostedemail.com: domain of vschneid@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=vschneid@redhat.com; dmarc=pass (policy=quarantine) header.from=redhat.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1763133326; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=hvGV990aqgS/6XaVWScoJX92mzsp0oEflxykXgSnr9U=; b=QaWW6yjr6ifONUwc+g95xqD2wKdYYxTSFXEsJ2y7TVNACrbC9txrSdZmzdbLgHl34lzJFK bbti85VCJwBrQDu+4iiVuyiEUSuAS8g1ROrpdgnQl+5k9s3lOwTVfyoWfC1MTENL8gXrqa oL/3lmZCtffR35uZWfq2EYDmUzYOkuI= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=KDlcYp+s; spf=pass (imf15.hostedemail.com: domain of vschneid@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=vschneid@redhat.com; dmarc=pass (policy=quarantine) header.from=redhat.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1763133326; a=rsa-sha256; cv=none; b=u7spDx1YLEH2BQv9uz83N9PTHgatsV83hTaC/KQliFmOdL9j7gICvj3zkfnfrdE90YvkVo dTtwlp4LSn9awJUjRgdplxARmOl+12kehOUgOsNadpdNjF11euB35hNz/TouFYHw9N/dAA NpieoJIZjPLIGpU/fSrWxfDxTcZFIlQ= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1763133325; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hvGV990aqgS/6XaVWScoJX92mzsp0oEflxykXgSnr9U=; b=KDlcYp+skLCcwqAFhBOzOTFNRbcvXAdKhHfaEae4CqV81JOG1eYXu8+7QVxp6zEjyZhv5l N2Oe5Ift3vjGgH94xxoqK4FF0+qgS0GInulJyjyK0JUYY81+dwl3WpdPakmzQu6Wn9yGgp PHxZx21ILWcbk45h3zJ2AJe0socnPRc= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-608-pc6qRfMRPAqW4KHYPIFD0g-1; Fri, 14 Nov 2025 10:15:20 -0500 X-MC-Unique: pc6qRfMRPAqW4KHYPIFD0g-1 X-Mimecast-MFC-AGG-ID: pc6qRfMRPAqW4KHYPIFD0g_1763133310 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C3A171956080; Fri, 14 Nov 2025 15:15:09 +0000 (UTC) Received: from vschneid-thinkpadt14sgen2i.remote.csb (unknown [10.45.226.10]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 20E701800451; Fri, 14 Nov 2025 15:14:53 +0000 (UTC) From: Valentin Schneider To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, rcu@vger.kernel.org, x86@kernel.org, linux-arm-kernel@lists.infradead.org, loongarch@lists.linux.dev, linux-riscv@lists.infradead.org, linux-arch@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: Josh Poimboeuf , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , Andy Lutomirski , Peter Zijlstra , Arnaldo Carvalho de Melo , Paolo Bonzini , Arnd Bergmann , Frederic Weisbecker , "Paul E. McKenney" , Jason Baron , Steven Rostedt , Ard Biesheuvel , Sami Tolvanen , "David S. Miller" , Neeraj Upadhyay , Joel Fernandes , Josh Triplett , Boqun Feng , Uladzislau Rezki , Mathieu Desnoyers , Mel Gorman , Andrew Morton , Masahiro Yamada , Han Shen , Rik van Riel , Jann Horn , Dan Carpenter , Oleg Nesterov , Juri Lelli , Clark Williams , Yair Podemsky , Marcelo Tosatti , Daniel Wagner , Petr Tesarik , Shrikanth Hegde Subject: [PATCH v7 22/31] objtool: Add noinstr validation for static branches/calls Date: Fri, 14 Nov 2025 16:14:19 +0100 Message-ID: <20251114151428.1064524-2-vschneid@redhat.com> In-Reply-To: <20251114150133.1056710-1-vschneid@redhat.com> References: <20251114150133.1056710-1-vschneid@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 31B7DA001A X-Stat-Signature: r6oazbkmm1kx5q7zpx1qyjzwpcsjq53t X-Rspam-User: X-HE-Tag: 1763133326-83930 X-HE-Meta: U2FsdGVkX19CKKyhBSdMvlydq3+suihITrLruJi2d4r76Tl0YFTEO0DhLyYm/N/IrhnaWXsOxFg33i2k0ezds4M4EDYuMCNIs0uhOtw0NncVU/EokEll45ZkDyh3BbBn53IOeKygeM4aQdhlb03MzZ9F7JOthlzFgZWJ8D+yD5LHTaTCMof4l+qPQUS66/EUtSv82QyzROMaOYniJiSNYN/2B9i6N1ex4v6sPlAAJD16xTzyzQRLGHGnaoKRh9BM51rHKdCcdtvDbDFv9yaGsh9N+ha/Ki1YQ23RoA/dDKq7EAQbwVqZAeMhy9Csoo5DYmTrCbawPV8QnsvyJ69Q5DEyb3UXwdMrvF+ialRWd8X6N8AEb6IoGm0KylccdDiwla16lrjYypYjqzKVjumjgJAgE1Lcxpnt2MaC2ep9PUowM0Qx5KGPKm+8Et/NKq+ugMZA9KLJ30UgVVYMldU0EOZ/WOfQ5uyl6iIrxcW+NDmgLyQdUewodbBrDJHOKnV8BDbnxnTeGnf5HEBKM3e4kNGSqJivt0TMKlYUULml8COSdhPPRvrTumJ0ZuwzeC0tg8X0y4412DW429NWwGcdv29lGo0pW53qz9rwmT+WLYhAnHtOiogLFdgYd7/mZjowOezl7nLwpO4VkmBH0T3oiJ9bK13aM1LcgnPBwFkVEZPKmNDiTBsI1C+h7jfG60+0hWVX9I20PA1mjgP365t5QEadMJ7iKvluE1tvB2/7mH5h9D2oCR1LYTGZ3E4GYaAv7H8HJbkOF1O25uzbhwVAiXVCwOTXc2pRmgFutNVK6DUaaCVdpAEYse1LWTQex+qL3IEWcNrufhNbF7wd3lLnxGbeCqVbm9LBb2jfv0cbhRmGVXfEHoqVD/4FZHDvf83Ck3qyADwEuzAxgigCaD+skGapgQn2iSVEw0QuUzwzYxlc5hqPlpa41V9ARyzI/MbIPhrq/ZuH6KRwGSruTbs Bdy/hEl+ UvwqST9/Ri9EqnbP0rCF+XBuCUn3GV/f1zkrbiWqP2SILhRp1dAYN2xTHa3T2kmQBDNlyFTYFl83KjFELy92lmKjt0Yy9WYmZwoQxktoD7xx8Ga0d5zeTXwpSmr2Ngldr11HtPlXLPYzfP8mvV+N8EHMiZtK6W975WfFsqFHCrUhXQnesbrnVI2Y9iFK7bEMoGAZ8rVY4FZx/mJN3dAhHCJwT4MM6oFmnU2oPfqwfMt5pvHAiQ43A6fGCBQU2P7VAV4RBMghGLTg9uldWFg1Awu6sSXX93YsMZln3RNYAvpo0wPK9aIhFv0XpgiKSru6SLLCnPOO8gqeETynQgG0ZcbgqahFmyh9oNo8V3TgBS3ZZGIFdt228O0P/bUMkExJ83yhn+V8Q7au8Smy+/tatoYus+CoR3t/gfVeT7FhMnAEobaIGo/xoVQdEmJ4oqq1WpMbO X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Josh Poimboeuf Warn about static branches/calls in noinstr regions, unless the corresponding key is RO-after-init or has been manually whitelisted with DEFINE_STATIC_KEY_*_NOINSTR((). Signed-off-by: Josh Poimboeuf Signed-off-by: Valentin Schneider --- include/linux/jump_label.h | 17 +++-- include/linux/objtool.h | 14 ++++ include/linux/static_call.h | 3 + tools/objtool/Documentation/objtool.txt | 34 +++++++++ tools/objtool/check.c | 92 ++++++++++++++++++++++--- tools/objtool/include/objtool/check.h | 1 + tools/objtool/include/objtool/elf.h | 1 + tools/objtool/include/objtool/special.h | 1 + tools/objtool/special.c | 15 +++- 9 files changed, 162 insertions(+), 16 deletions(-) diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index c4f6240ff4d95..0ea203ebbc493 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -76,6 +76,7 @@ #include #include #include +#include extern bool static_key_initialized; @@ -376,8 +377,9 @@ struct static_key_false { #define DEFINE_STATIC_KEY_TRUE(name) \ struct static_key_true name = STATIC_KEY_TRUE_INIT -#define DEFINE_STATIC_KEY_TRUE_RO(name) \ - struct static_key_true name __ro_after_init = STATIC_KEY_TRUE_INIT +#define DEFINE_STATIC_KEY_TRUE_RO(name) \ + struct static_key_true name __ro_after_init = STATIC_KEY_TRUE_INIT; \ + ANNOTATE_NOINSTR_ALLOWED(name) #define DECLARE_STATIC_KEY_TRUE(name) \ extern struct static_key_true name @@ -385,8 +387,9 @@ struct static_key_false { #define DEFINE_STATIC_KEY_FALSE(name) \ struct static_key_false name = STATIC_KEY_FALSE_INIT -#define DEFINE_STATIC_KEY_FALSE_RO(name) \ - struct static_key_false name __ro_after_init = STATIC_KEY_FALSE_INIT +#define DEFINE_STATIC_KEY_FALSE_RO(name) \ + struct static_key_false name __ro_after_init = STATIC_KEY_FALSE_INIT; \ + ANNOTATE_NOINSTR_ALLOWED(name) /* * The _NOINSTR variants are used to tell objtool the static key is allowed to @@ -400,10 +403,12 @@ struct static_key_false { * definition with the rationale. */ #define DEFINE_STATIC_KEY_TRUE_NOINSTR(name) \ - DEFINE_STATIC_KEY_TRUE(name) + DEFINE_STATIC_KEY_TRUE(name); \ + ANNOTATE_NOINSTR_ALLOWED(name) #define DEFINE_STATIC_KEY_FALSE_NOINSTR(name) \ - DEFINE_STATIC_KEY_FALSE(name) + DEFINE_STATIC_KEY_FALSE(name); \ + ANNOTATE_NOINSTR_ALLOWED(name) #define DECLARE_STATIC_KEY_FALSE(name) \ extern struct static_key_false name diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 46ebaa46e6c58..78b73bf65d9a2 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -34,6 +34,19 @@ static void __used __section(".discard.func_stack_frame_non_standard") \ *__func_stack_frame_non_standard_##func = func +#define __ANNOTATE_NOINSTR_ALLOWED(key) \ + static void __used __section(".discard.noinstr_allowed") \ + *__annotate_noinstr_allowed_##key = &key + +/* + * This is used to tell objtool that a given static key is safe to be used + * within .noinstr code, and it doesn't need to generate a warning about it. + * + * For more information, see tools/objtool/Documentation/objtool.txt, + * "non-RO static key usage in noinstr code" + */ +#define ANNOTATE_NOINSTR_ALLOWED(key) __ANNOTATE_NOINSTR_ALLOWED(key) + /* * STACK_FRAME_NON_STANDARD_FP() is a frame-pointer-specific function ignore * for the case where a function is intentionally missing frame pointer setup, @@ -130,6 +143,7 @@ #define STACK_FRAME_NON_STANDARD_FP(func) #define __ASM_ANNOTATE(label, type) "" #define ASM_ANNOTATE(type) +#define ANNOTATE_NOINSTR_ALLOWED(key) #else .macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .endm diff --git a/include/linux/static_call.h b/include/linux/static_call.h index ea6ca57e2a829..0d4b16d348501 100644 --- a/include/linux/static_call.h +++ b/include/linux/static_call.h @@ -133,6 +133,7 @@ #include #include +#include #include #ifdef CONFIG_HAVE_STATIC_CALL @@ -198,6 +199,7 @@ extern long __static_call_return0(void); .func = _func, \ .type = 1, \ }; \ + ANNOTATE_NOINSTR_ALLOWED(STATIC_CALL_TRAMP(name)); \ ARCH_DEFINE_STATIC_CALL_TRAMP(name, _func) #define DEFINE_STATIC_CALL_NULL(name, _func) \ @@ -214,6 +216,7 @@ extern long __static_call_return0(void); .func = NULL, \ .type = 1, \ }; \ + ANNOTATE_NOINSTR_ALLOWED(STATIC_CALL_TRAMP(name)); \ ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name) #define DEFINE_STATIC_CALL_RET0(name, _func) \ diff --git a/tools/objtool/Documentation/objtool.txt b/tools/objtool/Documentation/objtool.txt index 9e97fc25b2d8a..991e085e10d95 100644 --- a/tools/objtool/Documentation/objtool.txt +++ b/tools/objtool/Documentation/objtool.txt @@ -456,6 +456,40 @@ the objtool maintainers. these special names and does not use module_init() / module_exit() macros to create them. +13. file.o: warning: func()+0x2a: key: non-RO static key usage in noinstr code + file.o: warning: func()+0x2a: key: non-RO static call usage in noinstr code + + This means that noinstr function func() uses a static key or + static call named 'key' which can be modified at runtime. This is + discouraged because it prevents code patching IPIs from being + deferred. + + You have the following options: + + 1) Check whether the static key/call in question is only modified + during init. If so, define it as read-only-after-init with + DEFINE_STATIC_KEY_*_RO() or DEFINE_STATIC_CALL_RO(). + + 2) Avoid the runtime patching. For static keys this can be done by + using static_key_enabled() or by getting rid of the static key + altogether if performance is not a concern. + + For static calls, something like the following could be done: + + target = static_call_query(foo); + if (target == func1) + func1(); + else if (target == func2) + func2(); + ... + + 3) Silence the warning by defining the static key/call with + DEFINE_STATIC_*_NOINSTR(). This decision should not + be taken lightly as it may result in code patching IPIs getting + sent to isolated NOHZ_FULL CPUs running in pure userspace. A + comment should be added above the definition explaining the + rationale for the decision. + If the error doesn't seem to make sense, it could be a bug in objtool. Feel free to ask objtool maintainers for help. diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 1efa9f1bf16ba..474ba2fc87ac6 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -982,6 +982,45 @@ static int create_direct_call_sections(struct objtool_file *file) return 0; } +static int read_noinstr_allowed(struct objtool_file *file) +{ + struct section *rsec; + struct symbol *sym; + struct reloc *reloc; + + rsec = find_section_by_name(file->elf, ".rela.discard.noinstr_allowed"); + if (!rsec) + return 0; + + for_each_reloc(rsec, reloc) { + switch (reloc->sym->type) { + case STT_OBJECT: + case STT_FUNC: + sym = reloc->sym; + break; + + case STT_SECTION: + sym = find_symbol_by_offset(reloc->sym->sec, + reloc_addend(reloc)); + if (!sym) { + WARN_FUNC(reloc->sym->sec, reloc_addend(reloc), + "can't find static key/call symbol"); + return -1; + } + break; + + default: + WARN("unexpected relocation symbol type in %s: %d", + rsec->name, reloc->sym->type); + return -1; + } + + sym->noinstr_allowed = 1; + } + + return 0; +} + /* * Warnings shouldn't be reported for ignored functions. */ @@ -1868,6 +1907,8 @@ static int handle_jump_alt(struct objtool_file *file, return -1; } + orig_insn->key = special_alt->key; + if (opts.hack_jump_label && special_alt->key_addend & 2) { struct reloc *reloc = insn_reloc(file, orig_insn); @@ -2602,6 +2643,10 @@ static int decode_sections(struct objtool_file *file) if (ret) return ret; + ret = read_noinstr_allowed(file); + if (ret) + return ret; + return 0; } @@ -3371,9 +3416,9 @@ static bool pv_call_dest(struct objtool_file *file, struct instruction *insn) return file->pv_ops[idx].clean; } -static inline bool noinstr_call_dest(struct objtool_file *file, - struct instruction *insn, - struct symbol *func) +static inline bool noinstr_call_allowed(struct objtool_file *file, + struct instruction *insn, + struct symbol *func) { /* * We can't deal with indirect function calls at present; @@ -3393,10 +3438,10 @@ static inline bool noinstr_call_dest(struct objtool_file *file, return true; /* - * If the symbol is a static_call trampoline, we can't tell. + * Only DEFINE_STATIC_CALL_*_RO allowed. */ if (func->static_call_tramp) - return true; + return func->noinstr_allowed; /* * The __ubsan_handle_*() calls are like WARN(), they only happen when @@ -3409,14 +3454,29 @@ static inline bool noinstr_call_dest(struct objtool_file *file, return false; } +static char *static_call_name(struct symbol *func) +{ + return func->name + strlen("__SCT__"); +} + static int validate_call(struct objtool_file *file, struct instruction *insn, struct insn_state *state) { - if (state->noinstr && state->instr <= 0 && - !noinstr_call_dest(file, insn, insn_call_dest(insn))) { - WARN_INSN(insn, "call to %s() leaves .noinstr.text section", call_dest_name(file, insn)); - return 1; + if (state->noinstr && state->instr <= 0) { + struct symbol *dest = insn_call_dest(insn); + + if (dest && dest->static_call_tramp) { + if (!dest->noinstr_allowed) { + WARN_INSN(insn, "%s: non-RO static call usage in noinstr", + static_call_name(dest)); + } + + } else if (dest && !noinstr_call_allowed(file, insn, dest)) { + WARN_INSN(insn, "call to %s() leaves .noinstr.text section", + call_dest_name(file, insn)); + return 1; + } } if (state->uaccess && !func_uaccess_safe(insn_call_dest(insn))) { @@ -3481,6 +3541,17 @@ static int validate_return(struct symbol *func, struct instruction *insn, struct return 0; } +static int validate_static_key(struct instruction *insn, struct insn_state *state) +{ + if (state->noinstr && state->instr <= 0 && !insn->key->noinstr_allowed) { + WARN_INSN(insn, "%s: non-RO static key usage in noinstr", + insn->key->name); + return 1; + } + + return 0; +} + static struct instruction *next_insn_to_validate(struct objtool_file *file, struct instruction *insn) { @@ -3673,6 +3744,9 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, if (handle_insn_ops(insn, next_insn, &state)) return 1; + if (insn->key) + validate_static_key(insn, &state); + switch (insn->type) { case INSN_RETURN: diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h index 00fb745e72339..d79b08f55bcbc 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -81,6 +81,7 @@ struct instruction { struct symbol *sym; struct stack_op *stack_ops; struct cfi_state *cfi; + struct symbol *key; }; static inline struct symbol *insn_func(struct instruction *insn) diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index df8434d3b7440..545deba57266a 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -71,6 +71,7 @@ struct symbol { u8 frame_pointer : 1; u8 ignore : 1; u8 nocfi : 1; + u8 noinstr_allowed : 1; struct list_head pv_target; struct reloc *relocs; struct section *group_sec; diff --git a/tools/objtool/include/objtool/special.h b/tools/objtool/include/objtool/special.h index 72d09c0adf1a1..e84d704f3f20e 100644 --- a/tools/objtool/include/objtool/special.h +++ b/tools/objtool/include/objtool/special.h @@ -18,6 +18,7 @@ struct special_alt { bool group; bool jump_or_nop; u8 key_addend; + struct symbol *key; struct section *orig_sec; unsigned long orig_off; diff --git a/tools/objtool/special.c b/tools/objtool/special.c index c80fed8a840ee..d77f3fa4bbbc9 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c @@ -110,13 +110,26 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry, if (entry->key) { struct reloc *key_reloc; + struct symbol *key; + s64 key_addend; key_reloc = find_reloc_by_dest(elf, sec, offset + entry->key); if (!key_reloc) { ERROR_FUNC(sec, offset + entry->key, "can't find key reloc"); return -1; } - alt->key_addend = reloc_addend(key_reloc); + + key = key_reloc->sym; + key_addend = reloc_addend(key_reloc); + + if (key->type == STT_SECTION) + key = find_symbol_by_offset(key->sec, key_addend & ~3); + + /* embedded keys not supported */ + if (key) { + alt->key = key; + alt->key_addend = key_addend; + } } return 0; -- 2.51.0