x86/bug: Merge annotate_reachable() into _BUG_FLAGS() asm

In __WARN_FLAGS(), we had two asm statements (abbreviated):

asm volatile("ud2");
asm volatile(".pushsection .discard.reachable");

These pair of statements are used to trigger an exception, but then help
objtool understand that for warnings, control flow will be restored
immediately afterwards.

The problem is that volatile is not a compiler barrier. GCC explicitly
documents this:

> Note that the compiler can move even volatile asm instructions
> relative to other code, including across jump instructions.

Also, no clobbers are specified to prevent instructions from subsequent
statements from being scheduled by compiler before the second asm
statement. This can lead to instructions from subsequent statements
being emitted by the compiler before the second asm statement.

Providing a scheduling model such as via -march= options enables the
compiler to better schedule instructions with known latencies to hide
latencies from data hazards compared to inline asm statements in which
latencies are not estimated.

If an instruction gets scheduled by the compiler between the two asm
statements, then objtool will think that it is not reachable, producing
a warning.

To prevent instructions from being scheduled in between the two asm
statements, merge them.

Also remove an unnecessary unreachable() asm annotation from BUG() in
favor of __builtin_unreachable(). objtool is able to track that the ud2
from BUG() terminates control flow within the function.

Link: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile
Link: https://github.com/ClangBuiltLinux/linux/issues/1483
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/r/20220202205557.2260694-1-ndesaulniers@google.com

authored by Nick Desaulniers and committed by Josh Poimboeuf bfb1a7c9 82880283

Changed files
+16 -25
arch
x86
include
asm
include
linux
+11 -9
arch/x86/include/asm/bug.h
··· 22 22 23 23 #ifdef CONFIG_DEBUG_BUGVERBOSE 24 24 25 - #define _BUG_FLAGS(ins, flags) \ 25 + #define _BUG_FLAGS(ins, flags, extra) \ 26 26 do { \ 27 27 asm_inline volatile("1:\t" ins "\n" \ 28 28 ".pushsection __bug_table,\"aw\"\n" \ ··· 31 31 "\t.word %c1" "\t# bug_entry::line\n" \ 32 32 "\t.word %c2" "\t# bug_entry::flags\n" \ 33 33 "\t.org 2b+%c3\n" \ 34 - ".popsection" \ 34 + ".popsection\n" \ 35 + extra \ 35 36 : : "i" (__FILE__), "i" (__LINE__), \ 36 37 "i" (flags), \ 37 38 "i" (sizeof(struct bug_entry))); \ ··· 40 39 41 40 #else /* !CONFIG_DEBUG_BUGVERBOSE */ 42 41 43 - #define _BUG_FLAGS(ins, flags) \ 42 + #define _BUG_FLAGS(ins, flags, extra) \ 44 43 do { \ 45 44 asm_inline volatile("1:\t" ins "\n" \ 46 45 ".pushsection __bug_table,\"aw\"\n" \ 47 46 "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \ 48 47 "\t.word %c0" "\t# bug_entry::flags\n" \ 49 48 "\t.org 2b+%c1\n" \ 50 - ".popsection" \ 49 + ".popsection\n" \ 50 + extra \ 51 51 : : "i" (flags), \ 52 52 "i" (sizeof(struct bug_entry))); \ 53 53 } while (0) ··· 57 55 58 56 #else 59 57 60 - #define _BUG_FLAGS(ins, flags) asm volatile(ins) 58 + #define _BUG_FLAGS(ins, flags, extra) asm volatile(ins) 61 59 62 60 #endif /* CONFIG_GENERIC_BUG */ 63 61 ··· 65 63 #define BUG() \ 66 64 do { \ 67 65 instrumentation_begin(); \ 68 - _BUG_FLAGS(ASM_UD2, 0); \ 69 - unreachable(); \ 66 + _BUG_FLAGS(ASM_UD2, 0, ""); \ 67 + __builtin_unreachable(); \ 70 68 } while (0) 71 69 72 70 /* ··· 77 75 */ 78 76 #define __WARN_FLAGS(flags) \ 79 77 do { \ 78 + __auto_type f = BUGFLAG_WARNING|(flags); \ 80 79 instrumentation_begin(); \ 81 - _BUG_FLAGS(ASM_UD2, BUGFLAG_WARNING|(flags)); \ 82 - annotate_reachable(); \ 80 + _BUG_FLAGS(ASM_UD2, f, ASM_REACHABLE); \ 83 81 instrumentation_end(); \ 84 82 } while (0) 85 83
+5 -16
include/linux/compiler.h
··· 117 117 */ 118 118 #define __stringify_label(n) #n 119 119 120 - #define __annotate_reachable(c) ({ \ 121 - asm volatile(__stringify_label(c) ":\n\t" \ 122 - ".pushsection .discard.reachable\n\t" \ 123 - ".long " __stringify_label(c) "b - .\n\t" \ 124 - ".popsection\n\t" : : "i" (c)); \ 125 - }) 126 - #define annotate_reachable() __annotate_reachable(__COUNTER__) 127 - 128 120 #define __annotate_unreachable(c) ({ \ 129 121 asm volatile(__stringify_label(c) ":\n\t" \ 130 122 ".pushsection .discard.unreachable\n\t" \ ··· 125 133 }) 126 134 #define annotate_unreachable() __annotate_unreachable(__COUNTER__) 127 135 128 - #define ASM_UNREACHABLE \ 129 - "999:\n\t" \ 130 - ".pushsection .discard.unreachable\n\t" \ 131 - ".long 999b - .\n\t" \ 136 + #define ASM_REACHABLE \ 137 + "998:\n\t" \ 138 + ".pushsection .discard.reachable\n\t" \ 139 + ".long 998b - .\n\t" \ 132 140 ".popsection\n\t" 133 141 134 142 /* Annotate a C jump table to allow objtool to follow the code flow */ 135 143 #define __annotate_jump_table __section(".rodata..c_jump_table") 136 144 137 145 #else 138 - #define annotate_reachable() 139 146 #define annotate_unreachable() 147 + # define ASM_REACHABLE 140 148 #define __annotate_jump_table 141 149 #endif 142 150 143 - #ifndef ASM_UNREACHABLE 144 - # define ASM_UNREACHABLE 145 - #endif 146 151 #ifndef unreachable 147 152 # define unreachable() do { \ 148 153 annotate_unreachable(); \