MIPS: fix build with binutils 2.24.51+
RFC PATCH v4 1/1 MIPS: fix build with binutils 2.24.51+
Starting with version 2.24.51.20140728 MIPS binutils complain loudly about mixing soft-float and hard-float object files, leading to this build failure since GCC is invoked with "-msoft-float" on MIPS:
{standard input}: Warning: .gnu_attribute 4,3 requires `softfloat'
LD arch/mips/alchemy/common/built-in.o
mipsel-softfloat-linux-gnu-ld: Warning: arch/mips/alchemy/common/built-in.o
uses -msoft-float (set by arch/mips/alchemy/common/prom.o), arch/mips/alchemy/common/sleeper.o uses -mhard-float
To fix this, we detect if GAS is new enough to support "-msoft-float" command option, and if it does, we can let GCC pass it to GAS; but then we also need to sprinkle the files which make use of floating point registers with the necessary ".set hardfloat" directives.
---
Compiles with binutils 2.23 and current git head, 32bit mips32r1 tested only.
Tests on 64bit and with MSA and other extensions also appreciated!
Markos: I can't reproduce the malta defconfig error you're seeing, at least not with sourceware sources.
v4: fixed issues outlined by Markos and Matthew.
v3: incorporate Maciej's suggestions:
- detect if gas can handle -msoft-float and ".set hardfloat"
- apply .set hardfloat only where really necessary
v2: cover more files
This was introduced in binutils commit 351cdf24d223290b15fa991e5052ec9e9bd1e284 ("[MIPS] Implement O32 FPXX, FP64 and FP64A ABI extensions").
arch/mips/Makefile | 9 +++++++++ arch/mips/include/asm/asmmacro-32.h | 6 ++++++ arch/mips/include/asm/asmmacro.h | 18 ++++++++++++++++++ arch/mips/include/asm/fpregdef.h | 14 ++++++++++++++ arch/mips/include/asm/fpu.h | 4 ++-- arch/mips/include/asm/mipsregs.h | 11 ++++++++++- arch/mips/kernel/branch.c | 8 ++------ arch/mips/kernel/genex.S | 1 + arch/mips/kernel/r2300_fpu.S | 6 ++++++ arch/mips/kernel/r2300_switch.S | 5 +++++ arch/mips/kernel/r4k_fpu.S | 18 ++++++++++++++++++ arch/mips/kernel/r4k_switch.S | 9 +++++++++ arch/mips/kernel/r6000_fpu.S | 5 +++++ 13 files changed, 105 insertions(+), 9 deletions(-)
arch/mips/Makefile +9 -0
@@ -93,6 +93,15 @@ LDFLAGS_vmlinux += -G 0 -static -n -nostdlib KBUILD_AFLAGS_MODULE += -mlong-calls KBUILD_CFLAGS_MODULE += -mlong-calls +# +# pass -msoft-float to GAS if it supports it. However on newer binutils +# (specifically newer than 2.24.51.20140728) we then also need to explicitly +# set ".set hardfloat" in all files which manipulate floating point registers. +# +ifneq ($(call as-option,-Wa$(comma)-msoft-float,),) + cflags-y += -DGAS_HAS_SET_HARDFLOAT -Wa,-msoft-float +endif + cflags-y += -ffreestanding #
arch/mips/include/asm/asmmacro-32.h +6 -0
@@ -13,6 +13,8 @@#include <asm/mipsregs.h> .macro fpu_save_single thread tmp=t0 + .set push +SET_HARDFLOAT cfc1 \tmp, fcr31 swc1 $f0, THREAD_FPR0_LS64(\thread) swc1 $f1, THREAD_FPR1_LS64(\thread)
@@ -47,9 +49,12 @@ swc1 $f30, THREAD_FPR30_LS64(\thread) swc1 $f31, THREAD_FPR31_LS64(\thread) sw \tmp, THREAD_FCR31(\thread) + .set pop .endm .macro fpu_restore_single thread tmp=t0 + .set push +SET_HARDFLOAT lw \tmp, THREAD_FCR31(\thread) lwc1 $f0, THREAD_FPR0_LS64(\thread) lwc1 $f1, THREAD_FPR1_LS64(\thread)
@@ -84,6 +89,7 @@ lwc1 $f30, THREAD_FPR30_LS64(\thread) lwc1 $f31, THREAD_FPR31_LS64(\thread) ctc1 \tmp, fcr31 + .set pop .endm .macro cpu_save_nonscratch thread
arch/mips/include/asm/asmmacro.h +18 -0
@@ -57,6 +57,8 @@#endif /* CONFIG_CPU_MIPSR2 */ .macro fpu_save_16even thread tmp=t0 + .set push +SET_HARDFLOAT cfc1 \tmp, fcr31 sdc1 $f0, THREAD_FPR0_LS64(\thread) sdc1 $f2, THREAD_FPR2_LS64(\thread)
@@ -75,11 +77,13 @@ sdc1 $f28, THREAD_FPR28_LS64(\thread) sdc1 $f30, THREAD_FPR30_LS64(\thread) sw \tmp, THREAD_FCR31(\thread) + .set pop .endm .macro fpu_save_16odd thread .set push .set mips64r2 + SET_HARDFLOAT sdc1 $f1, THREAD_FPR1_LS64(\thread) sdc1 $f3, THREAD_FPR3_LS64(\thread) sdc1 $f5, THREAD_FPR5_LS64(\thread)
@@ -110,6 +114,8 @@ .endm .macro fpu_restore_16even thread tmp=t0 + .set push +SET_HARDFLOAT lw \tmp, THREAD_FCR31(\thread) ldc1 $f0, THREAD_FPR0_LS64(\thread) ldc1 $f2, THREAD_FPR2_LS64(\thread)
@@ -133,6 +139,7 @@ .macro fpu_restore_16odd thread .set push .set mips64r2 +SET_HARDFLOAT ldc1 $f1, THREAD_FPR1_LS64(\thread) ldc1 $f3, THREAD_FPR3_LS64(\thread) ldc1 $f5, THREAD_FPR5_LS64(\thread)
@@ -277,6 +284,7 @@ .macro cfcmsa rd, cs .set push .set noat + SET_HARDFLOAT .insn .word CFC_MSA_INSN | (\cs << 11) move \rd, $1
@@ -286,6 +294,7 @@ .macro ctcmsa cd, rs .set push .set noat + SET_HARDFLOAT move $1, \rs .word CTC_MSA_INSN | (\cd << 6) .set pop
@@ -294,6 +303,7 @@ .macro ld_d wd, off, base .set push .set noat + SET_HARDFLOAT add $1, \base, \off .word LDD_MSA_INSN | (\wd << 6) .set pop
@@ -302,6 +312,7 @@ .macro st_d wd, off, base .set push .set noat + SET_HARDFLOAT add $1, \base, \off .word STD_MSA_INSN | (\wd << 6) .set pop
@@ -310,6 +321,7 @@ .macro copy_u_w rd, ws, n .set push .set noat + SET_HARDFLOAT .insn .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11)/* move triggers an assembler bug... */
@@ -320,6 +332,7 @@ .macro copy_u_d rd, ws, n .set push .set noat + SET_HARDFLOAT .insn .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11)/* move triggers an assembler bug... */
@@ -330,6 +343,7 @@ .macro insert_w wd, n, rs .set push .set noat +SET_HARDFLOAT /* move triggers an assembler bug... */ or $1, \rs, zero .word INSERT_W_MSA_INSN | (\n << 16) | (\wd << 6)
@@ -339,6 +353,7 @@ .macro insert_d wd, n, rs .set push .set noat +SET_HARDFLOAT /* move triggers an assembler bug... */ or $1, \rs, zero .word INSERT_D_MSA_INSN | (\n << 16) | (\wd << 6)
@@ -381,6 +396,7 @@ st_d 31, THREAD_FPR31, \thread .set push .set noat + SET_HARDFLOAT cfcmsa $1, MSA_CSR sw $1, THREAD_MSA_CSR(\thread) .set pop
@@ -389,6 +405,7 @@ .macro msa_restore_all thread .set push .set noat +SET_HARDFLOAT lw $1, THREAD_MSA_CSR(\thread) ctcmsa MSA_CSR, $1 .set pop
@@ -441,6 +458,7 @@ .macro msa_init_all_upper .set push .set noat + SET_HARDFLOAT not $1, zero msa_init_upper 0 .set pop
arch/mips/include/asm/fpregdef.h +14 -0
@@ -14,6 +14,20 @@#include <asm/sgidefs.h> +/* +* starting with binutils 2.24.51.20140729, MIPS binutils warn about mixing +* hardfloat and softfloat object files. The kernel build uses soft-float by +* default, so we also need to pass -msoft-float along to GAS if it supports it. +* But this in turn causes assembler errors in files which access hardfloat +* registers. We detect if GAS supports "-msoft-float" in the Makefile and +* explicitly put ".set hardfloat" where floating point registers are touched. +*/ +#ifdef GAS_HAS_SET_HARDFLOAT +#define SET_HARDFLOAT .set hardfloat +#else +#define SET_HARDFLOAT +#endif +#if _MIPS_SIM == _MIPS_SIM_ABI32/*
arch/mips/include/asm/fpu.h +2 -2
@@ -145,8 +145,8 @@ static inline void lose_fpu(int save)if (is_msa_enabled ()) {if (save) {save_msa (current); - asmvolatile ("cfc1 %0, $31" - :"=r" (current->thread.fpu.fcr31)); + current->thread.fpu.fcr31 = +read_32bit_cp1_register (CP1_STATUS ); }disable_msa ();clear_thread_flag (TIF_USEDMSA );
arch/mips/include/asm/mipsregs.h +10 -1
@@ -1324,7 +1324,7 @@ do { \/* * Macros to access the floating point coprocessor control registers */ -#define read_32bit_cp1_register (source) \ +#define _read_32bit_cp1_register (source, gas_hardfloat) \ ({ \ int __res; \ \
@@ -1334,12 +1334,21 @@ do { \" # gas fails to assemble cfc1 for some archs, \n" \" # like Octeon. \n" \" .set mips1 \n" \ + " "STR(gas_hardfloat)" \n" \ " cfc1 %0,"STR(source)" \n" \ " .set pop \n" \ : "=r" (__res)); \ __res; \ }) +#ifdef GAS_HAS_SET_HARDFLOAT +#define read_32bit_cp1_register (source) \ + _read_32bit_cp1_register(source, .set hardfloat) +#else +#define read_32bit_cp1_register (source) \ + _read_32bit_cp1_register(source, ) +#endif +#ifdef HAVE_AS_DSP #define rddsp (mask) \ ({ \
arch/mips/kernel/branch.c +2 -6
@@ -144,7 +144,7 @@ int __mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,case mm_bc1t_op:preempt_disable ();if (is_fpu_owner ()) - asmvolatile ("cfc1\t%0,$31" :"=r" (fcr31)); + fcr31 =read_32bit_cp1_register (CP1_STATUS );else fcr31 = current->thread.fpu.fcr31;preempt_enable ();
@@ -562,11 +562,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,case cop1_op:preempt_disable ();if (is_fpu_owner ()) - asmvolatile ( -".set push\n" -"\t.set mips1\n" -"\tcfc1\t%0,$31\n" -"\t.set pop" :"=r" (fcr31)); + fcr31 =read_32bit_cp1_register (CP1_STATUS );else fcr31 = current->thread.fpu.fcr31;preempt_enable ();
arch/mips/kernel/genex.S +1 -0
@@ -358,6 +358,7 @@ NESTED(nmi_handler, PT_SIZE, sp) .set push /* gas fails to assemble cfc1 for some archs (octeon).*/ \ .set mips1 + SET_HARDFLOAT cfc1 a1, fcr31 li a2, ~(0x3f << 12) and a2, a1
arch/mips/kernel/r2300_fpu.S +6 -0
@@ -28,6 +28,8 @@ .set mips1 /* Save floating point context */ LEAF(_save_fp_context) + .set push + SET_HARDFLOAT li v0, 0 # assume success cfc1 t1,fcr31 EX(swc1 $f0,(SC_FPREGS+0)(a0))
@@ -65,6 +67,7 @@ LEAF(_save_fp_context) EX(sw t1,(SC_FPC_CSR)(a0)) cfc1 t0,$0 # implementation/version jr ra + .set pop .set nomacro EX(sw t0,(SC_FPC_EIR)(a0)) .set macro
@@ -80,6 +83,8 @@ LEAF(_save_fp_context) * stack frame which might have been changed by the user. */ LEAF(_restore_fp_context) + .set push + SET_HARDFLOAT li v0, 0 # assume success EX(lw t0,(SC_FPC_CSR)(a0)) EX(lwc1 $f0,(SC_FPREGS+0)(a0))
@@ -116,6 +121,7 @@ LEAF(_restore_fp_context) EX(lwc1 $f31,(SC_FPREGS+248)(a0)) jr ra ctc1 t0,fcr31 + .set pop END(_restore_fp_context) .set reorder
arch/mips/kernel/r2300_switch.S +5 -0
@@ -120,6 +120,9 @@ LEAF(_restore_fp) #define FPU_DEFAULT 0x00000000 + .set push + SET_HARDFLOAT + LEAF(_init_fpu) mfc0 t0, CP0_STATUS li t1, ST0_CU1
@@ -165,3 +168,5 @@ LEAF(_init_fpu) mtc1 t0, $f31 jr ra END(_init_fpu) + + .set pop
arch/mips/kernel/r4k_fpu.S +18 -0
@@ -21,6 +21,7 @@ .macro EX insn, reg, src .set push + SET_HARDFLOAT .set nomacro .ex\@: \insn \reg, \src .set pop
@@ -33,10 +34,14 @@ .set arch=r4000 LEAF(_save_fp_context) + .set push + SET_HARDFLOAT cfc1 t1, fcr31 + .set pop #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) .set push + SET_HARDFLOAT #ifdef CONFIG_CPU_MIPS32_R2 .set mips64r2 mfc0 t0, CP0_STATUS
@@ -64,6 +69,8 @@ LEAF(_save_fp_context) 1: .set pop #endif + .set push + SET_HARDFLOAT /* Store the 16 even double precision registers */ EX sdc1 $f0, SC_FPREGS+0(a0) EX sdc1 $f2, SC_FPREGS+16(a0)
@@ -84,11 +91,14 @@ LEAF(_save_fp_context) EX sw t1, SC_FPC_CSR(a0) jr ra li v0, 0 # success + .set pop END(_save_fp_context) #ifdef CONFIG_MIPS32_COMPAT /* Save 32-bit process floating point context */ LEAF(_save_fp_context32) + .set push + SET_HARDFLOAT cfc1 t1, fcr31 mfc0 t0, CP0_STATUS
@@ -134,6 +144,7 @@ LEAF(_save_fp_context32) EX sw t1, SC32_FPC_CSR(a0) cfc1 t0, $0 # implementation/version EX sw t0, SC32_FPC_EIR(a0) + .set pop jr ra li v0, 0 # success
@@ -150,6 +161,7 @@ LEAF(_restore_fp_context) #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) .set push + SET_HARDFLOAT #ifdef CONFIG_CPU_MIPS32_R2 .set mips64r2 mfc0 t0, CP0_STATUS
@@ -175,6 +187,8 @@ LEAF(_restore_fp_context) EX ldc1 $f31, SC_FPREGS+248(a0) 1: .set pop #endif + .set push + SET_HARDFLOAT EX ldc1 $f0, SC_FPREGS+0(a0) EX ldc1 $f2, SC_FPREGS+16(a0) EX ldc1 $f4, SC_FPREGS+32(a0)
@@ -192,6 +206,7 @@ LEAF(_restore_fp_context) EX ldc1 $f28, SC_FPREGS+224(a0) EX ldc1 $f30, SC_FPREGS+240(a0) ctc1 t1, fcr31 + .set pop jr ra li v0, 0 # success END(_restore_fp_context)
@@ -199,6 +214,8 @@ LEAF(_restore_fp_context) #ifdef CONFIG_MIPS32_COMPAT LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ + .set push + SET_HARDFLOAT EX lw t1, SC32_FPC_CSR(a0) mfc0 t0, CP0_STATUS
@@ -242,6 +259,7 @@ LEAF(_restore_fp_context32) ctc1 t1, fcr31 jr ra li v0, 0 # success + .set pop END(_restore_fp_context32) #endif
arch/mips/kernel/r4k_switch.S +9 -0
@@ -65,8 +65,12 @@ bgtz a3, 1f /* Save 128b MSA vector context + scalar FP control & status. */ + .set push + SET_HARDFLOAT cfc1 t1, fcr31 msa_save_all a0 + .set pop /* SET_HARDFLOAT */ + sw t1, THREAD_FCR31(a0) b 2f
@@ -161,6 +165,9 @@ LEAF(_init_msa_upper) #define FPU_DEFAULT 0x00000000 + .set push + SET_HARDFLOAT + LEAF(_init_fpu) mfc0 t0, CP0_STATUS li t1, ST0_CU1
@@ -291,3 +298,5 @@ LEAF(_init_fpu) #endif jr ra END(_init_fpu) + + .set pop /* SET_HARDFLOAT */
arch/mips/kernel/r6000_fpu.S +5 -0
@@ -18,6 +18,9 @@ .set noreorder .set mips2 + .set push + SET_HARDFLOAT + /* Save floating point context */ LEAF(_save_fp_context) mfc0 t0,CP0_STATUS
@@ -85,3 +88,5 @@ 1: jr ra nop END(_restore_fp_context) + + .set pop /* SET_HARDFLOAT */
Signature · 1 line
2.1.2
Hi Manuel,
Sorry for taking a while to respond to you, from a toolchain perspective I think this patch is looking good with one extra change as below. I'll leave the kernel guys to comment further.
Quoted 8 lines · Manuel Lauss
arch/mips/kernel/r4k_fpu.S +0
-0@@ -33,10 +34,14 @@ .set arch=r4000 LEAF(_save_fp_context)
arch/mips/kernel/r4k_fpu.S line 46
Quoted 10 lines
arch/mips/kernel/r4k_fpu.S +4
-0+ .set push + SET_HARDFLOAT cfc1 t1, fcr31 + .set pop #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) .set push + SET_HARDFLOAT #ifdef CONFIG_CPU_MIPS32_R2 .set mips64r2
I know you haven't modified the lines with .set mips64r2 on them but they are not strictly correct.
Instead of mips64r2 (which is dangerous to put in 32-bit code for a variety of reasons unless absolutely critical)... this should be:
.set mips32r2
.set fp=64
There should be no need to protect this change based on assembler version as I believe .set fp=... support predates .set mips64r2. This change protects the kernel source from failing to build depending on how future toolchains are configured and it would be ideal to include in this patch to keep all these tweaks in one place.
For the record the issue is that .set mips64r2 is getting used with the O32 ABI which is OK albeit weird. Under some circumstances the use of .set mips64r2 will result in implicitly setting fp=64 which is required for the SDC1 instructions which follow, however it will not always set fp=64. Markos has a set of tools which are configured such that .set mips64r2 used with an O32 ABI will not switch to 64-bit FP registers which is the reason he has seen a problem which you can't reproduce.
arch/mips/kernel/r4k_fpu.S LEAF(_restore_fp_context) · line 166
Quoted 7 lines
arch/mips/kernel/r4k_fpu.S +1
-0@@ -150,6 +161,7 @@ LEAF(_restore_fp_context) #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) .set push + SET_HARDFLOAT #ifdef CONFIG_CPU_MIPS32_R2 .set mips64r2
Likewise.
Thanks,
Matthew