Blame sysdeps/unix/sysv/linux/i386/makecontext.S

Packit 6c4009
/* Create new context.
Packit 6c4009
   Copyright (C) 2001-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
Packit 6c4009
#include "ucontext_i.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
ENTRY(__makecontext)
Packit 6c4009
	movl	4(%esp), %eax
Packit 6c4009
Packit 6c4009
	/* Load the address of the function we are supposed to run.  */
Packit 6c4009
	movl	8(%esp), %ecx
Packit 6c4009
Packit 6c4009
	/* Compute the address of the stack.  The information comes from
Packit 6c4009
	   to us_stack element.  */
Packit 6c4009
	movl	oSS_SP(%eax), %edx
Packit 6c4009
	movl	%ecx, oEIP(%eax)
Packit 6c4009
	addl	oSS_SIZE(%eax), %edx
Packit 6c4009
Packit 6c4009
	/* Remember the number of parameters for the exit handler since
Packit 6c4009
	   it has to remove them.  We store the number in the EBX register
Packit 6c4009
	   which the function we will call must preserve.  */
Packit 6c4009
	movl	12(%esp), %ecx
Packit 6c4009
	movl	%ecx, oEBX(%eax)
Packit 6c4009
Packit 6c4009
	/* Make room on the new stack for the parameters.
Packit 6c4009
	   Room for the arguments, return address (== L(exitcode)) and
Packit 6c4009
	   oLINK pointer is needed.  One of the pointer sizes is subtracted
Packit 6c4009
	   after aligning the stack.  */
Packit 6c4009
	negl	%ecx
Packit 6c4009
	leal	-4(%edx,%ecx,4), %edx
Packit 6c4009
	negl	%ecx
Packit 6c4009
Packit 6c4009
	/* Align the stack.  */
Packit 6c4009
	andl	$0xfffffff0, %edx
Packit 6c4009
	subl	$4, %edx
Packit 6c4009
Packit 6c4009
	/* Store the future stack pointer.  */
Packit 6c4009
	movl	%edx, oESP(%eax)
Packit 6c4009
Packit 6c4009
	/* Put the next context on the new stack (from the uc_link
Packit 6c4009
	   element).  */
Packit 6c4009
	movl	oLINK(%eax), %eax
Packit 6c4009
	movl	%eax, 4(%edx,%ecx,4)
Packit 6c4009
Packit 6c4009
	/* Copy all the parameters.  */
Packit 6c4009
	jecxz	2f
Packit 6c4009
1:	movl	12(%esp,%ecx,4), %eax
Packit 6c4009
	movl	%eax, (%edx,%ecx,4)
Packit 6c4009
	decl	%ecx
Packit 6c4009
	jnz	1b
Packit 6c4009
2:
Packit 6c4009
Packit 6c4009
	/* If the function we call returns we must continue with the
Packit 6c4009
	   context which is given in the uc_link element.  To do this
Packit 6c4009
	   set the return address for the function the user provides
Packit 6c4009
	   to a little bit of helper code which does the magic (see
Packit 6c4009
	   below).  */
Packit 6c4009
#ifdef PIC
Packit 6c4009
	call	1f
Packit 6c4009
	cfi_adjust_cfa_offset (4)
Packit 6c4009
1:	popl	%ecx
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	addl	$L(exitcode)-1b, %ecx
Packit 6c4009
	movl	%ecx, (%edx)
Packit 6c4009
#else
Packit 6c4009
	movl	$L(exitcode), (%edx)
Packit 6c4009
#endif
Packit 6c4009
	/* We need to terminate the FDE here instead of after ret because
Packit 6c4009
	   the unwinder looks at ra-1 for unwind information.  */
Packit 6c4009
	cfi_endproc
Packit 6c4009
Packit 6c4009
	/* 'makecontext' returns no value.  */
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	/* This is the helper code which gets called if a function which
Packit 6c4009
	   is registered with 'makecontext' returns.  In this case we
Packit 6c4009
	   have to install the context listed in the uc_link element of
Packit 6c4009
	   the context 'makecontext' manipulated at the time of the
Packit 6c4009
	   'makecontext' call.  If the pointer is NULL the process must
Packit 6c4009
	   terminate.  */
Packit 6c4009
L(exitcode):
Packit 6c4009
	/* This removes the parameters passed to the function given to
Packit 6c4009
	   'makecontext' from the stack.  EBX contains the number of
Packit 6c4009
	   parameters (see above).  */
Packit 6c4009
	leal	(%esp,%ebx,4), %esp
Packit 6c4009
Packit 6c4009
	cmpl	$0, (%esp)		/* Check the next context.  */
Packit 6c4009
	je	2f			/* If it is zero exit.  */
Packit 6c4009
Packit 6c4009
	call	HIDDEN_JUMPTARGET(__setcontext)
Packit 6c4009
	/* If this returns (which can happen if the syscall fails) we'll
Packit 6c4009
	   exit the program with the return error value (-1).  */
Packit 6c4009
	jmp L(call_exit)
Packit 6c4009
Packit 6c4009
2:
Packit 6c4009
	/* Exit with status 0.  */
Packit 6c4009
	xorl	%eax, %eax
Packit 6c4009
Packit 6c4009
L(call_exit):
Packit 6c4009
	/* Align the stack and pass the exit code (from %eax).  */
Packit 6c4009
	andl	$0xfffffff0, %esp
Packit 6c4009
	subl	$12, %esp
Packit 6c4009
	pushl	%eax
Packit 6c4009
Packit 6c4009
	call	HIDDEN_JUMPTARGET(exit)
Packit 6c4009
	/* The 'exit' call should never return.  In case it does cause
Packit 6c4009
	   the process to terminate.  */
Packit 6c4009
	hlt
Packit 6c4009
	cfi_startproc
Packit 6c4009
END(__makecontext)
Packit 6c4009
Packit 6c4009
weak_alias (__makecontext, makecontext)