xref: /illumos-gate/usr/src/lib/libc/i386/gen/makectxt.c (revision 3e76f9d6851ef6c63217178eb67278ec2809b944)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57257d1b4Sraf  * Common Development and Distribution License (the "License").
67257d1b4Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
237257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307257d1b4Sraf #pragma weak _makecontext = makecontext
317c478bd9Sstevel@tonic-gate 
327257d1b4Sraf #include "lint.h"
337c478bd9Sstevel@tonic-gate #include <stdarg.h>
347c478bd9Sstevel@tonic-gate #include <ucontext.h>
357c478bd9Sstevel@tonic-gate #include <sys/stack.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * The ucontext_t that the user passes in must have been primed with a
397c478bd9Sstevel@tonic-gate  * call to getcontext(2), have the uc_stack member set to reflect the
407c478bd9Sstevel@tonic-gate  * stack which this context will use, and have the uc_link member set
417c478bd9Sstevel@tonic-gate  * to the context which should be resumed when this context returns.
427c478bd9Sstevel@tonic-gate  * When makecontext() returns, the ucontext_t will be set to run the
437c478bd9Sstevel@tonic-gate  * given function with the given parameters on the stack specified by
447c478bd9Sstevel@tonic-gate  * uc_stack, and which will return to the ucontext_t specified by uc_link.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
47ceef08daSJosef 'Jeff' Sipek /*
48ceef08daSJosef 'Jeff' Sipek  * The original i386 ABI said that the stack pointer need be only 4-byte
49ceef08daSJosef 'Jeff' Sipek  * aligned before a function call (STACK_ALIGN == 4).  The ABI supplement
50ceef08daSJosef 'Jeff' Sipek  * version 1.0 changed the required alignment to 16-byte for the benefit of
51ceef08daSJosef 'Jeff' Sipek  * floating point code compiled using sse2.  The compiler assumes this
52ceef08daSJosef 'Jeff' Sipek  * alignment and maintains it for calls it generates.  If the stack is
53ceef08daSJosef 'Jeff' Sipek  * initially properly aligned, it will continue to be so aligned.  If it is
54ceef08daSJosef 'Jeff' Sipek  * not initially so aligned, it will never become so aligned.
55ceef08daSJosef 'Jeff' Sipek  *
56ceef08daSJosef 'Jeff' Sipek  * One slightly confusing detail to keep in mind is that the 16-byte
57ceef08daSJosef 'Jeff' Sipek  * alignment (%esp & 0xf == 0) is true just *before* the call instruction.
58ceef08daSJosef 'Jeff' Sipek  * The call instruction will then push a return value, decrementing %esp by
59ceef08daSJosef 'Jeff' Sipek  * 4.  Therefore, if one dumps %esp at the at the very first instruction in
60ceef08daSJosef 'Jeff' Sipek  * a function, it will end with a 0xc.  The compiler expects this and
61ceef08daSJosef 'Jeff' Sipek  * compensates for it properly.
62ceef08daSJosef 'Jeff' Sipek  *
63ceef08daSJosef 'Jeff' Sipek  * Note: If you change this value, you need to change it in the following
64ceef08daSJosef 'Jeff' Sipek  * files as well:
65ceef08daSJosef 'Jeff' Sipek  *
66ceef08daSJosef 'Jeff' Sipek  *  - lib/libc/i386/threads/machdep.c
67*3e76f9d6SRichard Lowe  *  - lib/crt/i386/crti.s
68*3e76f9d6SRichard Lowe  *  - lib/crt/i386/crt1.s
69ceef08daSJosef 'Jeff' Sipek  */
70ceef08daSJosef 'Jeff' Sipek #undef	STACK_ALIGN
71ceef08daSJosef 'Jeff' Sipek #define	STACK_ALIGN	16
72ceef08daSJosef 'Jeff' Sipek 
737c478bd9Sstevel@tonic-gate static void resumecontext(void);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate void
767c478bd9Sstevel@tonic-gate makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	long *sp;
797c478bd9Sstevel@tonic-gate 	long *tsp;
807c478bd9Sstevel@tonic-gate 	va_list ap;
817c478bd9Sstevel@tonic-gate 	size_t size;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	ucp->uc_mcontext.gregs[EIP] = (greg_t)func;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	size = sizeof (long) * (argc + 1);
867c478bd9Sstevel@tonic-gate 
87ceef08daSJosef 'Jeff' Sipek 	tsp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp +
887c478bd9Sstevel@tonic-gate 	    ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1));
897c478bd9Sstevel@tonic-gate 
90ceef08daSJosef 'Jeff' Sipek 	/*
91ceef08daSJosef 'Jeff' Sipek 	 * Since we're emulating the call instruction, we must push the
92ceef08daSJosef 'Jeff' Sipek 	 * return address (which involves adjusting the stack pointer to
93ceef08daSJosef 'Jeff' Sipek 	 * have the proper 4-byte bias).
94ceef08daSJosef 'Jeff' Sipek 	 */
95ceef08daSJosef 'Jeff' Sipek 	sp = tsp - 1;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	*sp = (long)resumecontext;		/* return address */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	ucp->uc_mcontext.gregs[UESP] = (greg_t)sp;
100ceef08daSJosef 'Jeff' Sipek 
101ceef08daSJosef 'Jeff' Sipek 	/*
102ceef08daSJosef 'Jeff' Sipek 	 * "push" all the arguments
103ceef08daSJosef 'Jeff' Sipek 	 */
104ceef08daSJosef 'Jeff' Sipek 	va_start(ap, argc);
105ceef08daSJosef 'Jeff' Sipek 	while (argc-- > 0)
106ceef08daSJosef 'Jeff' Sipek 		*tsp++ = va_arg(ap, long);
107ceef08daSJosef 'Jeff' Sipek 	va_end(ap);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static void
1127c478bd9Sstevel@tonic-gate resumecontext(void)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate 	ucontext_t uc;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	(void) getcontext(&uc);
1177c478bd9Sstevel@tonic-gate 	(void) setcontext(uc.uc_link);
1187c478bd9Sstevel@tonic-gate }
119