[MIPS] More uaccess.h fixes with gcc >= 4.0.1.
authorRalf Baechle <ralf@linux-mips.org>
Fri, 10 Feb 2006 01:31:24 +0000 (01:31 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Tue, 14 Feb 2006 19:13:24 +0000 (19:13 +0000)
From Richard Sandiford <richard@codesourcery.com>:

This patch caused a miscompilation of the restore_gp_regs() block
in restore_sigcontext().  This was in a 32-bit kernel compiled with
GCC CVS head.

restore_gp_regs() copies 64-bit user fields into 32-bit variables,
and in this combination, the new __get_user_asm_ll32() clobbers too
many registers.  It says:

/*
 * Get a long long 64 using 32 bit registers.
 */
{ \
__asm__ __volatile__( \
"1: lw %1, (%3) \n" \
"2: lw %D1, 4(%3) \n" \
" move %0, $0 \n" \
"3: .section .fixup,\"ax\" \n" \
"4: li %0, %4 \n" \
" move %1, $0 \n" \
" move %D1, $0 \n" \
" j 3b \n" \
" .previous \n" \
" .section __ex_table,\"a\" \n" \
" " __UA_ADDR " 1b, 4b \n" \
" " __UA_ADDR " 2b, 4b \n" \
" .previous \n" \
: "=r" (__gu_err), "=&r" (val) \
: "0" (0), "r" (addr), "i" (-EFAULT)); \
}

and this requires val (%1) to be a 64-bit value.  In the case I saw,
gcc was using $3 for the 32-bit val, and wasn't expecting $4 to be
clobbered.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
include/asm-mips/uaccess.h

index 91d813a..7a553e9 100644 (file)
@@ -266,6 +266,8 @@ do {                                                                        \
  */
 #define __get_user_asm_ll32(val, addr)                                 \
 {                                                                      \
+        unsigned long long __gu_tmp;                                   \
+                                                                       \
        __asm__ __volatile__(                                           \
        "1:     lw      %1, (%3)                                \n"     \
        "2:     lw      %D1, 4(%3)                              \n"     \
@@ -280,8 +282,9 @@ do {                                                                        \
        "       " __UA_ADDR "   1b, 4b                          \n"     \
        "       " __UA_ADDR "   2b, 4b                          \n"     \
        "       .previous                                       \n"     \
-       : "=r" (__gu_err), "=&r" (val)                                  \
+       : "=r" (__gu_err), "=&r" (__gu_tmp)                             \
        : "0" (0), "r" (addr), "i" (-EFAULT));                          \
+       (val) = __gu_tmp;                                               \
 }
 
 /*