OSDN Git Service

Rework __try1/__except1 to resolve issue [#1328].
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Tue, 28 Jun 2016 13:50:38 +0000 (14:50 +0100)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Tue, 28 Jun 2016 13:50:38 +0000 (14:50 +0100)
mingwrt/ChangeLog
mingwrt/include/excpt.h

index 7e2001b..77484d2 100644 (file)
@@ -1,3 +1,22 @@
+2016-06-28  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
+       Rework __try1/__except1 to resolve issue [#1328].
+
+       * include/excpt.h: Assert copyright; tidy layout.
+       (_EXCPT_H_): Multiple inclusion guard macro renamed to...
+       (_EXCPT_H): ...this; update all references as appropriate.
+       (_BEGIN_C_DECLS, _END_C_DECLS): Use these.
+       (__typecast_alloca): New macro; define it, casting return type of...
+       (__builtin_alloca): ...this to a specified data type; use it in...
+       (__try1_setup, __except1_teardown): ...these new macros; define them
+       as parameterized templates, providing both -masm-att and -masm-intel
+       syntax implementations, with host specific word size and register
+       assignment parameter substitutions; use them to redefine...
+       (__try1, __except1): ...each of these, using __builtin_alloca to avoid
+       direct stack pushes when registering exception handlers; assign the
+       template parameters as appropriate to support implementation for...
+       [_WIN64, _WIN32]: ...either of these, as the host requires.
+
 2016-06-17  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
        Merge Cygwin CVS updates to legacy branch.
index 7433dd0..df03176 100644 (file)
 /*
  * excpt.h
- * This file has no copyright assigned and is placed in the Public Domain.
- * This file is a part of the mingw-runtime package.
- * No warranty is given; refer to the file DISCLAIMER within the package.
  *
- * Support for operating system level structured exception handling.
+ * Experimental support for operating system level structured handling
+ * of exceptions.
  *
- * NOTE: This is very preliminary stuff. I am also pretty sure it is
- *       completely Intel specific.
+ * $Id$
+ *
+ * Written by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ * Revised by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 1997, 1999, 2001-2002, 2004, 2007, 2012, 2016,
+ *  MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
  *
  */
+#ifndef _EXCPT_H
+#pragma GCC system_header
+#define _EXCPT_H
+
+/* FIXME: this utility macro, to allocate stack space for any aggregate
+ * data type, with an explicit type cast of a pointer to that data type,
+ * deserves a place in a more universally accessible header file.  The
+ * type cast is not strictly necessary for C, (but is permitted); it is
+ * essential for C++.
+ */
+#define __typecast_alloca(type) (type *)(__builtin_alloca( sizeof(type) ))
 
-#ifndef        _EXCPT_H_
-#define        _EXCPT_H_
-
-/* All the headers include this file. */
+/* All MinGW CRT headers are required to include <_mingw.h>
+ */
 #include <_mingw.h>
 
+/* Exception handler functions require definitions of _CONTEXT, and
+ * _EXCEPTION_RECORD structures, which are provided in <windef.h>
+ */
 #include <windef.h>
 
-/*
- * NOTE: The constants structs and typedefs below should be defined in the
- *       Win32 API headers.
+#ifndef _EXCPT_W32API_H
+/* FIXME: These constants, structs, and typedefs should be defined
+ * in the Win32 API headers; (we need to establish where -- perhaps
+ * this header itself should be redesignated as a W32API header).
  */
-#define        EH_NONCONTINUABLE       0x01
-#define        EH_UNWINDING            0x02
-#define        EH_EXIT_UNWIND          0x04
-#define        EH_STACK_INVALID        0x08
-#define        EH_NESTED_CALL          0x10
-
-#ifndef        RC_INVOKED
-
-typedef enum {
-       ExceptionContinueExecution,
-       ExceptionContinueSearch,
-       ExceptionNestedException,
-       ExceptionCollidedUnwind
+#define EH_NONCONTINUABLE      0x01
+#define EH_UNWINDING           0x02
+#define EH_EXIT_UNWIND         0x04
+#define EH_STACK_INVALID       0x08
+#define EH_NESTED_CALL         0x10
+
+#ifndef RC_INVOKED
+
+typedef enum
+{ ExceptionContinueExecution,
+  ExceptionContinueSearch,
+  ExceptionNestedException,
+  ExceptionCollidedUnwind
 } EXCEPTION_DISPOSITION;
 
+#endif /* ! RC_INVOKED */
+#endif /* !_EXCPT_W2API_H */
 
-/*
- * End of stuff that should be in the Win32 API files.
- */
+#ifndef RC_INVOKED
 
+_BEGIN_C_DECLS
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The type of function that is expected as an exception handler to be
- * installed with __try1.
+/* The type of function that is expected as an exception handler,
+ * to be installed by the __try1(__handler) primitive.
  */
 typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)
-               (struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
+(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
 
-/*
- * This is not entirely necessary, but it is the structure installed by
- * the __try1 primitive below.
- */
 typedef struct _EXCEPTION_REGISTRATION
-{
-       struct _EXCEPTION_REGISTRATION* prev;
-       PEXCEPTION_HANDLER              handler;
+{ /* Maps the structure of the exception handler registration
+   * block, as installed by the __try1(__handler) primitive.
+   */
+  struct _EXCEPTION_REGISTRATION       *prev;
+  PEXCEPTION_HANDLER                    handler;
 } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;
 
+/* Aliases which may be preferred, when referring to the
+ * EXCEPTION_REGISTRATION structure.
+ */
 typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD;
 typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD;
 
-/*
- * A macro which installs the supplied exception handler.
- * Push the pointer to the new handler onto the stack,
- * then push the pointer to the old registration structure (at fs:0)
- * onto the stack, then put a pointer to the new registration
- * structure (i.e. the current stack pointer) at fs:0.
+/* Deployment of exception handlers is facilitated by the pair
+ * of macros, __try1(_handler) and __except1.
+ *
+ * CAUTION: __try1(__handler) and __except1 must be deployed as
+ * a complementary pair, within the scope of the stack frame of
+ * a single function, with __try1(__handler) preceding the use
+ * of __except1.  Failure to invoke __except1 before release of
+ * any stack frame, in which __try1(__handler) has been invoked,
+ * will invalidate the EXCEPTION_REGISTRATION_RECORD, which has
+ * been installed by __try1(_handler), at the head of the active
+ * exception handler chain; this will cause undefined behaviour,
+ * which is sure to go badly.
+ *
+ * To accommodate implementation differences between _WIN32 and
+ * _WIN64 hosts, the actual implementations of __try1(__handler)
+ * and __except1 are expressed in terms of a pair of lower level
+ * internal macros, namely:
+ *
+ * Macro: __try1_setup(__handler,__wsize,__ts)
+ *
+ * Helper for implementation of macro __try1(__handler); allocate
+ * a block of memory, within the stack frame of the calling function,
+ * which is then initialized as an EXCEPTION_REGISTRATION_RECORD, and
+ * linked to the head of the installed exception handler chain.
+ *
+ * Inputs:
+ *  __handler  pointer to an EXCEPTION_HANDLER function.
+ *  __wsize    the Intel host word size pointer description.
+ *  __ts       thread information segment register name.
  */
-#ifdef _WIN64
-# define __try1(pHandler) \
-       __asm__ __volatile__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : \
-       "g" (pHandler));
-#else
-# define __try1(pHandler) \
-       __asm__ __volatile__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : \
-       "g" (pHandler));
-#endif
+#define __try1_setup(__handler,__wsize,__ts)                           \
+{ EXCEPTION_REGISTRATION *__hook;                                      \
+  __hook = __typecast_alloca( EXCEPTION_REGISTRATION );                \
+  __hook->handler = __handler;                                         \
+  __asm__ __volatile__                                                 \
+  ( "mov{%z0}\t{%%|%0, "__wsize" }"__ts":{|[}0x0{, %0|]}\n\t"          \
+    "mov{%z1}\t{%1, %%|"__wsize" }"__ts":{|[}0x0{|], %1}"              \
+    :"=r"(__hook->prev):"r"(__hook):"memory"                           \
+  );                                                                   \
+}
 
-/*
- * A macro which (despite its name) *removes* an installed
- * exception handler. Should be used only in conjunction with the above
- * install routine __try1.
- * Move the pointer to the old reg. struct (at the current stack
- * position) to fs:0, replacing the pointer we installed above,
- * then add 8 to the stack pointer to get rid of the space we
- * used when we pushed on our new reg. struct above. Notice that
- * the stack must be in the exact state at this point that it was
- * after we did __try1 or this will smash things.
+/* Macro: __except1_teardown(__wsize,__ts)
+ *
+ * Helper which provides the implementation for the __except1
+ * complement to __try1(__handler) macro; it unlinks the first
+ * EXCEPTION_REGISTRATION_RECORD from the head of the exception
+ * handler chain.  Arguments are as described for those of the
+ * same name, in the __try1_setup macro argument list.
+ */
+#define __except1_teardown(__wsize,__ts)                               \
+{ register EXCEPTION_REGISTRATION *__hook;                             \
+  __asm__ __volatile__                                                 \
+  ( "mov{%z0}\t{%%|%0, "__wsize" }"__ts":{|[}0x0{, %0|]}\n\t"          \
+    "mov{%z0}\t{(}%0{)}, {|"__wsize" [}%0{|]}\n\t"                     \
+    "mov{%z0}\t{%0, %%|"__wsize" }"__ts":{|[}0x0{|], %0}"              \
+    :"+r"(__hook)::"memory"                                            \
+  );                                                                   \
+}
+
+/* Specialization of the above primitives, creating __try1(__handler),
+ * and its complementary __except1 implementation, with the appropriate
+ * assignments of word size and TIB segment register, for each of...
  */
 #ifdef _WIN64
-# define       __except1       \
-       __asm__ __volatile__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq \
-       $16,%%rsp;" : : : "%rax");
-#else
-# define __except1     \
-       __asm__ __volatile__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl \
-       $8,%%esp;" : : : "%eax");
-#endif
+/* ...64-bit windows, for which the word size for representation of
+ * pointers, in Intel-syntax code, is "QWORD PTR", and the gs segment
+ * is used for access to the thread information block...
+ */
+# define __try1(__handler) __try1_setup(__handler,"QWORD PTR","gs")
+# define __except1 __except1_teardown("QWORD PTR","gs")
 
-#ifdef __cplusplus
-}
+#else  /* _WIN32 */
+/* ...while in 32-bit windows, the corresponding pointer word size
+ * is "DWORD PTR", and the the thread information block is located
+ * in the fs segment.
+ */
+# define __try1(__handler) __try1_setup(__handler,"DWORD PTR","fs")
+# define __except1 __except1_teardown("DWORD PTR","fs")
 #endif
 
-#endif /* Not RC_INVOKED */
+_END_C_DECLS
 
-#endif /* _EXCPT_H_ not defined */
+#endif /* ! RC_INVOKED */
+#endif /* !_EXCPT_H: $RCSfile$: end of file */