diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2006-02-10 01:31:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-02-14 19:13:24 +0000 |
commit | 3218357c94af92478ef39163163a81e654385320 (patch) | |
tree | 459be556900bb4a78d93e0185d49df8ed8a7aff4 /include/asm-mips/uaccess.h | |
parent | 41700e73995d6c814932cb55e12525bd34be1ca5 (diff) |
[MIPS] More uaccess.h fixes with gcc >= 4.0.1.
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>
Diffstat (limited to 'include/asm-mips/uaccess.h')
-rw-r--r-- | include/asm-mips/uaccess.h | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index 91d813a37823..7a553e9d44d3 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -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; \ } /* |