mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-13 23:00:22 +00:00
1999-07-27 Mark Kettenis <kettenis@gnu.org>
* sysdeps/mach/hurd/i386/init-first.c (init): Move the inline assembler code to switch stacks and call init1 outside this function. Inside `init' the code was optimized away by gcc 2.95 since it was "clearly" unreachable. * sysdeps/mach/hurd/i386/trampoline.c (_hurd_setup_sighandler): Do something similar for the trampoline code.
This commit is contained in:
parent
a3dd87b380
commit
68a743d253
@ -1,5 +1,5 @@
|
|||||||
/* Initialization code run first thing by the ELF startup code. For i386/Hurd.
|
/* Initialization code run first thing by the ELF startup code. For i386/Hurd.
|
||||||
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
Copyright (C) 1995, 96, 97, 98, 99 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -157,6 +157,8 @@ init (int *data)
|
|||||||
void *newsp = (*_cthread_init_routine) ();
|
void *newsp = (*_cthread_init_routine) ();
|
||||||
struct hurd_startup_data *od;
|
struct hurd_startup_data *od;
|
||||||
|
|
||||||
|
void switch_stacks (void);
|
||||||
|
|
||||||
/* Copy per-thread variables from that temporary
|
/* Copy per-thread variables from that temporary
|
||||||
area onto the new cthread stack. */
|
area onto the new cthread stack. */
|
||||||
memcpy (__hurd_threadvar_location_from_sp (0, newsp),
|
memcpy (__hurd_threadvar_location_from_sp (0, newsp),
|
||||||
@ -181,7 +183,7 @@ init (int *data)
|
|||||||
be the return address for `init1'; we will jump there with NEWSP
|
be the return address for `init1'; we will jump there with NEWSP
|
||||||
as the stack pointer. */
|
as the stack pointer. */
|
||||||
*--(int *) newsp = data[-1];
|
*--(int *) newsp = data[-1];
|
||||||
((void **) data)[-1] = &&switch_stacks;
|
((void **) data)[-1] = switch_stacks;
|
||||||
/* Force NEWSP into %ecx and &init1 into %eax, which are not restored
|
/* Force NEWSP into %ecx and &init1 into %eax, which are not restored
|
||||||
by function return. */
|
by function return. */
|
||||||
asm volatile ("# a %0 c %1" : : "a" (newsp), "c" (&init1));
|
asm volatile ("# a %0 c %1" : : "a" (newsp), "c" (&init1));
|
||||||
@ -194,6 +196,8 @@ init (int *data)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
int usercode;
|
int usercode;
|
||||||
|
|
||||||
|
void call_init1 (void);
|
||||||
|
|
||||||
array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
|
array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
|
||||||
if (array == NULL)
|
if (array == NULL)
|
||||||
__libc_fatal ("Can't allocate single-threaded thread variables.");
|
__libc_fatal ("Can't allocate single-threaded thread variables.");
|
||||||
@ -208,34 +212,40 @@ init (int *data)
|
|||||||
/* The argument data is just above the stack frame we will unwind by
|
/* The argument data is just above the stack frame we will unwind by
|
||||||
returning. Mutate our own return address to run the code below. */
|
returning. Mutate our own return address to run the code below. */
|
||||||
usercode = data[-1];
|
usercode = data[-1];
|
||||||
((void **) data)[-1] = &&call_init1;
|
((void **) data)[-1] = call_init1;
|
||||||
/* Force USERCODE into %eax and &init1 into %ecx, which are not
|
/* Force USERCODE into %eax and &init1 into %ecx, which are not
|
||||||
restored by function return. */
|
restored by function return. */
|
||||||
asm volatile ("# a %0 c %1" : : "a" (usercode), "c" (&init1));
|
asm volatile ("# a %0 c %1" : : "a" (usercode), "c" (&init1));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch_stacks:
|
|
||||||
/* Our return address was redirected to here, so at this point our stack
|
|
||||||
is unwound and callers' registers restored. Only %ecx and %eax are
|
|
||||||
call-clobbered and thus still have the values we set just above.
|
|
||||||
Fetch from there the new stack pointer we will run on, and jmp to the
|
|
||||||
run-time address of `init1'; when it returns, it will run the user
|
|
||||||
code with the argument data at the top of the stack. */
|
|
||||||
asm volatile ("movl %eax, %esp; jmp *%ecx");
|
|
||||||
/* NOTREACHED */
|
|
||||||
|
|
||||||
call_init1:
|
|
||||||
/* As in the stack-switching case, at this point our stack is unwound and
|
|
||||||
callers' registers restored, and only %ecx and %eax communicate values
|
|
||||||
from the lines above. In this case we have stashed in %eax the user
|
|
||||||
code return address. Push it on the top of the stack so it acts as
|
|
||||||
init1's return address, and then jump there. */
|
|
||||||
asm volatile ("pushl %eax; jmp *%ecx");
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* These bits of inline assembler used to be located inside `init'.
|
||||||
|
However they were optimized away by gcc 2.95. */
|
||||||
|
|
||||||
|
/* The return address of `init' above, was redirected to here, so at
|
||||||
|
this point our stack is unwound and callers' registers restored.
|
||||||
|
Only %ecx and %eax are call-clobbered and thus still have the
|
||||||
|
values we set just above. Fetch from there the new stack pointer
|
||||||
|
we will run on, and jmp to the run-time address of `init1'; when it
|
||||||
|
returns, it will run the user code with the argument data at the
|
||||||
|
top of the stack. */
|
||||||
|
asm ("
|
||||||
|
switch_stacks:
|
||||||
|
movl %eax, %esp
|
||||||
|
jmp *%ecx
|
||||||
|
");
|
||||||
|
|
||||||
|
/* As in the stack-switching case, at this point our stack is unwound
|
||||||
|
and callers' registers restored, and only %ecx and %eax communicate
|
||||||
|
values from the lines above. In this case we have stashed in %eax
|
||||||
|
the user code return address. Push it on the top of the stack so
|
||||||
|
it acts as init1's return address, and then jump there. */
|
||||||
|
asm ("
|
||||||
|
call_init1:
|
||||||
|
push %eax
|
||||||
|
jmp *%ecx
|
||||||
|
");
|
||||||
|
|
||||||
|
|
||||||
#ifdef PIC
|
#ifdef PIC
|
||||||
/* This function is called to initialize the shared C library.
|
/* This function is called to initialize the shared C library.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Set thread_state for sighandler, and sigcontext to recover. i386 version.
|
/* Set thread_state for sighandler, and sigcontext to recover. i386 version.
|
||||||
Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
Copyright (C) 1994, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -32,7 +32,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
|||||||
volatile int rpc_wait,
|
volatile int rpc_wait,
|
||||||
struct machine_thread_all_state *state)
|
struct machine_thread_all_state *state)
|
||||||
{
|
{
|
||||||
__label__ trampoline, rpc_wait_trampoline, firewall;
|
void trampoline (void);
|
||||||
|
void rpc_wait_trampoline (void);
|
||||||
|
void firewall (void);
|
||||||
extern const void _hurd_intr_rpc_msg_in_trap;
|
extern const void _hurd_intr_rpc_msg_in_trap;
|
||||||
extern const void _hurd_intr_rpc_msg_cx_sp;
|
extern const void _hurd_intr_rpc_msg_cx_sp;
|
||||||
extern const void _hurd_intr_rpc_msg_sp_restored;
|
extern const void _hurd_intr_rpc_msg_sp_restored;
|
||||||
@ -140,7 +142,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
|||||||
stackframe->sigcode = detail->code;
|
stackframe->sigcode = detail->code;
|
||||||
stackframe->scp = stackframe->return_scp = scp = &stackframe->ctx;
|
stackframe->scp = stackframe->return_scp = scp = &stackframe->ctx;
|
||||||
stackframe->sigreturn_addr = &__sigreturn;
|
stackframe->sigreturn_addr = &__sigreturn;
|
||||||
stackframe->sigreturn_returns_here = &&firewall; /* Crash on return. */
|
stackframe->sigreturn_returns_here = firewall; /* Crash on return. */
|
||||||
|
|
||||||
/* Set up the sigcontext from the current state of the thread. */
|
/* Set up the sigcontext from the current state of the thread. */
|
||||||
|
|
||||||
@ -196,7 +198,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
|||||||
|
|
||||||
_hurdsig_end_catch_fault ();
|
_hurdsig_end_catch_fault ();
|
||||||
|
|
||||||
state->basic.eip = (int) &&rpc_wait_trampoline;
|
state->basic.eip = (int) rpc_wait_trampoline;
|
||||||
/* The reply-receiving trampoline code runs initially on the original
|
/* The reply-receiving trampoline code runs initially on the original
|
||||||
user stack. We pass it the signal stack pointer in %ebx. */
|
user stack. We pass it the signal stack pointer in %ebx. */
|
||||||
state->basic.uesp = state->basic.esp; /* Restore mach_msg syscall SP. */
|
state->basic.uesp = state->basic.esp; /* Restore mach_msg syscall SP. */
|
||||||
@ -209,26 +211,26 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state->basic.eip = (int) &&trampoline;
|
state->basic.eip = (int) trampoline;
|
||||||
state->basic.uesp = (int) sigsp;
|
state->basic.uesp = (int) sigsp;
|
||||||
}
|
}
|
||||||
/* We pass the handler function to the trampoline code in %edx. */
|
/* We pass the handler function to the trampoline code in %edx. */
|
||||||
state->basic.edx = (int) handler;
|
state->basic.edx = (int) handler;
|
||||||
|
|
||||||
return scp;
|
return scp;
|
||||||
|
}
|
||||||
|
|
||||||
/* The trampoline code follows. This is not actually executed as part of
|
/* The trampoline code follows. This used to be located inside
|
||||||
this function, it is just convenient to write it that way. */
|
_hurd_setup_sighandler, but was optimized away by gcc 2.95. */
|
||||||
|
|
||||||
rpc_wait_trampoline:
|
asm ("rpc_wait_trampoline:\n");
|
||||||
/* This is the entry point when we have an RPC reply message to receive
|
/* This is the entry point when we have an RPC reply message to receive
|
||||||
before running the handler. The MACH_MSG_SEND bit has already been
|
before running the handler. The MACH_MSG_SEND bit has already been
|
||||||
cleared in the OPTION argument on our stack. The interrupted user
|
cleared in the OPTION argument on our stack. The interrupted user
|
||||||
stack pointer has not been changed, so the system call can find its
|
stack pointer has not been changed, so the system call can find its
|
||||||
arguments; the signal stack pointer is in %ebx. For our convenience,
|
arguments; the signal stack pointer is in %ebx. For our convenience,
|
||||||
%ecx points to the sc_eax member of the sigcontext. */
|
%ecx points to the sc_eax member of the sigcontext. */
|
||||||
asm volatile
|
asm (/* Retry the interrupted mach_msg system call. */
|
||||||
(/* Retry the interrupted mach_msg system call. */
|
|
||||||
"movl $-25, %eax\n" /* mach_msg_trap */
|
"movl $-25, %eax\n" /* mach_msg_trap */
|
||||||
"lcall $7, $0\n"
|
"lcall $7, $0\n"
|
||||||
/* When the sigcontext was saved, %eax was MACH_RCV_INTERRUPTED. But
|
/* When the sigcontext was saved, %eax was MACH_RCV_INTERRUPTED. But
|
||||||
@ -241,7 +243,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
|||||||
/* Switch to the signal stack. */
|
/* Switch to the signal stack. */
|
||||||
"movl %ebx, %esp\n");
|
"movl %ebx, %esp\n");
|
||||||
|
|
||||||
trampoline:
|
asm ("trampoline:\n");
|
||||||
/* Entry point for running the handler normally. The arguments to the
|
/* Entry point for running the handler normally. The arguments to the
|
||||||
handler function are already on the top of the stack:
|
handler function are already on the top of the stack:
|
||||||
|
|
||||||
@ -249,8 +251,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
|||||||
4(%esp) SIGCODE
|
4(%esp) SIGCODE
|
||||||
8(%esp) SCP
|
8(%esp) SCP
|
||||||
*/
|
*/
|
||||||
asm volatile
|
asm ("call *%edx\n" /* Call the handler function. */
|
||||||
("call *%edx\n" /* Call the handler function. */
|
|
||||||
"addl $12, %esp\n" /* Pop its args. */
|
"addl $12, %esp\n" /* Pop its args. */
|
||||||
/* The word at the top of stack is &__sigreturn; following are a dummy
|
/* The word at the top of stack is &__sigreturn; following are a dummy
|
||||||
word to fill the slot for the address for __sigreturn to return to,
|
word to fill the slot for the address for __sigreturn to return to,
|
||||||
@ -258,9 +259,5 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
|
|||||||
__sigreturn (SCP); this call never returns. */
|
__sigreturn (SCP); this call never returns. */
|
||||||
"ret");
|
"ret");
|
||||||
|
|
||||||
firewall:
|
asm ("firewall:\n"
|
||||||
asm volatile ("hlt");
|
"hlt");
|
||||||
|
|
||||||
/* NOTREACHED */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user