From ca2c58dc87aed527aea5e80d39a72c95e537f41c Mon Sep 17 00:00:00 2001
From: Kevin B Kenny <kennykb@acm.org>
Date: Thu, 23 Jun 2005 19:48:26 +0000
Subject: bug 1225957

---
 ChangeLog        |   9 +-
 win/tclWinChan.c | 202 ++++++++++++++--------------
 win/tclWinFCmd.c | 396 ++++++++++++++++++++++++++-----------------------------
 3 files changed, 294 insertions(+), 313 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 3d243af..f3630d3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2005-06-23  Kevin Kenny  <kennykb@acm.org>
+
+	* win/tclWinChan.c: More rewriting of __asm__ blocks that
+	* win/tclWinFCmd.c: implement SEH in GCC, because mingw's
+	gcc 3.4.2 is not as forgiving of violations committed by
+	the old code and caused panics. [Bug #1225957]
+	
 2005-06-23  Daniel Steffen  <das@users.sourceforge.net>
 
 	* tools/tcltk-man2html.tcl: fixed useversion glob pattern to accept
@@ -5,7 +12,7 @@
 	
 2005-06-22  Don Porter  <dgp@users.sourceforge.net>
 
-        * win/tclWinFile.c:     Potential buffer overflow.  [Bug 1225571]
+	* win/tclWinFile.c: Potential buffer overflow.  [Bug 1225571]
         Thanks to Pat Thoyts for discovery and fix.
 
 2005-06-22  Kevin Kenny <kennykb@acm.org>
diff --git a/win/tclWinChan.c b/win/tclWinChan.c
index c4ec930..db8b75b 100644
--- a/win/tclWinChan.c
+++ b/win/tclWinChan.c
@@ -9,7 +9,7 @@
  * See the file "license.terms" for information on usage and redistribution
  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  *
- * RCS: @(#) $Id: tclWinChan.c,v 1.42 2005/06/08 14:12:19 dkf Exp $
+ * RCS: @(#) $Id: tclWinChan.c,v 1.43 2005/06/23 19:48:50 kennykb Exp $
  */
 
 #include "tclWinInt.h"
@@ -127,16 +127,24 @@ static Tcl_ChannelType fileChannelType = {
     FileTruncateProc,		/* Truncate proc. */
 };
 
-#if defined(HAVE_NO_SEH) && defined(TCL_MEM_DEBUG)
-static void *INITIAL_ESP, *INITIAL_EBP, *INITIAL_HANDLER;
-static void *RESTORED_ESP, *RESTORED_EBP, *RESTORED_HANDLER;
-#endif /* HAVE_NO_SEH && TCL_MEM_DEBUG */
-
 #ifdef HAVE_NO_SEH
-static __attribute__ ((cdecl)) EXCEPTION_DISPOSITION
-_except_makefilechannel_handler(struct _EXCEPTION_RECORD *ExceptionRecord,
-	void *EstablisherFrame, struct _CONTEXT *ContextRecord,
-	void *DispatcherContext);
+
+/*
+ * Unlike Borland and Microsoft, we don't register exception handlers
+ * by pushing registration records onto the runtime stack.  Instead, we
+ * register them by creating an EXCEPTION_REGISTRATION within the activation
+ * record.
+ */
+
+typedef struct EXCEPTION_REGISTRATION {
+    struct EXCEPTION_REGISTRATION* link;
+    EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*,
+				      struct _CONTEXT*, void* );
+    void* ebp;
+    void* esp;
+    int status;
+} EXCEPTION_REGISTRATION;
+
 #endif
 
 /*
@@ -1049,6 +1057,9 @@ Tcl_MakeFileChannel(rawHandle, mode)
 					 * and TCL_WRITABLE to indicate file
 					 * mode. */
 {
+#ifdef HAVE_NO_SEH
+    EXCEPTION_REGISTRATION registration;
+#endif
     char channelName[16 + TCL_INTEGER_SPACE];
     Tcl_Channel channel = NULL;
     HANDLE handle = (HANDLE) rawHandle;
@@ -1137,81 +1148,93 @@ Tcl_MakeFileChannel(rawHandle, mode)
 	 * of this duped handle which might throw EXCEPTION_INVALID_HANDLE.
 	 */
 
-#ifdef HAVE_NO_SEH
-# ifdef TCL_MEM_DEBUG
-	__asm__ __volatile__ (
-	    "movl %%esp,  %0" "\n\t"
-	    "movl %%ebp,  %1" "\n\t"
-	    "movl %%fs:0, %2" "\n\t"
-	    : "=m"(INITIAL_ESP),
-	      "=m"(INITIAL_EBP),
-	      "=r"(INITIAL_HANDLER) );
-# endif /* TCL_MEM_DEBUG */
-
-	__asm__ __volatile__ (
-	    "pushl %%ebp" "\n\t"
-	    "pushl %0" "\n\t"
-	    "pushl %%fs:0" "\n\t"
-	    "movl  %%esp, %%fs:0"
-	    :
-	    : "r" (_except_makefilechannel_handler) );
-	result = CloseHandle(dupedHandle);
-	__asm__ __volatile__ (
-	    "jmp  makefilechannel_pop" "\n"
-	"makefilechannel_reentry:" "\n\t"
-	    "movl %%fs:0, %%eax" "\n\t"
-	    "movl 0x8(%%eax), %%esp" "\n\t"
-	    "movl 0x8(%%esp), %%ebp" "\n"
-	    "movl $0, %0" "\n"
-	"makefilechannel_pop:" "\n\t"
-	    "movl (%%esp), %%eax" "\n\t"
-	    "movl %%eax, %%fs:0" "\n\t"
-	    "add  $12, %%esp" "\n\t"
-	    : "=m"(result)
-	    :
-	    : "%eax");
-
-# ifdef TCL_MEM_DEBUG
+	result = 0;
+#ifndef HAVE_NO_SEH
+	__try {
+	    CloseHandle(dupedHandle);
+	    result = 1;
+	} __except (EXCEPTION_EXECUTE_HANDLER) {}
+#else
+	/*
+	 * Don't have SEH available, do things the hard way.
+	 * Note that this needs to be one block of asm, to avoid stack
+	 * imbalance; also, it is illegal for one asm block to contain 
+	 * a jump to another.
+	 */
+	
 	__asm__ __volatile__ (
-	    "movl  %%esp,  %0" "\n\t"
-	    "movl  %%ebp,  %1" "\n\t"
-	    "movl  %%fs:0, %2" "\n\t"
-	    : "=m"(RESTORED_ESP),
-	      "=m"(RESTORED_EBP),
-	      "=r"(RESTORED_HANDLER) );
-
-	if (INITIAL_ESP != RESTORED_ESP) {
-	    Tcl_Panic("ESP restored incorrectly");
-	}
-	if (INITIAL_EBP != RESTORED_EBP) {
-	    Tcl_Panic("EBP restored incorrectly");
-	}
-	if (INITIAL_HANDLER != RESTORED_HANDLER) {
-	    Tcl_Panic("HANDLER restored incorrectly");
-	}
-# endif /* TCL_MEM_DEBUG */
 
-	if (result == 0) {
 	    /*
-	     * The handle failed to close.  The original is therefore
-	     * invalid.
+	     * Pick up parameters before messing with the stack
 	     */
 
-	    return NULL;
-	}
+	    "movl       %[dupedHandle], %%ebx"          "\n\t"
 
-#else
-	__try {
-	    result = CloseHandle(dupedHandle);
-	} __except (EXCEPTION_EXECUTE_HANDLER) {
 	    /*
-	     * Definately an invalid handle.  So, therefore, the original
-	     * is invalid also.
+	     * Construct an EXCEPTION_REGISTRATION to protect the
+	     * call to CloseHandle
 	     */
+	    "leal       %[registration], %%edx"         "\n\t"
+	    "movl       %%fs:0,         %%eax"          "\n\t"
+	    "movl       %%eax,          0x0(%%edx)"     "\n\t" /* link */
+	    "leal       1f,             %%eax"          "\n\t"
+	    "movl       %%eax,          0x4(%%edx)"     "\n\t" /* handler */
+	    "movl       %%ebp,          0x8(%%edx)"     "\n\t" /* ebp */
+	    "movl       %%esp,          0xc(%%edx)"     "\n\t" /* esp */
+	    "movl       $0,             0x10(%%edx)"    "\n\t" /* status */
+	
+	    /* Link the EXCEPTION_REGISTRATION on the chain */
+	    
+	    "movl       %%edx,          %%fs:0"         "\n\t"
+	    
+	    /* Call CloseHandle( dupedHandle ) */
+	    
+	    "pushl      %%ebx"                          "\n\t"
+	    "call       _CloseHandle@4"                 "\n\t"
+	    
+	    /* 
+	     * Come here on normal exit.  Recover the EXCEPTION_REGISTRATION
+	     * and put a TRUE status return into it.
+	     */
+	    
+	    "movl       %%fs:0,         %%edx"          "\n\t"
+	    "movl	$1,		%%eax"		"\n\t"
+	    "movl       %%eax,          0x10(%%edx)"    "\n\t"
+	    "jmp        2f"                             "\n"
+	    
+	    /*
+	     * Come here on an exception.  Recover the EXCEPTION_REGISTRATION
+	     */
+	    
+	    "1:"                                        "\t"
+	    "movl       %%fs:0,         %%edx"          "\n\t"
+	    "movl       0x8(%%edx),     %%edx"          "\n\t"
+	    
+	    /* 
+	     * Come here however we exited.  Restore context from the
+	     * EXCEPTION_REGISTRATION in case the stack is unbalanced.
+	     */
+	    
+	    "2:"                                        "\t"
+	    "movl       0xc(%%edx),     %%esp"          "\n\t"
+	    "movl       0x8(%%edx),     %%ebp"          "\n\t"
+	    "movl       0x0(%%edx),     %%eax"          "\n\t"
+	    "movl       %%eax,          %%fs:0"         "\n\t"
+	    
+	    :
+	    /* No outputs */
+	    :
+	    [registration]  "m"     (registration),
+	    [dupedHandle]   "m"	    (dupedHandle)
+	    :
+	    "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
+	    );
+	result = registration.status;
 
+#endif
+	if (result == FALSE) {
 	    return NULL;
 	}
-#endif /* HAVE_NO_SEH */
 
 	/* Fall through, the handle is valid. */
 
@@ -1229,37 +1252,6 @@ Tcl_MakeFileChannel(rawHandle, mode)
 /*
  *----------------------------------------------------------------------
  *
- * _except_makefilechannel_handler --
- *
- *	SEH exception handler for Tcl_MakeFileChannel.
- *
- * Results:
- *	See Tcl_MakeFileChannel.
- *
- * Side effects:
- *	See Tcl_MakeFileChannel.
- *
- *----------------------------------------------------------------------
- */
-#ifdef HAVE_NO_SEH
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_makefilechannel_handler(
-    struct _EXCEPTION_RECORD *ExceptionRecord,
-    void *EstablisherFrame,
-    struct _CONTEXT *ContextRecord,
-    void *DispatcherContext)
-{
-    __asm__ __volatile__ (
-	    "jmp makefilechannel_reentry");
-    return 0; /* Function does not return */
-}
-#endif
-
-/*
- *----------------------------------------------------------------------
- *
  * TclpGetDefaultStdChannel --
  *
  *	Constructs a channel for the specified standard OS handle.
diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c
index a5df717..0534971 100644
--- a/win/tclWinFCmd.c
+++ b/win/tclWinFCmd.c
@@ -9,7 +9,7 @@
  * See the file "license.terms" for information on usage and redistribution
  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  *
- * RCS: @(#) $Id: tclWinFCmd.c,v 1.45 2005/05/10 18:35:37 kennykb Exp $
+ * RCS: @(#) $Id: tclWinFCmd.c,v 1.46 2005/06/23 19:48:51 kennykb Exp $
  */
 
 #include "tclWinInt.h"
@@ -74,35 +74,25 @@ CONST TclFileAttrProcs tclpFileAttrProcs[] = {
 	{GetWinFileShortName, CannotSetAttribute},
 	{GetWinFileAttributes, SetWinFileAttributes}};
 
-#if defined(HAVE_NO_SEH) && defined(TCL_MEM_DEBUG)
-static void *INITIAL_ESP,
-            *INITIAL_EBP,
-            *INITIAL_HANDLER,
-            *RESTORED_ESP,
-            *RESTORED_EBP,
-            *RESTORED_HANDLER;
-#endif /* HAVE_NO_SEH && TCL_MEM_DEBUG */
-
 #ifdef HAVE_NO_SEH
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_dorenamefile_handler(
-    struct _EXCEPTION_RECORD *ExceptionRecord,
-    void *EstablisherFrame,
-    struct _CONTEXT *ContextRecord,
-    void *DispatcherContext);
-
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_docopyfile_handler(
-    struct _EXCEPTION_RECORD *ExceptionRecord,
-    void *EstablisherFrame,
-    struct _CONTEXT *ContextRecord,
-    void *DispatcherContext);
-
-#endif /* HAVE_NO_SEH */
+
+/*
+ * Unlike Borland and Microsoft, we don't register exception handlers
+ * by pushing registration records onto the runtime stack.  Instead, we
+ * register them by creating an EXCEPTION_REGISTRATION within the activation
+ * record.
+ */
+
+typedef struct EXCEPTION_REGISTRATION {
+    struct EXCEPTION_REGISTRATION* link;
+    EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*,
+				      struct _CONTEXT*, void* );
+    void* ebp;
+    void* esp;
+    int status;
+} EXCEPTION_REGISTRATION;
+
+#endif
 
 /*
  * Prototype for the TraverseWinTree callback function.
@@ -193,6 +183,9 @@ DoRenameFile(
     CONST TCHAR *nativeDst)	/* New pathname for file or directory
 				 * (native). */
 {    
+#ifdef HAVE_NO_SEH
+    EXCEPTION_REGISTRATION registration;
+#endif
     DWORD srcAttr, dstAttr;
     int retval = -1;
 
@@ -212,72 +205,95 @@ DoRenameFile(
      * if one of the arguments is a char block device.
      */
 
-#ifdef HAVE_NO_SEH
-# ifdef TCL_MEM_DEBUG
-    __asm__ __volatile__ (
-            "movl %%esp,  %0" "\n\t"
-            "movl %%ebp,  %1" "\n\t"
-            "movl %%fs:0, %2" "\n\t"
-            : "=m"(INITIAL_ESP),
-              "=m"(INITIAL_EBP),
-              "=r"(INITIAL_HANDLER) );
-# endif /* TCL_MEM_DEBUG */
-
-    __asm__ __volatile__ (
-            "pushl %%ebp" "\n\t"
-            "pushl %0" "\n\t"
-            "pushl %%fs:0" "\n\t"
-            "movl  %%esp, %%fs:0"
-            :
-            : "r" (_except_dorenamefile_handler)
-            );
-#else
+#ifndef HAVE_NO_SEH
     __try {
-#endif /* HAVE_NO_SEH */
 	if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) {
 	    retval = TCL_OK;
 	}
-#ifdef HAVE_NO_SEH
-    __asm__ __volatile__ (
-            "jmp  dorenamefile_pop" "\n"
-        "dorenamefile_reentry:" "\n\t"
-            "movl %%fs:0, %%eax" "\n\t"
-            "movl 0x8(%%eax), %%esp" "\n\t"
-            "movl 0x8(%%esp), %%ebp" "\n"
-        "dorenamefile_pop:" "\n\t"
-            "movl (%%esp), %%eax" "\n\t"
-            "movl %%eax, %%fs:0" "\n\t"
-            "add  $12, %%esp" "\n\t"
-            :
-            :
-            : "%eax");
-
-# ifdef TCL_MEM_DEBUG
-    __asm__ __volatile__ (
-            "movl  %%esp,  %0" "\n\t"
-            "movl  %%ebp,  %1" "\n\t"
-            "movl  %%fs:0, %2" "\n\t"
-            : "=m"(RESTORED_ESP),
-              "=m"(RESTORED_EBP),
-              "=r"(RESTORED_HANDLER) );
-
-    if (INITIAL_ESP != RESTORED_ESP) {
-        Tcl_Panic("ESP restored incorrectly");
-    }
-    if (INITIAL_EBP != RESTORED_EBP) {
-        Tcl_Panic("EBP restored incorrectly");
-    }
-    if (INITIAL_HANDLER != RESTORED_HANDLER) {
-        Tcl_Panic("HANDLER restored incorrectly");
-    }
-# endif /* TCL_MEM_DEBUG */
-#else
     } __except (EXCEPTION_EXECUTE_HANDLER) {}
-#endif /* HAVE_NO_SEH */
+#else
 
     /*
-     * Avoid using control flow statements in the SEH guarded block!
+     * Don't have SEH available, do things the hard way.
+     * Note that this needs to be one block of asm, to avoid stack
+     * imbalance; also, it is illegal for one asm block to contain 
+     * a jump to another.
      */
+
+    __asm__ __volatile__ (
+	/*
+	 * Pick up params before messing with the stack */
+
+	"movl	    %[nativeDst],   %%ebx"	    "\n\t"
+	"movl       %[nativeSrc],   %%ecx"          "\n\t"
+
+	/*
+	 * Construct an EXCEPTION_REGISTRATION to protect the
+	 * call to MoveFile
+	 */
+	"leal       %[registration], %%edx"         "\n\t"
+	"movl       %%fs:0,         %%eax"          "\n\t"
+	"movl       %%eax,          0x0(%%edx)"     "\n\t" /* link */
+	"leal       1f,             %%eax"          "\n\t"
+	"movl       %%eax,          0x4(%%edx)"     "\n\t" /* handler */
+	"movl       %%ebp,          0x8(%%edx)"     "\n\t" /* ebp */
+	"movl       %%esp,          0xc(%%edx)"     "\n\t" /* esp */
+	"movl       $0,             0x10(%%edx)"    "\n\t" /* status */
+	
+	/* Link the EXCEPTION_REGISTRATION on the chain */
+	
+	"movl       %%edx,          %%fs:0"         "\n\t"
+	
+	/* Call MoveFile( nativeSrc, nativeDst ) */
+	
+	"pushl	    %%ebx"			    "\n\t"
+	"pushl	    %%ecx"			    "\n\t"
+	"movl	    %[moveFile],    %%eax"	    "\n\t"
+	"call	    *%%eax"			    "\n\t"
+	
+	/* 
+	 * Come here on normal exit.  Recover the EXCEPTION_REGISTRATION
+	 * and put the status return from MoveFile into it.
+	 */
+	
+	"movl	    %%fs:0,	    %%edx"	    "\n\t"
+	"movl	    %%eax,	    0x10(%%edx)"    "\n\t"
+	"jmp	    2f"				    "\n"
+	
+	/*
+	 * Come here on an exception.  Recover the EXCEPTION_REGISTRATION
+	 */
+	
+	"1:"					    "\t"
+	"movl       %%fs:0,         %%edx"          "\n\t"
+	"movl       0x8(%%edx),     %%edx"          "\n\t"
+	
+	/* 
+	 * Come here however we exited.  Restore context from the
+	 * EXCEPTION_REGISTRATION in case the stack is unbalanced.
+	 */
+	
+	"2:"                                        "\t"
+	"movl       0xc(%%edx),     %%esp"          "\n\t"
+	"movl       0x8(%%edx),     %%ebp"          "\n\t"
+	"movl       0x0(%%edx),     %%eax"          "\n\t"
+	"movl       %%eax,          %%fs:0"         "\n\t"
+	
+	:
+	/* No outputs */
+        :
+	[registration]  "m"     (registration),
+	[nativeDst]	"m"     (nativeDst),
+	[nativeSrc]     "m"     (nativeSrc),
+	[moveFile]      "r"     (tclWinProcs->moveFileProc)
+        :
+	"%eax", "%ebx", "%ecx", "%edx", "memory"
+        );
+    if (registration.status != FALSE) {
+	retval = TCL_OK;
+    }
+#endif
+
     if (retval != -1) {
         return retval;
     }
@@ -506,37 +522,6 @@ DoRenameFile(
 }
 
 /*
- *----------------------------------------------------------------------
- *
- * _except_dorenamefile_handler --
- *
- *	SEH exception handler for DoRenameFile.
- *
- * Results:
- *	See DoRenameFile.
- *
- * Side effects:
- *	See DoRenameFile.
- *
- *----------------------------------------------------------------------
- */
-#ifdef HAVE_NO_SEH
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_dorenamefile_handler(
-    struct _EXCEPTION_RECORD *ExceptionRecord,
-    void *EstablisherFrame,
-    struct _CONTEXT *ContextRecord,
-    void *DispatcherContext)
-{
-    __asm__ __volatile__ (
-            "jmp dorenamefile_reentry");
-    return 0; /* Function does not return */
-}
-#endif /* HAVE_NO_SEH */
-
-/*
  *---------------------------------------------------------------------------
  *
  * TclpObjCopyFile, DoCopyFile --
@@ -577,6 +562,9 @@ DoCopyFile(
    CONST TCHAR *nativeSrc,	/* Pathname of file to be copied (native). */
    CONST TCHAR *nativeDst)	/* Pathname of file to copy to (native). */
 {
+#ifdef HAVE_NO_SEH
+    EXCEPTION_REGISTRATION registration;
+#endif
     int retval = -1;
 
     /*
@@ -595,72 +583,97 @@ DoCopyFile(
      * of the arguments is a char block device.
      */
 
-#ifdef HAVE_NO_SEH
-# ifdef TCL_MEM_DEBUG
-    __asm__ __volatile__ (
-            "movl %%esp,  %0" "\n\t"
-            "movl %%ebp,  %1" "\n\t"
-            "movl %%fs:0, %2" "\n\t"
-            : "=m"(INITIAL_ESP),
-              "=m"(INITIAL_EBP),
-              "=r"(INITIAL_HANDLER) );
-# endif /* TCL_MEM_DEBUG */
-
-    __asm__ __volatile__ (
-            "pushl %%ebp" "\n\t"
-            "pushl %0" "\n\t"
-            "pushl %%fs:0" "\n\t"
-            "movl  %%esp, %%fs:0"
-            :
-            : "r" (_except_docopyfile_handler)
-            );
-#else
+#ifndef HAVE_NO_SEH
     __try {
-#endif /* HAVE_NO_SEH */
 	if ((*tclWinProcs->copyFileProc)(nativeSrc, nativeDst, 0) != FALSE) {
 	    retval = TCL_OK;
 	}
-#ifdef HAVE_NO_SEH
-    __asm__ __volatile__ (
-            "jmp  docopyfile_pop" "\n"
-        "docopyfile_reentry:" "\n\t"
-            "movl %%fs:0, %%eax" "\n\t"
-            "movl 0x8(%%eax), %%esp" "\n\t"
-            "movl 0x8(%%esp), %%ebp" "\n"
-        "docopyfile_pop:" "\n\t"
-            "movl (%%esp), %%eax" "\n\t"
-            "movl %%eax, %%fs:0" "\n\t"
-            "add  $12, %%esp" "\n\t"
-            :
-            :
-            : "%eax");
-
-# ifdef TCL_MEM_DEBUG
-    __asm__ __volatile__ (
-            "movl  %%esp,  %0" "\n\t"
-            "movl  %%ebp,  %1" "\n\t"
-            "movl  %%fs:0, %2" "\n\t"
-            : "=m"(RESTORED_ESP),
-              "=m"(RESTORED_EBP),
-              "=r"(RESTORED_HANDLER) );
-
-    if (INITIAL_ESP != RESTORED_ESP) {
-        Tcl_Panic("ESP restored incorrectly");
-    }
-    if (INITIAL_EBP != RESTORED_EBP) {
-        Tcl_Panic("EBP restored incorrectly");
-    }
-    if (INITIAL_HANDLER != RESTORED_HANDLER) {
-        Tcl_Panic("HANDLER restored incorrectly");
-    }
-# endif /* TCL_MEM_DEBUG */
-#else
     } __except (EXCEPTION_EXECUTE_HANDLER) {}
-#endif /* HAVE_NO_SEH */
+#else
 
     /*
-     * Avoid using control flow statements in the SEH guarded block!
+     * Don't have SEH available, do things the hard way.
+     * Note that this needs to be one block of asm, to avoid stack
+     * imbalance; also, it is illegal for one asm block to contain 
+     * a jump to another.
      */
+
+    __asm__ __volatile__ (
+
+	/*
+	 * Pick up parameters before messing with the stack
+	 */
+
+	"movl       %[nativeDst],   %%ebx"          "\n\t"
+        "movl       %[nativeSrc],   %%ecx"          "\n\t"
+	/*
+	 * Construct an EXCEPTION_REGISTRATION to protect the
+	 * call to CopyFile
+	 */
+	"leal       %[registration], %%edx"         "\n\t"
+	"movl       %%fs:0,         %%eax"          "\n\t"
+	"movl       %%eax,          0x0(%%edx)"     "\n\t" /* link */
+	"leal       1f,             %%eax"          "\n\t"
+	"movl       %%eax,          0x4(%%edx)"     "\n\t" /* handler */
+	"movl       %%ebp,          0x8(%%edx)"     "\n\t" /* ebp */
+	"movl       %%esp,          0xc(%%edx)"     "\n\t" /* esp */
+	"movl       $0,             0x10(%%edx)"    "\n\t" /* status */
+	
+	/* Link the EXCEPTION_REGISTRATION on the chain */
+	
+	"movl       %%edx,          %%fs:0"         "\n\t"
+	
+	/* Call CopyFile( nativeSrc, nativeDst, 0 ) */
+	
+	"movl	    %[copyFile],    %%eax"	    "\n\t"
+	"pushl	    $0" 			    "\n\t"
+	"pushl	    %%ebx"			    "\n\t"
+	"pushl	    %%ecx"			    "\n\t"
+	"call	    *%%eax"			    "\n\t"
+	
+	/* 
+	 * Come here on normal exit.  Recover the EXCEPTION_REGISTRATION
+	 * and put the status return from CopyFile into it.
+	 */
+	
+	"movl	    %%fs:0,	    %%edx"	    "\n\t"
+	"movl	    %%eax,	    0x10(%%edx)"    "\n\t"
+	"jmp	    2f"				    "\n"
+	
+	/*
+	 * Come here on an exception.  Recover the EXCEPTION_REGISTRATION
+	 */
+	
+	"1:"					    "\t"
+	"movl       %%fs:0,         %%edx"          "\n\t"
+	"movl       0x8(%%edx),     %%edx"          "\n\t"
+	
+	/* 
+	 * Come here however we exited.  Restore context from the
+	 * EXCEPTION_REGISTRATION in case the stack is unbalanced.
+	 */
+	
+	"2:"                                        "\t"
+	"movl       0xc(%%edx),     %%esp"          "\n\t"
+	"movl       0x8(%%edx),     %%ebp"          "\n\t"
+	"movl       0x0(%%edx),     %%eax"          "\n\t"
+	"movl       %%eax,          %%fs:0"         "\n\t"
+	
+	:
+	/* No outputs */
+        :
+	[registration]  "m"     (registration),
+	[nativeDst]	"m"     (nativeDst),
+	[nativeSrc]     "m"     (nativeSrc),
+	[copyFile]      "r"     (tclWinProcs->copyFileProc)
+        :
+	"%eax", "%ebx", "%ecx", "%edx", "memory"
+        );
+    if (registration.status != FALSE) {
+	retval = TCL_OK;
+    }
+#endif
+
     if (retval != -1) {
         return retval;
     }
@@ -709,37 +722,6 @@ DoCopyFile(
 }
 
 /*
- *----------------------------------------------------------------------
- *
- * _except_docopyfile_handler --
- *
- *	SEH exception handler for DoCopyFile.
- *
- * Results:
- *	See DoCopyFile.
- *
- * Side effects:
- *	See DoCopyFile.
- *
- *----------------------------------------------------------------------
- */
-#ifdef HAVE_NO_SEH
-static
-__attribute__ ((cdecl))
-EXCEPTION_DISPOSITION
-_except_docopyfile_handler(
-    struct _EXCEPTION_RECORD *ExceptionRecord,
-    void *EstablisherFrame,
-    struct _CONTEXT *ContextRecord,
-    void *DispatcherContext)
-{
-    __asm__ __volatile__ (
-            "jmp docopyfile_reentry");
-    return 0; /* Function does not return */
-}
-#endif /* HAVE_NO_SEH */
-
-/*
  *---------------------------------------------------------------------------
  *
  * TclpObjDeleteFile, TclpDeleteFile --
-- 
cgit v0.12