Commit b5d748ca authored by Linus Torvalds's avatar Linus Torvalds

Make x86 semaphore routines use register calling convention.

This avoids a bug where the compiler would overwrite the
stackframe that the caller also considered to be a register
save area.

It also shrinks the code segment by a tiny amount by moving
the failure case argument setup into the slow path. This not
only makes the fast path smaller, but it makes it easier on
gcc (gcc is not very good at generating code that uses fixed
register names).
parent de553d73
...@@ -49,12 +49,12 @@ ...@@ -49,12 +49,12 @@
* we cannot lose wakeup events. * we cannot lose wakeup events.
*/ */
asmlinkage void __up(struct semaphore *sem) fastcall void __up(struct semaphore *sem)
{ {
wake_up(&sem->wait); wake_up(&sem->wait);
} }
asmlinkage void __sched __down(struct semaphore * sem) fastcall void __sched __down(struct semaphore * sem)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk); DECLARE_WAITQUEUE(wait, tsk);
...@@ -91,7 +91,7 @@ asmlinkage void __sched __down(struct semaphore * sem) ...@@ -91,7 +91,7 @@ asmlinkage void __sched __down(struct semaphore * sem)
tsk->state = TASK_RUNNING; tsk->state = TASK_RUNNING;
} }
asmlinkage int __sched __down_interruptible(struct semaphore * sem) fastcall int __sched __down_interruptible(struct semaphore * sem)
{ {
int retval = 0; int retval = 0;
struct task_struct *tsk = current; struct task_struct *tsk = current;
...@@ -154,7 +154,7 @@ asmlinkage int __sched __down_interruptible(struct semaphore * sem) ...@@ -154,7 +154,7 @@ asmlinkage int __sched __down_interruptible(struct semaphore * sem)
* single "cmpxchg" without failure cases, * single "cmpxchg" without failure cases,
* but then it wouldn't work on a 386. * but then it wouldn't work on a 386.
*/ */
asmlinkage int __down_trylock(struct semaphore * sem) fastcall int __down_trylock(struct semaphore * sem)
{ {
int sleepers; int sleepers;
unsigned long flags; unsigned long flags;
...@@ -183,9 +183,9 @@ asmlinkage int __down_trylock(struct semaphore * sem) ...@@ -183,9 +183,9 @@ asmlinkage int __down_trylock(struct semaphore * sem)
* need to convert that sequence back into the C sequence when * need to convert that sequence back into the C sequence when
* there is contention on the semaphore. * there is contention on the semaphore.
* *
* %ecx contains the semaphore pointer on entry. Save the C-clobbered * %eax contains the semaphore pointer on entry. Save the C-clobbered
* registers (%eax, %edx and %ecx) except %eax when used as a return * registers (%eax, %edx and %ecx) except %eax whish is either a return
* value.. * value or just clobbered..
*/ */
asm( asm(
".section .sched.text\n" ".section .sched.text\n"
...@@ -196,13 +196,11 @@ asm( ...@@ -196,13 +196,11 @@ asm(
"pushl %ebp\n\t" "pushl %ebp\n\t"
"movl %esp,%ebp\n\t" "movl %esp,%ebp\n\t"
#endif #endif
"pushl %eax\n\t"
"pushl %edx\n\t" "pushl %edx\n\t"
"pushl %ecx\n\t" "pushl %ecx\n\t"
"call __down\n\t" "call __down\n\t"
"popl %ecx\n\t" "popl %ecx\n\t"
"popl %edx\n\t" "popl %edx\n\t"
"popl %eax\n\t"
#if defined(CONFIG_FRAME_POINTER) #if defined(CONFIG_FRAME_POINTER)
"movl %ebp,%esp\n\t" "movl %ebp,%esp\n\t"
"popl %ebp\n\t" "popl %ebp\n\t"
...@@ -257,13 +255,11 @@ asm( ...@@ -257,13 +255,11 @@ asm(
".align 4\n" ".align 4\n"
".globl __up_wakeup\n" ".globl __up_wakeup\n"
"__up_wakeup:\n\t" "__up_wakeup:\n\t"
"pushl %eax\n\t"
"pushl %edx\n\t" "pushl %edx\n\t"
"pushl %ecx\n\t" "pushl %ecx\n\t"
"call __up\n\t" "call __up\n\t"
"popl %ecx\n\t" "popl %ecx\n\t"
"popl %edx\n\t" "popl %edx\n\t"
"popl %eax\n\t"
"ret" "ret"
); );
......
...@@ -87,15 +87,15 @@ static inline void init_MUTEX_LOCKED (struct semaphore *sem) ...@@ -87,15 +87,15 @@ static inline void init_MUTEX_LOCKED (struct semaphore *sem)
sema_init(sem, 0); sema_init(sem, 0);
} }
asmlinkage void __down_failed(void /* special register calling convention */); fastcall void __down_failed(void /* special register calling convention */);
asmlinkage int __down_failed_interruptible(void /* params in registers */); fastcall int __down_failed_interruptible(void /* params in registers */);
asmlinkage int __down_failed_trylock(void /* params in registers */); fastcall int __down_failed_trylock(void /* params in registers */);
asmlinkage void __up_wakeup(void /* special register calling convention */); fastcall void __up_wakeup(void /* special register calling convention */);
asmlinkage void __down(struct semaphore * sem); fastcall void __down(struct semaphore * sem);
asmlinkage int __down_interruptible(struct semaphore * sem); fastcall int __down_interruptible(struct semaphore * sem);
asmlinkage int __down_trylock(struct semaphore * sem); fastcall int __down_trylock(struct semaphore * sem);
asmlinkage void __up(struct semaphore * sem); fastcall void __up(struct semaphore * sem);
/* /*
* This is ugly, but we want the default case to fall through. * This is ugly, but we want the default case to fall through.
...@@ -111,12 +111,13 @@ static inline void down(struct semaphore * sem) ...@@ -111,12 +111,13 @@ static inline void down(struct semaphore * sem)
"js 2f\n" "js 2f\n"
"1:\n" "1:\n"
LOCK_SECTION_START("") LOCK_SECTION_START("")
"2:\tcall __down_failed\n\t" "2:\tlea %0,%%eax\n\t"
"call __down_failed\n\t"
"jmp 1b\n" "jmp 1b\n"
LOCK_SECTION_END LOCK_SECTION_END
:"=m" (sem->count) :"=m" (sem->count)
:"c" (sem) :
:"memory"); :"memory","ax");
} }
/* /*
...@@ -135,11 +136,12 @@ static inline int down_interruptible(struct semaphore * sem) ...@@ -135,11 +136,12 @@ static inline int down_interruptible(struct semaphore * sem)
"xorl %0,%0\n" "xorl %0,%0\n"
"1:\n" "1:\n"
LOCK_SECTION_START("") LOCK_SECTION_START("")
"2:\tcall __down_failed_interruptible\n\t" "2:\tlea %1,%%eax\n\t"
"call __down_failed_interruptible\n\t"
"jmp 1b\n" "jmp 1b\n"
LOCK_SECTION_END LOCK_SECTION_END
:"=a" (result), "=m" (sem->count) :"=a" (result), "=m" (sem->count)
:"c" (sem) :
:"memory"); :"memory");
return result; return result;
} }
...@@ -159,11 +161,12 @@ static inline int down_trylock(struct semaphore * sem) ...@@ -159,11 +161,12 @@ static inline int down_trylock(struct semaphore * sem)
"xorl %0,%0\n" "xorl %0,%0\n"
"1:\n" "1:\n"
LOCK_SECTION_START("") LOCK_SECTION_START("")
"2:\tcall __down_failed_trylock\n\t" "2:\tlea %1,%%eax\n\t"
"call __down_failed_trylock\n\t"
"jmp 1b\n" "jmp 1b\n"
LOCK_SECTION_END LOCK_SECTION_END
:"=a" (result), "=m" (sem->count) :"=a" (result), "=m" (sem->count)
:"c" (sem) :
:"memory"); :"memory");
return result; return result;
} }
...@@ -182,13 +185,14 @@ static inline void up(struct semaphore * sem) ...@@ -182,13 +185,14 @@ static inline void up(struct semaphore * sem)
"jle 2f\n" "jle 2f\n"
"1:\n" "1:\n"
LOCK_SECTION_START("") LOCK_SECTION_START("")
"2:\tcall __up_wakeup\n\t" "2:\tlea %0,%%eax\n\t"
"call __up_wakeup\n\t"
"jmp 1b\n" "jmp 1b\n"
LOCK_SECTION_END LOCK_SECTION_END
".subsection 0\n" ".subsection 0\n"
:"=m" (sem->count) :"=m" (sem->count)
:"c" (sem) :
:"memory"); :"memory","ax");
} }
#endif #endif
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
extra \ extra \
".ifndef " LOCK_SECTION_NAME "\n\t" \ ".ifndef " LOCK_SECTION_NAME "\n\t" \
LOCK_SECTION_NAME ":\n\t" \ LOCK_SECTION_NAME ":\n\t" \
".endif\n\t" ".endif\n"
#define LOCK_SECTION_END \ #define LOCK_SECTION_END \
".previous\n\t" ".previous\n\t"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment