diff options
author | das <das@FreeBSD.org> | 2008-06-28 17:55:43 +0000 |
---|---|---|
committer | das <das@FreeBSD.org> | 2008-06-28 17:55:43 +0000 |
commit | 610bd747b7bcb7c261f797b98f48478d9994781e (patch) | |
tree | 50753ee5022fdb7c1e8a537550b00e2c80532b21 /lib/libc/amd64 | |
parent | 8f779d35ce6bfd2d82fb53ce57f2cb1161c87507 (diff) | |
download | FreeBSD-src-610bd747b7bcb7c261f797b98f48478d9994781e.zip FreeBSD-src-610bd747b7bcb7c261f797b98f48478d9994781e.tar.gz |
Two FP-related setjmp/longjmp changes:
1. Save and restore the control part of the MXCSR in addition to the
i387 control word to ensure that the two are consistent.
Note that standards don't require longjmp to restore either control
word, and none of Linux, MacOS X 10.3 and earlier, NetBSD, OpenBSD,
or Solaris do it. However, it is historical FreeBSD behavior, and
bde points out that it is needed to make longjmping out of a signal
handler work properly, given the way FreeBSD clobbers the FPU state
on signal handler entry.
2. Don't clobber the FPU exception flags in longjmp. C99 requires them
to remain unchanged.
Diffstat (limited to 'lib/libc/amd64')
-rw-r--r-- | lib/libc/amd64/gen/_setjmp.S | 11 | ||||
-rw-r--r-- | lib/libc/amd64/gen/setjmp.S | 11 |
2 files changed, 20 insertions, 2 deletions
diff --git a/lib/libc/amd64/gen/_setjmp.S b/lib/libc/amd64/gen/_setjmp.S index 3998fbe..5d57f88 100644 --- a/lib/libc/amd64/gen/_setjmp.S +++ b/lib/libc/amd64/gen/_setjmp.S @@ -58,6 +58,7 @@ ENTRY(_setjmp) movq %r14,48(%rax) /* 6; r14 */ movq %r15,56(%rax) /* 7; r15 */ fnstcw 64(%rax) /* 8; fpu cw */ + stmxcsr 68(%rax) /* and mxcsr */ xorq %rax,%rax ret @@ -65,6 +66,15 @@ ENTRY(_setjmp) .set CNAME(_longjmp),CNAME(___longjmp) ENTRY(___longjmp) movq %rdi,%rdx + /* Restore the mxcsr, but leave exception flags intact. */ + stmxcsr -4(%rsp) + movl 68(%rdx),%eax + andl $0xffffffc0,%eax + movl -4(%rsp),%edi + andl $0x3f,%edi + xorl %eax,%edi + movl %edi,-4(%rsp) + ldmxcsr -4(%rsp) movq %rsi,%rax /* retval */ movq 0(%rdx),%rcx movq 8(%rdx),%rbx @@ -74,7 +84,6 @@ ENTRY(___longjmp) movq 40(%rdx),%r13 movq 48(%rdx),%r14 movq 56(%rdx),%r15 - fninit fldcw 64(%rdx) testq %rax,%rax jnz 1f diff --git a/lib/libc/amd64/gen/setjmp.S b/lib/libc/amd64/gen/setjmp.S index 7d11384..995c801 100644 --- a/lib/libc/amd64/gen/setjmp.S +++ b/lib/libc/amd64/gen/setjmp.S @@ -67,6 +67,7 @@ ENTRY(setjmp) movq %r14,48(%rcx) /* 6; r14 */ movq %r15,56(%rcx) /* 7; r15 */ fnstcw 64(%rcx) /* 8; fpu cw */ + stmxcsr 68(%rcx) /* and mxcsr */ xorq %rax,%rax ret @@ -83,6 +84,15 @@ ENTRY(__longjmp) popq %rsi popq %rdi /* jmpbuf */ movq %rdi,%rdx + /* Restore the mxcsr, but leave exception flags intact. */ + stmxcsr -4(%rsp) + movl 68(%rdx),%eax + andl $0xffffffc0,%eax + movl -4(%rsp),%edi + andl $0x3f,%edi + xorl %eax,%edi + movl %edi,-4(%rsp) + ldmxcsr -4(%rsp) movq %rsi,%rax /* retval */ movq 0(%rdx),%rcx movq 8(%rdx),%rbx @@ -92,7 +102,6 @@ ENTRY(__longjmp) movq 40(%rdx),%r13 movq 48(%rdx),%r14 movq 56(%rdx),%r15 - fninit fldcw 64(%rdx) testq %rax,%rax jnz 1f |