summaryrefslogtreecommitdiffstats
path: root/sys/amd64/ia32/ia32_sigtramp.S
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/ia32/ia32_sigtramp.S')
-rw-r--r--sys/amd64/ia32/ia32_sigtramp.S31
1 files changed, 26 insertions, 5 deletions
diff --git a/sys/amd64/ia32/ia32_sigtramp.S b/sys/amd64/ia32/ia32_sigtramp.S
index 710834c..3541988 100644
--- a/sys/amd64/ia32/ia32_sigtramp.S
+++ b/sys/amd64/ia32/ia32_sigtramp.S
@@ -91,8 +91,29 @@ ia32_osigcode:
*/
ALIGN_TEXT
lcall_tramp:
+ .code64
+ /*
+ * There, we are in 64bit mode and need to return to 32bit.
+ * First, convert call frame from 64 to 32 bit format.
+ */
+ pushq %rax
+ movl 16(%rsp),%eax
+ movl %eax,20(%rsp) /* ret %cs */
+ movl 8(%rsp),%eax
+ movl %eax,16(%rsp) /* ret %rip -> %eip */
+ popq %rax
+ addq $8,%rsp
+ /* Now return to 32bit */
+ pushq $0x33 /* _ucode32sel UPL */
+ callq 1f
+1:
+ addq $2f-1b,(%rsp)
+ lretq
+2:
+ /* Back in 32bit mode */
+ .code32
cmpl $SYS_vfork,%eax
- je 2f
+ je 4f
pushl %ebp
movl %esp,%ebp
pushl 0x24(%ebp) /* arg 6 */
@@ -101,19 +122,19 @@ lcall_tramp:
pushl 0x18(%ebp)
pushl 0x14(%ebp)
pushl 0x10(%ebp) /* arg 1 */
- pushl 0xc(%ebp) /* gap */
+ pushl 0xc(%ebp) /* gap */
int $0x80
leavel
-1:
+3:
lretl
-2:
+4:
/*
* vfork handling is special and relies on the libc stub saving
* the return ip in %ecx. If vfork failed, then there is no
* child which can corrupt the frame created by call gate.
*/
int $0x80
- jb 1b
+ jb 3b
addl $8,%esp
jmpl *%ecx
#endif
OpenPOWER on IntegriCloud