| 1 | /* Create new context. |
| 2 | Copyright (C) 2001-2024 Free Software Foundation, Inc. |
| 3 | This file is part of the GNU C Library. |
| 4 | |
| 5 | The GNU C Library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License as published by the Free Software Foundation; either |
| 8 | version 2.1 of the License, or (at your option) any later version. |
| 9 | |
| 10 | The GNU C Library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with the GNU C Library; if not, see |
| 17 | <https://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | #include <sysdep.h> |
| 20 | |
| 21 | #include "ucontext_i.h" |
| 22 | |
| 23 | |
| 24 | ENTRY(__makecontext) |
| 25 | movl 4(%esp), %eax |
| 26 | |
| 27 | /* Load the address of the function we are supposed to run. */ |
| 28 | movl 8(%esp), %ecx |
| 29 | |
| 30 | /* Compute the address of the stack. The information comes from |
| 31 | to us_stack element. */ |
| 32 | movl oSS_SP(%eax), %edx |
| 33 | movl %ecx, oEIP(%eax) |
| 34 | addl oSS_SIZE(%eax), %edx |
| 35 | |
| 36 | /* Remember the number of parameters for the exit handler since |
| 37 | it has to remove them. We store the number in the EBX register |
| 38 | which the function we will call must preserve. */ |
| 39 | movl 12(%esp), %ecx |
| 40 | movl %ecx, oEBX(%eax) |
| 41 | |
| 42 | /* Make room on the new stack for the parameters. |
| 43 | Room for the arguments, return address (== L(exitcode)) and |
| 44 | oLINK pointer is needed. One of the pointer sizes is subtracted |
| 45 | after aligning the stack. */ |
| 46 | negl %ecx |
| 47 | leal -4(%edx,%ecx,4), %edx |
| 48 | negl %ecx |
| 49 | |
| 50 | /* Align the stack. */ |
| 51 | andl $0xfffffff0, %edx |
| 52 | subl $4, %edx |
| 53 | |
| 54 | /* Store the future stack pointer. */ |
| 55 | movl %edx, oESP(%eax) |
| 56 | |
| 57 | /* Put the next context on the new stack (from the uc_link |
| 58 | element). */ |
| 59 | movl oLINK(%eax), %eax |
| 60 | movl %eax, 4(%edx,%ecx,4) |
| 61 | |
| 62 | /* Copy all the parameters. */ |
| 63 | jecxz 2f |
| 64 | 1: movl 12(%esp,%ecx,4), %eax |
| 65 | movl %eax, (%edx,%ecx,4) |
| 66 | decl %ecx |
| 67 | jnz 1b |
| 68 | 2: |
| 69 | |
| 70 | /* If the function we call returns we must continue with the |
| 71 | context which is given in the uc_link element. To do this |
| 72 | set the return address for the function the user provides |
| 73 | to a little bit of helper code which does the magic (see |
| 74 | below). */ |
| 75 | #ifdef PIC |
| 76 | call 1f |
| 77 | cfi_adjust_cfa_offset (4) |
| 78 | 1: popl %ecx |
| 79 | cfi_adjust_cfa_offset (-4) |
| 80 | addl $L(exitcode)-1b, %ecx |
| 81 | movl %ecx, (%edx) |
| 82 | #else |
| 83 | movl $L(exitcode), (%edx) |
| 84 | #endif |
| 85 | /* We need to terminate the FDE here instead of after ret because |
| 86 | the unwinder looks at ra-1 for unwind information. */ |
| 87 | cfi_endproc |
| 88 | |
| 89 | /* 'makecontext' returns no value. */ |
| 90 | ret |
| 91 | |
| 92 | /* This is the helper code which gets called if a function which |
| 93 | is registered with 'makecontext' returns. In this case we |
| 94 | have to install the context listed in the uc_link element of |
| 95 | the context 'makecontext' manipulated at the time of the |
| 96 | 'makecontext' call. If the pointer is NULL the process must |
| 97 | terminate. */ |
| 98 | L(exitcode): |
| 99 | /* This removes the parameters passed to the function given to |
| 100 | 'makecontext' from the stack. EBX contains the number of |
| 101 | parameters (see above). */ |
| 102 | leal (%esp,%ebx,4), %esp |
| 103 | |
| 104 | cmpl $0, (%esp) /* Check the next context. */ |
| 105 | je 2f /* If it is zero exit. */ |
| 106 | |
| 107 | call HIDDEN_JUMPTARGET(__setcontext) |
| 108 | /* If this returns (which can happen if the syscall fails) we'll |
| 109 | exit the program with the return error value (-1). */ |
| 110 | jmp L(call_exit) |
| 111 | |
| 112 | 2: |
| 113 | /* Exit with status 0. */ |
| 114 | xorl %eax, %eax |
| 115 | |
| 116 | L(call_exit): |
| 117 | /* Align the stack and pass the exit code (from %eax). */ |
| 118 | andl $0xfffffff0, %esp |
| 119 | subl $12, %esp |
| 120 | pushl %eax |
| 121 | |
| 122 | call HIDDEN_JUMPTARGET(exit) |
| 123 | /* The 'exit' call should never return. In case it does cause |
| 124 | the process to terminate. */ |
| 125 | hlt |
| 126 | cfi_startproc |
| 127 | END(__makecontext) |
| 128 | |
| 129 | weak_alias (__makecontext, makecontext) |
| 130 | |