[PATCH 2/2] arm64: alternatives: Work around NOP generation with broken assembler

Will Deacon will.deacon at arm.com
Mon Dec 5 02:05:46 PST 2016


On Sat, Dec 03, 2016 at 02:05:38PM +0000, Marc Zyngier wrote:
> When compiling a .inst directive in an alternative clause with
> a rather old version of gas (circa 2.24), and when used with
> the alternative_else_nop_endif feature, the compilation fails
> with a rather cryptic message such as:
> 
> arch/arm64/lib/clear_user.S:33: Error: bad or irreducible absolute expression
> 
> which is caused by the bug described in eb7c11ee3c5c ("arm64:
> alternative: Work around .inst assembler bugs").
> 
> This effectively prevents the use of the "nops" macro, which
> requires the number of instruction as a parameter (the assembler
> is confused and unable to compute the difference between two labels).
> 
> As an alternative(!), use the .fill directive to output the number
> of required NOPs (.fill has the good idea to output the fill pattern
> in the endianness of the instruction stream).

Are you sure about that? The gas docs say:

`The contents of each repeat bytes is taken from an 8-byte number. The
 highest order 4 bytes are zero. The lowest order 4 bytes are value rendered
 in the byte-order of an integer on the computer as is assembling for.'

and I'd expect "integer" to refer to data values, rather than instructions.

> 
> Fixes: 792d47379f4d ("arm64: alternative: add auto-nop infrastructure")
> Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
> ---
>  arch/arm64/include/asm/alternative.h | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
> index 39feb85..39f8c98 100644
> --- a/arch/arm64/include/asm/alternative.h
> +++ b/arch/arm64/include/asm/alternative.h
> @@ -159,9 +159,19 @@ void apply_alternatives(void *start, size_t length);
>   * of NOPs. The number of NOPs is chosen automatically to match the
>   * previous case.
>   */
> +
> +#define NOP_INST	0xd503201f

If we define this, let's put it in insn.h or something. It could even be
used in the vdso linker script, which open codes this constant.

> +
>  .macro alternative_else_nop_endif
>  alternative_else
> -	nops	(662b-661b) / AARCH64_INSN_SIZE
> +	/*
> +	 * The same assembler bug strikes again here if the first half
> +	 * of the alternative sequence contains a .inst, leading to a
> +	 * bizarre error message. Fortulately, .fill replaces the

Fortunately

> +	 * "nops" macro by inserting padding with the target machine
> +	 * endianness.
> +	 */
> +	.fill	(662b-661b) / AARCH64_INSN_SIZE, AARCH64_INSN_SIZE, NOP_INST

Assuming we can get .fill to do the right thing, we should probably use
it in __nops rather than open-coding it here. Or is the issue that we're
unable to pass (662b-661b) / AARCH64_INSN_SIZE to any macro?

Will



More information about the linux-arm-kernel mailing list