mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-01 06:39:05 +00:00
x86/alternative: Simplify callthunk patching
Now that paravirt call patching is implemented using alternatives, it is possible to avoid having to patch the alternative sites by including the altinstr_replacement calls in the call_sites list. This means we're now stacking relative adjustments like so: callthunks_patch_builtin_calls(): patches all function calls to target: func() -> func()-10 since the CALL accounting lives in the CALL_PADDING. This explicitly includes .altinstr_replacement alt_replace_call(): patches: x86_BUG() -> target() this patching is done in a relative manner, and will preserve the above adjustment, meaning that with calldepth patching it will do: x86_BUG()-10 -> target()-10 apply_relocation(): does code relocation, and adjusts all RIP-relative instructions to the new location, also in a relative manner. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Sami Tolvanen <samitolvanen@google.com> Link: https://lore.kernel.org/r/20250207122546.617187089@infradead.org
This commit is contained in:
parent
93f16a1ab7
commit
ab9fea5948
@ -100,7 +100,6 @@ struct module;
|
||||
|
||||
struct callthunk_sites {
|
||||
s32 *call_start, *call_end;
|
||||
struct alt_instr *alt_start, *alt_end;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CALL_THUNKS
|
||||
|
@ -1705,14 +1705,14 @@ void __init alternative_instructions(void)
|
||||
apply_retpolines(__retpoline_sites, __retpoline_sites_end);
|
||||
apply_returns(__return_sites, __return_sites_end);
|
||||
|
||||
apply_alternatives(__alt_instructions, __alt_instructions_end);
|
||||
|
||||
/*
|
||||
* Now all calls are established. Apply the call thunks if
|
||||
* required.
|
||||
* Adjust all CALL instructions to point to func()-10, including
|
||||
* those in .altinstr_replacement.
|
||||
*/
|
||||
callthunks_patch_builtin_calls();
|
||||
|
||||
apply_alternatives(__alt_instructions, __alt_instructions_end);
|
||||
|
||||
/*
|
||||
* Seal all functions that do not have their address taken.
|
||||
*/
|
||||
|
@ -239,22 +239,11 @@ patch_call_sites(s32 *start, s32 *end, const struct core_text *ct)
|
||||
patch_call((void *)s + *s, ct);
|
||||
}
|
||||
|
||||
static __init_or_module void
|
||||
patch_alt_call_sites(struct alt_instr *start, struct alt_instr *end,
|
||||
const struct core_text *ct)
|
||||
{
|
||||
struct alt_instr *a;
|
||||
|
||||
for (a = start; a < end; a++)
|
||||
patch_call((void *)&a->instr_offset + a->instr_offset, ct);
|
||||
}
|
||||
|
||||
static __init_or_module void
|
||||
callthunks_setup(struct callthunk_sites *cs, const struct core_text *ct)
|
||||
{
|
||||
prdbg("Patching call sites %s\n", ct->name);
|
||||
patch_call_sites(cs->call_start, cs->call_end, ct);
|
||||
patch_alt_call_sites(cs->alt_start, cs->alt_end, ct);
|
||||
prdbg("Patching call sites done%s\n", ct->name);
|
||||
}
|
||||
|
||||
@ -263,8 +252,6 @@ void __init callthunks_patch_builtin_calls(void)
|
||||
struct callthunk_sites cs = {
|
||||
.call_start = __call_sites,
|
||||
.call_end = __call_sites_end,
|
||||
.alt_start = __alt_instructions,
|
||||
.alt_end = __alt_instructions_end
|
||||
};
|
||||
|
||||
if (!cpu_feature_enabled(X86_FEATURE_CALL_DEPTH))
|
||||
|
@ -275,12 +275,7 @@ int module_finalize(const Elf_Ehdr *hdr,
|
||||
void *rseg = (void *)returns->sh_addr;
|
||||
apply_returns(rseg, rseg + returns->sh_size);
|
||||
}
|
||||
if (alt) {
|
||||
/* patch .altinstructions */
|
||||
void *aseg = (void *)alt->sh_addr;
|
||||
apply_alternatives(aseg, aseg + alt->sh_size);
|
||||
}
|
||||
if (calls || alt) {
|
||||
if (calls) {
|
||||
struct callthunk_sites cs = {};
|
||||
|
||||
if (calls) {
|
||||
@ -288,13 +283,13 @@ int module_finalize(const Elf_Ehdr *hdr,
|
||||
cs.call_end = (void *)calls->sh_addr + calls->sh_size;
|
||||
}
|
||||
|
||||
if (alt) {
|
||||
cs.alt_start = (void *)alt->sh_addr;
|
||||
cs.alt_end = (void *)alt->sh_addr + alt->sh_size;
|
||||
}
|
||||
|
||||
callthunks_patch_module_calls(&cs, me);
|
||||
}
|
||||
if (alt) {
|
||||
/* patch .altinstructions */
|
||||
void *aseg = (void *)alt->sh_addr;
|
||||
apply_alternatives(aseg, aseg + alt->sh_size);
|
||||
}
|
||||
if (ibt_endbr) {
|
||||
void *iseg = (void *)ibt_endbr->sh_addr;
|
||||
apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size);
|
||||
|
@ -850,5 +850,6 @@ bool arch_is_rethunk(struct symbol *sym)
|
||||
bool arch_is_embedded_insn(struct symbol *sym)
|
||||
{
|
||||
return !strcmp(sym->name, "retbleed_return_thunk") ||
|
||||
!strcmp(sym->name, "srso_alias_safe_ret") ||
|
||||
!strcmp(sym->name, "srso_safe_ret");
|
||||
}
|
||||
|
@ -1283,15 +1283,6 @@ static void annotate_call_site(struct objtool_file *file,
|
||||
if (!sym)
|
||||
sym = reloc->sym;
|
||||
|
||||
/*
|
||||
* Alternative replacement code is just template code which is
|
||||
* sometimes copied to the original instruction. For now, don't
|
||||
* annotate it. (In the future we might consider annotating the
|
||||
* original instruction if/when it ever makes sense to do so.)
|
||||
*/
|
||||
if (!strcmp(insn->sec->name, ".altinstr_replacement"))
|
||||
return;
|
||||
|
||||
if (sym->static_call_tramp) {
|
||||
list_add_tail(&insn->call_node, &file->static_call_list);
|
||||
return;
|
||||
@ -1349,7 +1340,8 @@ static void annotate_call_site(struct objtool_file *file,
|
||||
return;
|
||||
}
|
||||
|
||||
if (insn->type == INSN_CALL && !insn->sec->init)
|
||||
if (insn->type == INSN_CALL && !insn->sec->init &&
|
||||
!insn->_call_dest->embedded_insn)
|
||||
list_add_tail(&insn->call_node, &file->call_list);
|
||||
|
||||
if (!sibling && dead_end_function(file, sym))
|
||||
|
Loading…
Reference in New Issue
Block a user