work around gcc bugs with 'asm goto' with outputs

commit 4356e9f841f7fbb945521cef3577ba394c65f3fc upstream.

We've had issues with gcc and 'asm goto' before, and we created a
'asm_volatile_goto()' macro for that in the past: see commits
3f0116c323 ("compiler/gcc4: Add quirk for 'asm goto' miscompilation
bug") and a9f180345f ("compiler/gcc4: Make quirk for
asm_volatile_goto() unconditional").

Then, much later, we ended up removing the workaround in commit
43c249ea0b ("compiler-gcc.h: remove ancient workaround for gcc PR
58670") because we no longer supported building the kernel with the
affected gcc versions, but we left the macro uses around.

Now, Sean Christopherson reports a new version of a very similar
problem, which is fixed by re-applying that ancient workaround.  But the
problem in question is limited to only the 'asm goto with outputs'
cases, so instead of re-introducing the old workaround as-is, let's
rename and limit the workaround to just that much less common case.

It looks like there are at least two separate issues that all hit in
this area:

 (a) some versions of gcc don't mark the asm goto as 'volatile' when it
     has outputs:

        https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98619
        https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110420

     which is easy to work around by just adding the 'volatile' by hand.

 (b) Internal compiler errors:

        https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110422

     which are worked around by adding the extra empty 'asm' as a
     barrier, as in the original workaround.

but the problem Sean sees may be a third thing since it involves bad
code generation (not an ICE) even with the manually added 'volatile'.

but the same old workaround works for this case, even if this feels a
bit like voodoo programming and may only be hiding the issue.

Reported-and-tested-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/all/20240208220604.140859-1-seanjc@google.com/
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Uros Bizjak <ubizjak@gmail.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Cc: Andrew Pinski <quic_apinski@quicinc.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Linus Torvalds 2024-02-09 12:39:31 -08:00 committed by Greg Kroah-Hartman
parent b2c9bf0647
commit aaff74d886
31 changed files with 84 additions and 65 deletions

View File

@ -31,7 +31,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, static __always_inline bool arch_static_branch(struct static_key *key,
bool branch) bool branch)
{ {
asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n"
"1: \n" "1: \n"
"nop \n" "nop \n"
".pushsection __jump_table, \"aw\" \n" ".pushsection __jump_table, \"aw\" \n"
@ -47,7 +47,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key *key, static __always_inline bool arch_static_branch_jump(struct static_key *key,
bool branch) bool branch)
{ {
asm_volatile_goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n" asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)" \n"
"1: \n" "1: \n"
"b %l[l_yes] \n" "b %l[l_yes] \n"
".pushsection __jump_table, \"aw\" \n" ".pushsection __jump_table, \"aw\" \n"

View File

@ -11,7 +11,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
WASM(nop) "\n\t" WASM(nop) "\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
".word 1b, %l[l_yes], %c0\n\t" ".word 1b, %l[l_yes], %c0\n\t"
@ -25,7 +25,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
WASM(b) " %l[l_yes]\n\t" WASM(b) " %l[l_yes]\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
".word 1b, %l[l_yes], %c0\n\t" ".word 1b, %l[l_yes], %c0\n\t"

View File

@ -229,7 +229,7 @@ alternative_has_cap_likely(const unsigned long cpucap)
compiletime_assert(cpucap < ARM64_NCAPS, compiletime_assert(cpucap < ARM64_NCAPS,
"cpucap must be < ARM64_NCAPS"); "cpucap must be < ARM64_NCAPS");
asm_volatile_goto( asm goto(
ALTERNATIVE_CB("b %l[l_no]", %[cpucap], alt_cb_patch_nops) ALTERNATIVE_CB("b %l[l_no]", %[cpucap], alt_cb_patch_nops)
: :
: [cpucap] "i" (cpucap) : [cpucap] "i" (cpucap)
@ -247,7 +247,7 @@ alternative_has_cap_unlikely(const unsigned long cpucap)
compiletime_assert(cpucap < ARM64_NCAPS, compiletime_assert(cpucap < ARM64_NCAPS,
"cpucap must be < ARM64_NCAPS"); "cpucap must be < ARM64_NCAPS");
asm_volatile_goto( asm goto(
ALTERNATIVE("nop", "b %l[l_yes]", %[cpucap]) ALTERNATIVE("nop", "b %l[l_yes]", %[cpucap])
: :
: [cpucap] "i" (cpucap) : [cpucap] "i" (cpucap)

View File

@ -18,7 +18,7 @@
static __always_inline bool arch_static_branch(struct static_key * const key, static __always_inline bool arch_static_branch(struct static_key * const key,
const bool branch) const bool branch)
{ {
asm_volatile_goto( asm goto(
"1: nop \n\t" "1: nop \n\t"
" .pushsection __jump_table, \"aw\" \n\t" " .pushsection __jump_table, \"aw\" \n\t"
" .align 3 \n\t" " .align 3 \n\t"
@ -35,7 +35,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key * const key, static __always_inline bool arch_static_branch_jump(struct static_key * const key,
const bool branch) const bool branch)
{ {
asm_volatile_goto( asm goto(
"1: b %l[l_yes] \n\t" "1: b %l[l_yes] \n\t"
" .pushsection __jump_table, \"aw\" \n\t" " .pushsection __jump_table, \"aw\" \n\t"
" .align 3 \n\t" " .align 3 \n\t"

View File

@ -12,7 +12,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, static __always_inline bool arch_static_branch(struct static_key *key,
bool branch) bool branch)
{ {
asm_volatile_goto( asm goto(
"1: nop32 \n" "1: nop32 \n"
" .pushsection __jump_table, \"aw\" \n" " .pushsection __jump_table, \"aw\" \n"
" .align 2 \n" " .align 2 \n"
@ -29,7 +29,7 @@ label:
static __always_inline bool arch_static_branch_jump(struct static_key *key, static __always_inline bool arch_static_branch_jump(struct static_key *key,
bool branch) bool branch)
{ {
asm_volatile_goto( asm goto(
"1: bsr32 %l[label] \n" "1: bsr32 %l[label] \n"
" .pushsection __jump_table, \"aw\" \n" " .pushsection __jump_table, \"aw\" \n"
" .align 2 \n" " .align 2 \n"

View File

@ -22,7 +22,7 @@
static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{ {
asm_volatile_goto( asm goto(
"1: nop \n\t" "1: nop \n\t"
JUMP_TABLE_ENTRY JUMP_TABLE_ENTRY
: : "i"(&((char *)key)[branch]) : : l_yes); : : "i"(&((char *)key)[branch]) : : l_yes);
@ -35,7 +35,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{ {
asm_volatile_goto( asm goto(
"1: b %l[l_yes] \n\t" "1: b %l[l_yes] \n\t"
JUMP_TABLE_ENTRY JUMP_TABLE_ENTRY
: : "i"(&((char *)key)[branch]) : : l_yes); : : "i"(&((char *)key)[branch]) : : l_yes);

View File

@ -36,7 +36,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\t" B_INSN " 2f\n\t" asm goto("1:\t" B_INSN " 2f\n\t"
"2:\t.insn\n\t" "2:\t.insn\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
WORD_INSN " 1b, %l[l_yes], %0\n\t" WORD_INSN " 1b, %l[l_yes], %0\n\t"
@ -50,7 +50,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\t" J_INSN " %l[l_yes]\n\t" asm goto("1:\t" J_INSN " %l[l_yes]\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
WORD_INSN " 1b, %l[l_yes], %0\n\t" WORD_INSN " 1b, %l[l_yes], %0\n\t"
".popsection\n\t" ".popsection\n\t"

View File

@ -12,7 +12,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
"nop\n\t" "nop\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
".align %1\n\t" ".align %1\n\t"
@ -29,7 +29,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
"b,n %l[l_yes]\n\t" "b,n %l[l_yes]\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
".align %1\n\t" ".align %1\n\t"

View File

@ -17,7 +17,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
"nop # arch_static_branch\n\t" "nop # arch_static_branch\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
".long 1b - ., %l[l_yes] - .\n\t" ".long 1b - ., %l[l_yes] - .\n\t"
@ -32,7 +32,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
"b %l[l_yes] # arch_static_branch_jump\n\t" "b %l[l_yes] # arch_static_branch_jump\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
".long 1b - ., %l[l_yes] - .\n\t" ".long 1b - ., %l[l_yes] - .\n\t"

View File

@ -74,7 +74,7 @@ __pu_failed: \
/* -mprefixed can generate offsets beyond range, fall back hack */ /* -mprefixed can generate offsets beyond range, fall back hack */
#ifdef CONFIG_PPC_KERNEL_PREFIXED #ifdef CONFIG_PPC_KERNEL_PREFIXED
#define __put_user_asm_goto(x, addr, label, op) \ #define __put_user_asm_goto(x, addr, label, op) \
asm_volatile_goto( \ asm goto( \
"1: " op " %0,0(%1) # put_user\n" \ "1: " op " %0,0(%1) # put_user\n" \
EX_TABLE(1b, %l2) \ EX_TABLE(1b, %l2) \
: \ : \
@ -83,7 +83,7 @@ __pu_failed: \
: label) : label)
#else #else
#define __put_user_asm_goto(x, addr, label, op) \ #define __put_user_asm_goto(x, addr, label, op) \
asm_volatile_goto( \ asm goto( \
"1: " op "%U1%X1 %0,%1 # put_user\n" \ "1: " op "%U1%X1 %0,%1 # put_user\n" \
EX_TABLE(1b, %l2) \ EX_TABLE(1b, %l2) \
: \ : \
@ -97,7 +97,7 @@ __pu_failed: \
__put_user_asm_goto(x, ptr, label, "std") __put_user_asm_goto(x, ptr, label, "std")
#else /* __powerpc64__ */ #else /* __powerpc64__ */
#define __put_user_asm2_goto(x, addr, label) \ #define __put_user_asm2_goto(x, addr, label) \
asm_volatile_goto( \ asm goto( \
"1: stw%X1 %0, %1\n" \ "1: stw%X1 %0, %1\n" \
"2: stw%X1 %L0, %L1\n" \ "2: stw%X1 %L0, %L1\n" \
EX_TABLE(1b, %l2) \ EX_TABLE(1b, %l2) \
@ -146,7 +146,7 @@ do { \
/* -mprefixed can generate offsets beyond range, fall back hack */ /* -mprefixed can generate offsets beyond range, fall back hack */
#ifdef CONFIG_PPC_KERNEL_PREFIXED #ifdef CONFIG_PPC_KERNEL_PREFIXED
#define __get_user_asm_goto(x, addr, label, op) \ #define __get_user_asm_goto(x, addr, label, op) \
asm_volatile_goto( \ asm_goto_output( \
"1: "op" %0,0(%1) # get_user\n" \ "1: "op" %0,0(%1) # get_user\n" \
EX_TABLE(1b, %l2) \ EX_TABLE(1b, %l2) \
: "=r" (x) \ : "=r" (x) \
@ -155,7 +155,7 @@ do { \
: label) : label)
#else #else
#define __get_user_asm_goto(x, addr, label, op) \ #define __get_user_asm_goto(x, addr, label, op) \
asm_volatile_goto( \ asm_goto_output( \
"1: "op"%U1%X1 %0, %1 # get_user\n" \ "1: "op"%U1%X1 %0, %1 # get_user\n" \
EX_TABLE(1b, %l2) \ EX_TABLE(1b, %l2) \
: "=r" (x) \ : "=r" (x) \
@ -169,7 +169,7 @@ do { \
__get_user_asm_goto(x, addr, label, "ld") __get_user_asm_goto(x, addr, label, "ld")
#else /* __powerpc64__ */ #else /* __powerpc64__ */
#define __get_user_asm2_goto(x, addr, label) \ #define __get_user_asm2_goto(x, addr, label) \
asm_volatile_goto( \ asm_goto_output( \
"1: lwz%X1 %0, %1\n" \ "1: lwz%X1 %0, %1\n" \
"2: lwz%X1 %L0, %L1\n" \ "2: lwz%X1 %L0, %L1\n" \
EX_TABLE(1b, %l2) \ EX_TABLE(1b, %l2) \

View File

@ -230,7 +230,7 @@ again:
* This allows interrupts to be unmasked without hard disabling, and * This allows interrupts to be unmasked without hard disabling, and
* also without new hard interrupts coming in ahead of pending ones. * also without new hard interrupts coming in ahead of pending ones.
*/ */
asm_volatile_goto( asm goto(
"1: \n" "1: \n"
" lbz 9,%0(13) \n" " lbz 9,%0(13) \n"
" cmpwi 9,0 \n" " cmpwi 9,0 \n"

View File

@ -98,7 +98,7 @@ riscv_has_extension_likely(const unsigned long ext)
"ext must be < RISCV_ISA_EXT_MAX"); "ext must be < RISCV_ISA_EXT_MAX");
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
asm_volatile_goto( asm goto(
ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1) ALTERNATIVE("j %l[l_no]", "nop", 0, %[ext], 1)
: :
: [ext] "i" (ext) : [ext] "i" (ext)
@ -121,7 +121,7 @@ riscv_has_extension_unlikely(const unsigned long ext)
"ext must be < RISCV_ISA_EXT_MAX"); "ext must be < RISCV_ISA_EXT_MAX");
if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
asm_volatile_goto( asm goto(
ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1) ALTERNATIVE("nop", "j %l[l_yes]", 0, %[ext], 1)
: :
: [ext] "i" (ext) : [ext] "i" (ext)

View File

@ -17,7 +17,7 @@
static __always_inline bool arch_static_branch(struct static_key * const key, static __always_inline bool arch_static_branch(struct static_key * const key,
const bool branch) const bool branch)
{ {
asm_volatile_goto( asm goto(
" .align 2 \n\t" " .align 2 \n\t"
" .option push \n\t" " .option push \n\t"
" .option norelax \n\t" " .option norelax \n\t"
@ -39,7 +39,7 @@ label:
static __always_inline bool arch_static_branch_jump(struct static_key * const key, static __always_inline bool arch_static_branch_jump(struct static_key * const key,
const bool branch) const bool branch)
{ {
asm_volatile_goto( asm goto(
" .align 2 \n\t" " .align 2 \n\t"
" .option push \n\t" " .option push \n\t"
" .option norelax \n\t" " .option norelax \n\t"

View File

@ -25,7 +25,7 @@
*/ */
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{ {
asm_volatile_goto("0: brcl 0,%l[label]\n" asm goto("0: brcl 0,%l[label]\n"
".pushsection __jump_table,\"aw\"\n" ".pushsection __jump_table,\"aw\"\n"
".balign 8\n" ".balign 8\n"
".long 0b-.,%l[label]-.\n" ".long 0b-.,%l[label]-.\n"
@ -39,7 +39,7 @@ label:
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
{ {
asm_volatile_goto("0: brcl 15,%l[label]\n" asm goto("0: brcl 15,%l[label]\n"
".pushsection __jump_table,\"aw\"\n" ".pushsection __jump_table,\"aw\"\n"
".balign 8\n" ".balign 8\n"
".long 0b-.,%l[label]-.\n" ".long 0b-.,%l[label]-.\n"

View File

@ -10,7 +10,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
"nop\n\t" "nop\n\t"
"nop\n\t" "nop\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
@ -26,7 +26,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
"b %l[l_yes]\n\t" "b %l[l_yes]\n\t"
"nop\n\t" "nop\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"

View File

@ -75,7 +75,7 @@ extern void setup_clear_cpu_cap(unsigned int bit);
*/ */
static __always_inline bool _static_cpu_has(u16 bit) static __always_inline bool _static_cpu_has(u16 bit)
{ {
asm_volatile_goto("1: jmp 6f\n" asm goto("1: jmp 6f\n"
"2:\n" "2:\n"
".skip -(((5f-4f) - (2b-1b)) > 0) * " ".skip -(((5f-4f) - (2b-1b)) > 0) * "
"((5f-4f) - (2b-1b)),0x90\n" "((5f-4f) - (2b-1b)),0x90\n"

View File

@ -168,7 +168,7 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
*/ */
static __always_inline bool _static_cpu_has(u16 bit) static __always_inline bool _static_cpu_has(u16 bit)
{ {
asm_volatile_goto( asm goto(
ALTERNATIVE_TERNARY("jmp 6f", %P[feature], "", "jmp %l[t_no]") ALTERNATIVE_TERNARY("jmp 6f", %P[feature], "", "jmp %l[t_no]")
".pushsection .altinstr_aux,\"ax\"\n" ".pushsection .altinstr_aux,\"ax\"\n"
"6:\n" "6:\n"

View File

@ -24,7 +24,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{ {
asm_volatile_goto("1:" asm goto("1:"
"jmp %l[l_yes] # objtool NOPs this \n\t" "jmp %l[l_yes] # objtool NOPs this \n\t"
JUMP_TABLE_ENTRY JUMP_TABLE_ENTRY
: : "i" (key), "i" (2 | branch) : : l_yes); : : "i" (key), "i" (2 | branch) : : l_yes);
@ -38,7 +38,7 @@ l_yes:
static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{ {
asm_volatile_goto("1:" asm goto("1:"
".byte " __stringify(BYTES_NOP5) "\n\t" ".byte " __stringify(BYTES_NOP5) "\n\t"
JUMP_TABLE_ENTRY JUMP_TABLE_ENTRY
: : "i" (key), "i" (branch) : : l_yes); : : "i" (key), "i" (branch) : : l_yes);
@ -52,7 +52,7 @@ l_yes:
static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{ {
asm_volatile_goto("1:" asm goto("1:"
"jmp %l[l_yes]\n\t" "jmp %l[l_yes]\n\t"
JUMP_TABLE_ENTRY JUMP_TABLE_ENTRY
: : "i" (key), "i" (branch) : : l_yes); : : "i" (key), "i" (branch) : : l_yes);

View File

@ -13,7 +13,7 @@
#define __GEN_RMWcc(fullop, _var, cc, clobbers, ...) \ #define __GEN_RMWcc(fullop, _var, cc, clobbers, ...) \
({ \ ({ \
bool c = false; \ bool c = false; \
asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ asm goto (fullop "; j" #cc " %l[cc_label]" \
: : [var] "m" (_var), ## __VA_ARGS__ \ : : [var] "m" (_var), ## __VA_ARGS__ \
: clobbers : cc_label); \ : clobbers : cc_label); \
if (0) { \ if (0) { \

View File

@ -205,7 +205,7 @@ static inline void clwb(volatile void *__p)
#ifdef CONFIG_X86_USER_SHADOW_STACK #ifdef CONFIG_X86_USER_SHADOW_STACK
static inline int write_user_shstk_64(u64 __user *addr, u64 val) static inline int write_user_shstk_64(u64 __user *addr, u64 val)
{ {
asm_volatile_goto("1: wrussq %[val], (%[addr])\n" asm goto("1: wrussq %[val], (%[addr])\n"
_ASM_EXTABLE(1b, %l[fail]) _ASM_EXTABLE(1b, %l[fail])
:: [addr] "r" (addr), [val] "r" (val) :: [addr] "r" (addr), [val] "r" (val)
:: fail); :: fail);

View File

@ -133,7 +133,7 @@ extern int __get_user_bad(void);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#define __put_user_goto_u64(x, addr, label) \ #define __put_user_goto_u64(x, addr, label) \
asm_volatile_goto("\n" \ asm goto("\n" \
"1: movl %%eax,0(%1)\n" \ "1: movl %%eax,0(%1)\n" \
"2: movl %%edx,4(%1)\n" \ "2: movl %%edx,4(%1)\n" \
_ASM_EXTABLE_UA(1b, %l2) \ _ASM_EXTABLE_UA(1b, %l2) \
@ -295,7 +295,7 @@ do { \
} while (0) } while (0)
#define __get_user_asm(x, addr, itype, ltype, label) \ #define __get_user_asm(x, addr, itype, ltype, label) \
asm_volatile_goto("\n" \ asm_goto_output("\n" \
"1: mov"itype" %[umem],%[output]\n" \ "1: mov"itype" %[umem],%[output]\n" \
_ASM_EXTABLE_UA(1b, %l2) \ _ASM_EXTABLE_UA(1b, %l2) \
: [output] ltype(x) \ : [output] ltype(x) \
@ -375,7 +375,7 @@ do { \
__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \
__typeof__(*(_ptr)) __old = *_old; \ __typeof__(*(_ptr)) __old = *_old; \
__typeof__(*(_ptr)) __new = (_new); \ __typeof__(*(_ptr)) __new = (_new); \
asm_volatile_goto("\n" \ asm_goto_output("\n" \
"1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\ "1: " LOCK_PREFIX "cmpxchg"itype" %[new], %[ptr]\n"\
_ASM_EXTABLE_UA(1b, %l[label]) \ _ASM_EXTABLE_UA(1b, %l[label]) \
: CC_OUT(z) (success), \ : CC_OUT(z) (success), \
@ -394,7 +394,7 @@ do { \
__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \
__typeof__(*(_ptr)) __old = *_old; \ __typeof__(*(_ptr)) __old = *_old; \
__typeof__(*(_ptr)) __new = (_new); \ __typeof__(*(_ptr)) __new = (_new); \
asm_volatile_goto("\n" \ asm_goto_output("\n" \
"1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n" \ "1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n" \
_ASM_EXTABLE_UA(1b, %l[label]) \ _ASM_EXTABLE_UA(1b, %l[label]) \
: CC_OUT(z) (success), \ : CC_OUT(z) (success), \
@ -477,7 +477,7 @@ struct __large_struct { unsigned long buf[100]; };
* aliasing issues. * aliasing issues.
*/ */
#define __put_user_goto(x, addr, itype, ltype, label) \ #define __put_user_goto(x, addr, itype, ltype, label) \
asm_volatile_goto("\n" \ asm goto("\n" \
"1: mov"itype" %0,%1\n" \ "1: mov"itype" %0,%1\n" \
_ASM_EXTABLE_UA(1b, %l2) \ _ASM_EXTABLE_UA(1b, %l2) \
: : ltype(x), "m" (__m(addr)) \ : : ltype(x), "m" (__m(addr)) \

View File

@ -8,7 +8,7 @@
#define svm_asm(insn, clobber...) \ #define svm_asm(insn, clobber...) \
do { \ do { \
asm_volatile_goto("1: " __stringify(insn) "\n\t" \ asm goto("1: " __stringify(insn) "\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \ _ASM_EXTABLE(1b, %l[fault]) \
::: clobber : fault); \ ::: clobber : fault); \
return; \ return; \
@ -18,7 +18,7 @@ fault: \
#define svm_asm1(insn, op1, clobber...) \ #define svm_asm1(insn, op1, clobber...) \
do { \ do { \
asm_volatile_goto("1: " __stringify(insn) " %0\n\t" \ asm goto("1: " __stringify(insn) " %0\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \ _ASM_EXTABLE(1b, %l[fault]) \
:: op1 : clobber : fault); \ :: op1 : clobber : fault); \
return; \ return; \
@ -28,7 +28,7 @@ fault: \
#define svm_asm2(insn, op1, op2, clobber...) \ #define svm_asm2(insn, op1, op2, clobber...) \
do { \ do { \
asm_volatile_goto("1: " __stringify(insn) " %1, %0\n\t" \ asm goto("1: " __stringify(insn) " %1, %0\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \ _ASM_EXTABLE(1b, %l[fault]) \
:: op1, op2 : clobber : fault); \ :: op1, op2 : clobber : fault); \
return; \ return; \

View File

@ -745,7 +745,7 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx,
*/ */
static int kvm_cpu_vmxoff(void) static int kvm_cpu_vmxoff(void)
{ {
asm_volatile_goto("1: vmxoff\n\t" asm goto("1: vmxoff\n\t"
_ASM_EXTABLE(1b, %l[fault]) _ASM_EXTABLE(1b, %l[fault])
::: "cc", "memory" : fault); ::: "cc", "memory" : fault);
@ -2789,7 +2789,7 @@ static int kvm_cpu_vmxon(u64 vmxon_pointer)
cr4_set_bits(X86_CR4_VMXE); cr4_set_bits(X86_CR4_VMXE);
asm_volatile_goto("1: vmxon %[vmxon_pointer]\n\t" asm goto("1: vmxon %[vmxon_pointer]\n\t"
_ASM_EXTABLE(1b, %l[fault]) _ASM_EXTABLE(1b, %l[fault])
: : [vmxon_pointer] "m"(vmxon_pointer) : : [vmxon_pointer] "m"(vmxon_pointer)
: : fault); : : fault);

View File

@ -94,7 +94,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field)
#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
asm_volatile_goto("1: vmread %[field], %[output]\n\t" asm_goto_output("1: vmread %[field], %[output]\n\t"
"jna %l[do_fail]\n\t" "jna %l[do_fail]\n\t"
_ASM_EXTABLE(1b, %l[do_exception]) _ASM_EXTABLE(1b, %l[do_exception])
@ -188,7 +188,7 @@ static __always_inline unsigned long vmcs_readl(unsigned long field)
#define vmx_asm1(insn, op1, error_args...) \ #define vmx_asm1(insn, op1, error_args...) \
do { \ do { \
asm_volatile_goto("1: " __stringify(insn) " %0\n\t" \ asm goto("1: " __stringify(insn) " %0\n\t" \
".byte 0x2e\n\t" /* branch not taken hint */ \ ".byte 0x2e\n\t" /* branch not taken hint */ \
"jna %l[error]\n\t" \ "jna %l[error]\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \ _ASM_EXTABLE(1b, %l[fault]) \
@ -205,7 +205,7 @@ fault: \
#define vmx_asm2(insn, op1, op2, error_args...) \ #define vmx_asm2(insn, op1, op2, error_args...) \
do { \ do { \
asm_volatile_goto("1: " __stringify(insn) " %1, %0\n\t" \ asm goto("1: " __stringify(insn) " %1, %0\n\t" \
".byte 0x2e\n\t" /* branch not taken hint */ \ ".byte 0x2e\n\t" /* branch not taken hint */ \
"jna %l[error]\n\t" \ "jna %l[error]\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \ _ASM_EXTABLE(1b, %l[fault]) \

View File

@ -13,7 +13,7 @@
static __always_inline bool arch_static_branch(struct static_key *key, static __always_inline bool arch_static_branch(struct static_key *key,
bool branch) bool branch)
{ {
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
"_nop\n\t" "_nop\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
".word 1b, %l[l_yes], %c0\n\t" ".word 1b, %l[l_yes], %c0\n\t"
@ -38,7 +38,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key,
* make it reachable and wrap both into a no-transform block * make it reachable and wrap both into a no-transform block
* to avoid any assembler interference with this. * to avoid any assembler interference with this.
*/ */
asm_volatile_goto("1:\n\t" asm goto("1:\n\t"
".begin no-transform\n\t" ".begin no-transform\n\t"
"_j %l[l_yes]\n\t" "_j %l[l_yes]\n\t"
"2:\n\t" "2:\n\t"

View File

@ -66,6 +66,25 @@
__builtin_unreachable(); \ __builtin_unreachable(); \
} while (0) } while (0)
/*
* GCC 'asm goto' with outputs miscompiles certain code sequences:
*
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110420
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110422
*
* Work it around via the same compiler barrier quirk that we used
* to use for the old 'asm goto' workaround.
*
* Also, always mark such 'asm goto' statements as volatile: all
* asm goto statements are supposed to be volatile as per the
* documentation, but some versions of gcc didn't actually do
* that for asms with outputs:
*
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98619
*/
#define asm_goto_output(x...) \
do { asm volatile goto(x); asm (""); } while (0)
#if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP) #if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP)
#define __HAVE_BUILTIN_BSWAP32__ #define __HAVE_BUILTIN_BSWAP32__
#define __HAVE_BUILTIN_BSWAP64__ #define __HAVE_BUILTIN_BSWAP64__

View File

@ -352,8 +352,8 @@ struct ftrace_likely_data {
# define __realloc_size(x, ...) # define __realloc_size(x, ...)
#endif #endif
#ifndef asm_volatile_goto #ifndef asm_goto_output
#define asm_volatile_goto(x...) asm goto(x) #define asm_goto_output(x...) asm goto(x)
#endif #endif
#ifdef CONFIG_CC_HAS_ASM_INLINE #ifdef CONFIG_CC_HAS_ASM_INLINE

View File

@ -57,7 +57,7 @@
/* Jump to label if @reg is zero */ /* Jump to label if @reg is zero */
#define NFT_PIPAPO_AVX2_NOMATCH_GOTO(reg, label) \ #define NFT_PIPAPO_AVX2_NOMATCH_GOTO(reg, label) \
asm_volatile_goto("vptest %%ymm" #reg ", %%ymm" #reg ";" \ asm goto("vptest %%ymm" #reg ", %%ymm" #reg ";" \
"je %l[" #label "]" : : : : label) "je %l[" #label "]" : : : : label)
/* Store 256 bits from YMM register into memory. Contrary to bucket load /* Store 256 bits from YMM register into memory. Contrary to bucket load

View File

@ -4,14 +4,14 @@
#define __ASM_GOTO_WORKAROUND_H #define __ASM_GOTO_WORKAROUND_H
/* /*
* This will bring in asm_volatile_goto and asm_inline macro definitions * This will bring in asm_goto_output and asm_inline macro definitions
* if enabled by compiler and config options. * if enabled by compiler and config options.
*/ */
#include <linux/types.h> #include <linux/types.h>
#ifdef asm_volatile_goto #ifdef asm_goto_output
#undef asm_volatile_goto #undef asm_goto_output
#define asm_volatile_goto(x...) asm volatile("invalid use of asm_volatile_goto") #define asm_goto_output(x...) asm volatile("invalid use of asm_goto_output")
#endif #endif
/* /*

View File

@ -4,7 +4,7 @@
#define __GEN_RMWcc(fullop, var, cc, ...) \ #define __GEN_RMWcc(fullop, var, cc, ...) \
do { \ do { \
asm_volatile_goto (fullop "; j" cc " %l[cc_label]" \ asm goto (fullop "; j" cc " %l[cc_label]" \
: : "m" (var), ## __VA_ARGS__ \ : : "m" (var), ## __VA_ARGS__ \
: "memory" : cc_label); \ : "memory" : cc_label); \
return 0; \ return 0; \

View File

@ -36,8 +36,8 @@
#include <linux/compiler-gcc.h> #include <linux/compiler-gcc.h>
#endif #endif
#ifndef asm_volatile_goto #ifndef asm_goto_output
#define asm_volatile_goto(x...) asm goto(x) #define asm_goto_output(x...) asm goto(x)
#endif #endif
#endif /* __LINUX_COMPILER_TYPES_H */ #endif /* __LINUX_COMPILER_TYPES_H */