[PATCH] arm64: Work around broken GCC handling of "S" constraint

Ard Biesheuvel ardb at kernel.org
Mon Dec 7 12:19:21 EST 2020


(resend with David's email address fixed)

On Mon, 7 Dec 2020 at 18:17, Ard Biesheuvel <ardb at kernel.org> wrote:
>
> On Mon, 7 Dec 2020 at 16:43, Marc Zyngier <maz at kernel.org> wrote:
> >
> > GCC 4.9 seems to have a problem with the "S" asm constraint
> > when the symbol lives in the same compilation unit, and pretends
> > the constraint is impossible:
> >
> > $ cat x.c
> > void *foo(void)
> > {
> >         static int x;
> >         int *addr;
> >         asm("adrp %0, %1" : "=r" (addr) : "S" (&x));
> >         return addr;
> > }
> >
> > $ ~/Work/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux/bin/aarch64-linux-gnu-gcc -S -x c -O2 x.c
> > x.c: In function ‘foo’:
> > x.c:5:2: error: impossible constraint in ‘asm’
> >   asm("adrp %0, %1" : "=r" (addr) : "S" (&x));
> >   ^
> >
> > Boo. Following revisions of the compiler work just fine, though.
> >
> > We can fallback to the "i" constraint in that case, which
> > *seems* to do the right thing. Hopefully we will be able to
> > remove this at some point, but in the meantime this gets us going.
> >
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
>
> > ---
> >  arch/arm64/Makefile              | 9 +++++++++
> >  arch/arm64/include/asm/kvm_asm.h | 8 +++++++-
> >  2 files changed, 16 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
> > index 5789c2d18d43..c4ee8e64ad1a 100644
> > --- a/arch/arm64/Makefile
> > +++ b/arch/arm64/Makefile
> > @@ -44,12 +44,21 @@ cc_has_k_constraint := $(call try-run,echo                          \
> >                 return 0;                                               \
> >         }' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1)
> >
> > +cc_has_broken_s_constraint := $(call try-run,echo                      \
> > +       'void *foo(void) {                                              \
> > +               static int x;                                           \
> > +               int *addr;                                              \
> > +               asm("adrp %0, %1" : "=r" (addr) : "S" (&x));            \
> > +               return addr;                                            \
> > +       }' | $(CC) -S -x c -c -O2 -o "$$TMP" -,,-DCONFIG_CC_HAS_BROKEN_S_CONSTRAINT=1)
> > +
> >  ifeq ($(CONFIG_BROKEN_GAS_INST),y)
> >  $(warning Detected assembler with broken .inst; disassembly will be unreliable)
> >  endif
> >
> >  KBUILD_CFLAGS  += -mgeneral-regs-only  \
> >                    $(compat_vdso) $(cc_has_k_constraint)
> > +KBUILD_CFLAGS  += $(cc_has_broken_s_constraint)
> >  KBUILD_CFLAGS  += $(call cc-disable-warning, psabi)
> >  KBUILD_AFLAGS  += $(compat_vdso)
> >
> > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > index 7ccf770c53d9..fa8e886998a3 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -199,6 +199,12 @@ extern void __vgic_v3_init_lrs(void);
> >
> >  extern u32 __kvm_get_mdcr_el2(void);
> >
> > +#ifdef CONFIG_CC_HAS_BROKEN_S_CONSTRAINT
> > +#define SYM_CONSTRAINT "i"
> > +#else
> > +#define SYM_CONSTRAINT "S"
> > +#endif
> > +
>
> Could we just check GCC_VERSION here?
>
> >  /*
> >   * Obtain the PC-relative address of a kernel symbol
> >   * s: symbol
> > @@ -215,7 +221,7 @@ extern u32 __kvm_get_mdcr_el2(void);
> >                 typeof(s) *addr;                                        \
> >                 asm("adrp       %0, %1\n"                               \
> >                     "add        %0, %0, :lo12:%1\n"                     \
> > -                   : "=r" (addr) : "S" (&s));                          \
> > +                   : "=r" (addr) : SYM_CONSTRAINT (&s));               \
> >                 addr;                                                   \
> >         })
> >
> > --
> > 2.29.2
> >



More information about the linux-arm-kernel mailing list