Re: [PATCH v2 10/11] x86/alternatives: Simplify ALTERNATIVE_n()

From: Borislav Petkov
Date: Thu Sep 07 2023 - 11:36:01 EST


On Thu, Sep 07, 2023 at 05:06:32PM +0200, Borislav Petkov wrote:
> > # ALT: oldnstr
> > 661:
> > # ALT: oldnstr
> > 661:
>
> I'll keep on playing with this.

Ok, below's what I've been thinking. It looks ok but I'll keep staring
at it for a while to make sure I'm not missing an angle.

We simply pass a number to the ALTERNATIVE macro, starting from 0. 0 is
the innermost invocation, 1 is the outer and so on. And then the labels
are unique and the sizes are correct. And we hardcode 0 to mean the
innermost macro invocation and use that for sizing of orig instr.

But I might be missing something so lemme poke at it more. Below is
a userspace program which makes this a lot easier to experiment with:

---
#include <stdio.h>

#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)

#define alt_slen "662b-6610b"
#define alt_total_slen "663b-661b"
#define alt_rlen "665f-664f"

#define OLDINSTR(oldinstr, n) \
"# ALT: oldnstr\n" \
"661" #n ":\n\t" oldinstr "\n662:\n" \
"# ALT: padding\n" \
".skip -(((" alt_rlen ")-(" alt_slen ")) > 0) * " \
"((" alt_rlen ")-(" alt_slen ")),0x90\n" \
"663:\n"

#define ALTINSTR_ENTRY(ft_flags) \
".pushsection .altinstructions,\"a\"\n" \
" .long 6610b - .\n" /* label */ \
" .long 664f - .\n" /* new instruction */ \
" .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \
" .byte " alt_total_slen "\n" /* source len */ \
" .byte " alt_rlen "\n" /* replacement len */ \
".popsection\n"

#define ALTINSTR_REPLACEMENT(newinstr) /* replacement */ \
".pushsection .altinstr_replacement, \"ax\"\n" \
"# ALT: replacement \n" \
"664:\n\t" newinstr "\n 665:\n" \
".popsection\n"

/*
* Define an alternative between two instructions. If @ft_flags is
* present, early code in apply_alternatives() replaces @oldinstr with
* @newinstr. ".skip" directive takes care of proper instruction padding
* in case @newinstr is longer than @oldinstr.
*
* Notably: @oldinstr may be an ALTERNATIVE() itself, also see
* apply_alternatives()
*/
#define __ALTERNATIVE(oldinstr, newinstr, ft_flags, n) \
OLDINSTR(oldinstr, n) \
ALTINSTR_ENTRY(ft_flags) \
ALTINSTR_REPLACEMENT(newinstr)

#define ALTERNATIVE(oldinstr, newinstr, ft_flags) \
__ALTERNATIVE(oldinstr, newinstr, ft_flags, 0)

#define ALTERNATIVE_2(oldinst, newinst1, flag1, newinst2, flag2) \
__ALTERNATIVE(__ALTERNATIVE(oldinst, newinst1, flag1, 0), \
newinst2, flag2, 1)

#define alternative_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) \
asm __inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) ::: "memory")

int main(void)
{
alternative_2("", "pop %%rax", 1, "call main", 1);
return 0;
}



--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette