From 877b02be0823cf9227e33ef1a2e227680fa3b275 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sat, 18 Jul 2015 12:35:23 +0200 Subject: [PATCH] Rearrange makecontext and add lots of comments * exceptions.cc (makecontext): Rearrange order of initialization and document at great length. Signed-off-by: Corinna Vinschen --- winsup/cygwin/ChangeLog | 5 ++++ winsup/cygwin/exceptions.cc | 49 ++++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index eb89f6745..7b54e10d0 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,8 @@ +2015-07-17 Corinna Vinschen + + * exceptions.cc (makecontext): Rearrange order of initialization and + document at great length. + 2015-07-17 Corinna Vinschen * exceptions.cc (__unwind_single_frame): Define empty macro on i686. diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index d69dbf799..0025be6b1 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -2030,22 +2030,31 @@ makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) uintptr_t *sp; va_list ap; - sp = (uintptr_t *) ((uintptr_t) ucp->uc_stack.ss_sp - + ucp->uc_stack.ss_size); + /* Initialize sp to the top of the stack. */ + sp = (uintptr_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); + /* Subtract slots required for arguments and the pointer to uc_link. */ sp -= (argc + 1); + /* Align. */ sp = (uintptr_t *) ((uintptr_t) sp & ~0xf); + /* Subtract one slot for setting the return address. */ --sp; + /* Set return address to the trampolin function __cont_link_context. */ sp[0] = (uintptr_t) __cont_link_context; - sp[argc + 1] = (uintptr_t) ucp->uc_link; -#ifdef __x86_64__ - ucp->uc_mcontext.rip = (uint64_t) func; - ucp->uc_mcontext.rbx = (uint64_t) (sp + argc + 1); - ucp->uc_mcontext.rsp = (uint64_t) sp; -#else - ucp->uc_mcontext.eip = (uint32_t) func; - ucp->uc_mcontext.ebx = (uint32_t) (sp + argc + 1); - ucp->uc_mcontext.esp = (uint32_t) sp; -#endif + /* Fetch arguments and store them on the stack. + + x86_64 only: + + - Store first four args in the AMD64 ABI arg registers. + + - Note that the stack is not short by these four register args. The + reason is the shadow space for these regs required by the AMD64 ABI. + + - The definition of makecontext only allows for "int" sized arguments to + func, 32 bit, likely for historical reasons. However, the argument + slots on x86_64 are 64 bit anyway, so we can fetch and store the args + as 64 bit values, and func can request 64 bit args without violating + the definition. This potentially allows porting 32 bit applications + providing pointer values to func without additional porting effort. */ va_start (ap, argc); for (int i = 0; i < argc; ++i) #ifdef __x86_64__ @@ -2071,4 +2080,20 @@ makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) sp[i + 1] = va_arg (ap, uintptr_t); #endif va_end (ap); + /* Store pointer to uc_link at the top of the stack. */ + sp[argc + 1] = (uintptr_t) ucp->uc_link; + /* Last but not least set the register in the context at ucp so that a + subsequent setcontext or swapcontext picks up the right values: + - Set rip/eip to the target function. + - Set rsp/esp to the just computed stack pointer value. + - Set rbx/ebx to the address of the pointer to uc_link. */ +#ifdef __x86_64__ + ucp->uc_mcontext.rip = (uint64_t) func; + ucp->uc_mcontext.rsp = (uint64_t) sp; + ucp->uc_mcontext.rbx = (uint64_t) (sp + argc + 1); +#else + ucp->uc_mcontext.eip = (uint32_t) func; + ucp->uc_mcontext.esp = (uint32_t) sp; + ucp->uc_mcontext.ebx = (uint32_t) (sp + argc + 1); +#endif }