Message ID | 20191031194652.118427-1-samitolvanen@google.com (mailing list archive) |
---|---|
State | Mainlined |
Commit | c54f90c2627cc316d365e3073614731e17dbc631 |
Headers | show |
Series | [RESEND] arm64: fix alternatives with LLVM's integrated assembler | expand |
On Thu, Oct 31, 2019 at 12:46:52PM -0700, Sami Tolvanen wrote: > LLVM's integrated assembler fails with the following error when > building KVM: > > <inline asm>:12:6: error: expected absolute expression > .if kvm_update_va_mask == 0 > ^ > <inline asm>:21:6: error: expected absolute expression > .if kvm_update_va_mask == 0 > ^ > <inline asm>:24:2: error: unrecognized instruction mnemonic > NOT_AN_INSTRUCTION > ^ > LLVM ERROR: Error parsing inline asm > > These errors come from ALTERNATIVE_CB and __ALTERNATIVE_CFG, > which test for the existence of the callback parameter in inline > assembly using the following expression: > > " .if " __stringify(cb) " == 0\n" > > This works with GNU as, but isn't supported by LLVM. This change > splits __ALTERNATIVE_CFG and ALTINSTR_ENTRY into separate macros > to fix the LLVM build. > > Link: https://github.com/ClangBuiltLinux/linux/issues/472 > Signed-off-by: Sami Tolvanen <samitolvanen@google.com> Reviewed-by: Kees Cook <keescook@chromium.org> -Kees > Tested-by: Nick Desaulniers <ndesaulniers@google.com> > --- > arch/arm64/include/asm/alternative.h | 32 ++++++++++++++++++---------- > 1 file changed, 21 insertions(+), 11 deletions(-) > > diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h > index b9f8d787eea9..324e7d5ab37e 100644 > --- a/arch/arm64/include/asm/alternative.h > +++ b/arch/arm64/include/asm/alternative.h > @@ -35,13 +35,16 @@ void apply_alternatives_module(void *start, size_t length); > static inline void apply_alternatives_module(void *start, size_t length) { } > #endif > > -#define ALTINSTR_ENTRY(feature,cb) \ > +#define ALTINSTR_ENTRY(feature) \ > " .word 661b - .\n" /* label */ \ > - " .if " __stringify(cb) " == 0\n" \ > " .word 663f - .\n" /* new instruction */ \ > - " .else\n" \ > + " .hword " __stringify(feature) "\n" /* feature bit */ \ > + " .byte 662b-661b\n" /* source len */ \ > + " .byte 664f-663f\n" /* replacement len */ > + > +#define ALTINSTR_ENTRY_CB(feature, cb) \ > + " .word 661b - .\n" /* label */ \ > " .word " __stringify(cb) "- .\n" /* callback */ \ > - " .endif\n" \ > " .hword " __stringify(feature) "\n" /* feature bit */ \ > " .byte 662b-661b\n" /* source len */ \ > " .byte 664f-663f\n" /* replacement len */ > @@ -62,15 +65,14 @@ static inline void apply_alternatives_module(void *start, size_t length) { } > * > * Alternatives with callbacks do not generate replacement instructions. > */ > -#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb) \ > +#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \ > ".if "__stringify(cfg_enabled)" == 1\n" \ > "661:\n\t" \ > oldinstr "\n" \ > "662:\n" \ > ".pushsection .altinstructions,\"a\"\n" \ > - ALTINSTR_ENTRY(feature,cb) \ > + ALTINSTR_ENTRY(feature) \ > ".popsection\n" \ > - " .if " __stringify(cb) " == 0\n" \ > ".pushsection .altinstr_replacement, \"a\"\n" \ > "663:\n\t" \ > newinstr "\n" \ > @@ -78,17 +80,25 @@ static inline void apply_alternatives_module(void *start, size_t length) { } > ".popsection\n\t" \ > ".org . - (664b-663b) + (662b-661b)\n\t" \ > ".org . - (662b-661b) + (664b-663b)\n" \ > - ".else\n\t" \ > + ".endif\n" > + > +#define __ALTERNATIVE_CFG_CB(oldinstr, feature, cfg_enabled, cb) \ > + ".if "__stringify(cfg_enabled)" == 1\n" \ > + "661:\n\t" \ > + oldinstr "\n" \ > + "662:\n" \ > + ".pushsection .altinstructions,\"a\"\n" \ > + ALTINSTR_ENTRY_CB(feature, cb) \ > + ".popsection\n" \ > "663:\n\t" \ > "664:\n\t" \ > - ".endif\n" \ > ".endif\n" > > #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \ > - __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0) > + __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg)) > > #define ALTERNATIVE_CB(oldinstr, cb) \ > - __ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb) > + __ALTERNATIVE_CFG_CB(oldinstr, ARM64_CB_PATCH, 1, cb) > #else > > #include <asm/assembler.h> > -- > 2.24.0.rc0.303.g954a862665-goog >
Hi Sami, Sorry -- I thought I'd already replied to this, but it had actually slipped through the cracks. On Thu, Oct 31, 2019 at 12:46:52PM -0700, Sami Tolvanen wrote: > LLVM's integrated assembler fails with the following error when > building KVM: > > <inline asm>:12:6: error: expected absolute expression > .if kvm_update_va_mask == 0 > ^ > <inline asm>:21:6: error: expected absolute expression > .if kvm_update_va_mask == 0 > ^ > <inline asm>:24:2: error: unrecognized instruction mnemonic > NOT_AN_INSTRUCTION > ^ > LLVM ERROR: Error parsing inline asm > > These errors come from ALTERNATIVE_CB and __ALTERNATIVE_CFG, > which test for the existence of the callback parameter in inline > assembly using the following expression: > > " .if " __stringify(cb) " == 0\n" > > This works with GNU as, but isn't supported by LLVM. This change > splits __ALTERNATIVE_CFG and ALTINSTR_ENTRY into separate macros > to fix the LLVM build. Please could you explain a bit more about the failure and why LLVM's integrated assembler rejects this? Could we use something like .ifb or .ifeqs instead? Thanks, Will
On Thu, Nov 14, 2019 at 8:55 AM Will Deacon <will@kernel.org> wrote: > > Hi Sami, > > Sorry -- I thought I'd already replied to this, but it had actually > slipped through the cracks. > > On Thu, Oct 31, 2019 at 12:46:52PM -0700, Sami Tolvanen wrote: > > LLVM's integrated assembler fails with the following error when > > building KVM: > > > > <inline asm>:12:6: error: expected absolute expression > > .if kvm_update_va_mask == 0 > > ^ > > <inline asm>:21:6: error: expected absolute expression > > .if kvm_update_va_mask == 0 > > ^ > > <inline asm>:24:2: error: unrecognized instruction mnemonic > > NOT_AN_INSTRUCTION > > ^ > > LLVM ERROR: Error parsing inline asm > > > > These errors come from ALTERNATIVE_CB and __ALTERNATIVE_CFG, > > which test for the existence of the callback parameter in inline > > assembly using the following expression: > > > > " .if " __stringify(cb) " == 0\n" > > > > This works with GNU as, but isn't supported by LLVM. This change > > splits __ALTERNATIVE_CFG and ALTINSTR_ENTRY into separate macros > > to fix the LLVM build. > > Please could you explain a bit more about the failure and why LLVM's > integrated assembler rejects this? There are currently more than one issue with `.if` assembler directives we're tracking against Clang's integrated assembler currently, particularly around the handling of special cases related to "fragments." Recommended reading: https://eli.thegreenplace.net/2013/01/03/assembler-relaxation This particular case looks like the error is related to referring to section before it has been seen. My current understanding is that Clang's integrated assembler is one pass, unlike GAS, so it chokes on references to symbols it has not yet seen. > Could we use something like .ifb or > .ifeqs instead? > > Thanks, > > Will
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index b9f8d787eea9..324e7d5ab37e 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -35,13 +35,16 @@ void apply_alternatives_module(void *start, size_t length); static inline void apply_alternatives_module(void *start, size_t length) { } #endif -#define ALTINSTR_ENTRY(feature,cb) \ +#define ALTINSTR_ENTRY(feature) \ " .word 661b - .\n" /* label */ \ - " .if " __stringify(cb) " == 0\n" \ " .word 663f - .\n" /* new instruction */ \ - " .else\n" \ + " .hword " __stringify(feature) "\n" /* feature bit */ \ + " .byte 662b-661b\n" /* source len */ \ + " .byte 664f-663f\n" /* replacement len */ + +#define ALTINSTR_ENTRY_CB(feature, cb) \ + " .word 661b - .\n" /* label */ \ " .word " __stringify(cb) "- .\n" /* callback */ \ - " .endif\n" \ " .hword " __stringify(feature) "\n" /* feature bit */ \ " .byte 662b-661b\n" /* source len */ \ " .byte 664f-663f\n" /* replacement len */ @@ -62,15 +65,14 @@ static inline void apply_alternatives_module(void *start, size_t length) { } * * Alternatives with callbacks do not generate replacement instructions. */ -#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb) \ +#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \ ".if "__stringify(cfg_enabled)" == 1\n" \ "661:\n\t" \ oldinstr "\n" \ "662:\n" \ ".pushsection .altinstructions,\"a\"\n" \ - ALTINSTR_ENTRY(feature,cb) \ + ALTINSTR_ENTRY(feature) \ ".popsection\n" \ - " .if " __stringify(cb) " == 0\n" \ ".pushsection .altinstr_replacement, \"a\"\n" \ "663:\n\t" \ newinstr "\n" \ @@ -78,17 +80,25 @@ static inline void apply_alternatives_module(void *start, size_t length) { } ".popsection\n\t" \ ".org . - (664b-663b) + (662b-661b)\n\t" \ ".org . - (662b-661b) + (664b-663b)\n" \ - ".else\n\t" \ + ".endif\n" + +#define __ALTERNATIVE_CFG_CB(oldinstr, feature, cfg_enabled, cb) \ + ".if "__stringify(cfg_enabled)" == 1\n" \ + "661:\n\t" \ + oldinstr "\n" \ + "662:\n" \ + ".pushsection .altinstructions,\"a\"\n" \ + ALTINSTR_ENTRY_CB(feature, cb) \ + ".popsection\n" \ "663:\n\t" \ "664:\n\t" \ - ".endif\n" \ ".endif\n" #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \ - __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0) + __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg)) #define ALTERNATIVE_CB(oldinstr, cb) \ - __ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb) + __ALTERNATIVE_CFG_CB(oldinstr, ARM64_CB_PATCH, 1, cb) #else #include <asm/assembler.h>