[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

ARM EABI (armel) Objective-C support patches



Hi,

I'm working with Andrew Jenner at CodeSourcery to fix Objective-C and
Fortran (gfortran) for the ARM EABI Debian port. These two patches
provide Objective-C support sufficient to run GCC's ObjC testsuite with
zero unexpected failures (as tested with CodeSourcery's
cross-compilation scripts -- I've not tried native builds).

One patch makes libobjc build and run properly (mostly ARM
EHABI-specific exception-handling support), the other is a
language-independent fix to define the EH_USES macro (which fixes a
couple of ObjC testsuite failures). Both are based on the
"gcc-4.3-source_4.3.0-1_all.deb" package, pre-patched for ARM EABI.

Is this the right place to send such patches, or should they go
elsewhere? (They will be submitted for inclusion in FSF mainline in due
course).

Thanks,

Julian

ChangeLog (libobjc-arm-eabi-support)

    * configure.ac (arm*-*-linux-gnueabi): Don't disable building
    of libobjc for ARM EABI Linux.
    * configure: Regenerate.

    libobjc/
    * exception.c (__objc_exception_class): Initialise as constant
    array for ARM EABI. Change macro to static const for non-ARM EABI.
    (ObjcException): Add note about structure layout. Remove landingPad
    and handlerSwitchValue for ARM EABI.
    (get_ttype_entry): Add __ARM_EABI_UNWINDER__ version
    of function.
    (CONTINUE_UNWINDING): Define for ARM EABI/otherwise cases.
    (PERSONALITY_FUNCTION): Use ARM EABI-specific arguments, and add
    ARM EABI unwinding support.
    (objc_exception_throw): Use memcpy to initialise exception class.

ChangeLog (arm-eh-uses)

    gcc/
    * config/arm/arm.h (EH_USES): Define.
--- .pc/arm-eh-uses/gcc/config/arm/arm.h	2008-04-23 14:57:33.000000000 -0700
+++ gcc/config/arm/arm.h	2008-04-23 14:58:18.000000000 -0700
@@ -879,6 +879,10 @@ extern int arm_structure_size_boundary;
 #define ARM_EH_STACKADJ_REGNUM	2
 #define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (SImode, ARM_EH_STACKADJ_REGNUM)
 
+/* r0 may be used by catch handlers.  Make sure it's marked live on entry
+   to those.  */
+#define EH_USES(N) ((N) == 0)
+
 /* The native (Norcroft) Pascal compiler for the ARM passes the static chain
    as an invisible last argument (possible since varargs don't exist in
    Pascal), so the following is not true.  */
--- .pc/libobjc-arm-eabi-support/configure.ac	2008-04-23 14:26:40.000000000 -0700
+++ configure.ac	2008-04-23 14:30:17.000000000 -0700
@@ -538,7 +538,6 @@ case "${target}" in
     ;;
   arm*-*-linux-gnueabi)
     noconfigdirs="$noconfigdirs target-qthreads"
-    noconfigdirs="$noconfigdirs target-libobjc"
     case ${with_newlib} in
       no) noconfigdirs="$noconfigdirs target-newlib target-libgloss"
     esac
--- .pc/libobjc-arm-eabi-support/libobjc/exception.c	2008-04-23 14:26:33.000000000 -0700
+++ libobjc/exception.c	2008-04-23 14:32:36.000000000 -0700
@@ -31,16 +31,25 @@ Boston, MA 02110-1301, USA.  */
 #include "unwind-pe.h"
 
 
+#ifdef __ARM_EABI_UNWINDER__
+
+const _Unwind_Exception_Class __objc_exception_class
+  = {'G', 'N', 'U', 'C', 'O', 'B', 'J', 'C'};
+  
+#else
+
 /* This is the exception class we report -- "GNUCOBJC".  */
-#define __objc_exception_class			\
-  ((((((((_Unwind_Exception_Class) 'G'		\
-         << 8 | (_Unwind_Exception_Class) 'N')	\
-        << 8 | (_Unwind_Exception_Class) 'U')	\
-       << 8 | (_Unwind_Exception_Class) 'C')	\
-      << 8 | (_Unwind_Exception_Class) 'O')	\
-     << 8 | (_Unwind_Exception_Class) 'B')	\
-    << 8 | (_Unwind_Exception_Class) 'J')	\
-   << 8 | (_Unwind_Exception_Class) 'C')
+static const _Unwind_Exception_Class __objc_exception_class
+  = ((((((((_Unwind_Exception_Class) 'G'
+            << 8 | (_Unwind_Exception_Class) 'N')
+           << 8 | (_Unwind_Exception_Class) 'U')
+          << 8 | (_Unwind_Exception_Class) 'C')
+         << 8 | (_Unwind_Exception_Class) 'O')
+        << 8 | (_Unwind_Exception_Class) 'B')
+       << 8 | (_Unwind_Exception_Class) 'J')
+      << 8 | (_Unwind_Exception_Class) 'C');
+
+#endif
 
 /* This is the object that is passed around by the Objective C runtime
    to represent the exception in flight.  */
@@ -50,12 +59,18 @@ struct ObjcException
   /* This bit is needed in order to interact with the unwind runtime.  */
   struct _Unwind_Exception base;
 
-  /* The actual object we want to throw.  */
+  /* The actual object we want to throw. Note: must come immediately after
+     unwind header.  */
   id value;
 
+#ifdef __ARM_EABI_UNWINDER__
+  /* Note: we use the barrier cache defined in the unwind control block for
+     ARM EABI.  */
+#else
   /* Cache some internal unwind data between phase 1 and phase 2.  */
   _Unwind_Ptr landingPad;
   int handlerSwitchValue;
+#endif
 };
 
 
@@ -106,6 +121,24 @@ parse_lsda_header (struct _Unwind_Contex
   return p;
 }
 
+#ifdef __ARM_EABI_UNWINDER__
+
+static Class
+get_ttype_entry (struct lsda_header_info *info, _uleb128_t i)
+{
+  _Unwind_Ptr ptr;
+  
+  ptr = (_Unwind_Ptr) (info->TType - (i * 4));
+  ptr = _Unwind_decode_target2 (ptr);
+  
+  if (ptr)
+    return objc_get_class ((const char *) ptr);
+  else
+    return 0;
+}
+
+#else
+
 static Class
 get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
 {
@@ -122,6 +155,8 @@ get_ttype_entry (struct lsda_header_info
     return 0;
 }
 
+#endif
+
 /* Like unto the method of the same name on Object, but takes an id.  */
 /* ??? Does this bork the meta-type system?  Can/should we look up an
    isKindOf method on the id?  */
@@ -150,12 +185,32 @@ isKindOf (id value, Class target)
 #define PERSONALITY_FUNCTION	__gnu_objc_personality_v0
 #endif
 
+#ifdef __ARM_EABI_UNWINDER__
+
+#define CONTINUE_UNWINDING \
+  do								\
+    {								\
+      if (__gnu_unwind_frame(ue_header, context) != _URC_OK)	\
+	return _URC_FAILURE;					\
+      return _URC_CONTINUE_UNWIND;				\
+    }								\
+  while (0)
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State state,
+		      struct _Unwind_Exception *ue_header,
+		      struct _Unwind_Context *context)
+#else
+
+#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
+
 _Unwind_Reason_Code
 PERSONALITY_FUNCTION (int version,
 		      _Unwind_Action actions,
 		      _Unwind_Exception_Class exception_class,
 		      struct _Unwind_Exception *ue_header,
 		      struct _Unwind_Context *context)
+#endif
 {
   struct ObjcException *xh = (struct ObjcException *) ue_header;
 
@@ -165,19 +220,65 @@ PERSONALITY_FUNCTION (int version,
   const unsigned char *p;
   _Unwind_Ptr landing_pad, ip;
   int handler_switch_value;
-  int saw_cleanup = 0, saw_handler;
+  int saw_cleanup = 0, saw_handler, foreign_exception;
   void *return_object;
+  int ip_before_insn = 0;
+
+#ifdef __ARM_EABI_UNWINDER__
+  _Unwind_Action actions;
+  
+  switch (state & _US_ACTION_MASK)
+    {
+    case _US_VIRTUAL_UNWIND_FRAME:
+      actions = _UA_SEARCH_PHASE;
+      break;
+
+    case _US_UNWIND_FRAME_STARTING:
+      actions = _UA_CLEANUP_PHASE;
+      if (!(state & _US_FORCE_UNWIND)
+	  && ue_header->barrier_cache.sp == _Unwind_GetGR (context, 13))
+	actions |= _UA_HANDLER_FRAME;
+      break;
+
+    case _US_UNWIND_FRAME_RESUME:
+      CONTINUE_UNWINDING;
+      break;
+
+    default:
+      abort();
+    }
+  actions |= state & _US_FORCE_UNWIND;
 
+  /* TODO: Foreign exceptions need some attention (e.g. rethrowing doesn't
+     work).  */
+  foreign_exception = 0;
+
+  /* The dwarf unwinder assumes the context structure holds things like the
+     function and LSDA pointers.  The ARM implementation caches these in
+     the exception header (UCB).  To avoid rewriting everything we make the
+     virtual IP register point at the UCB.  */
+  ip = (_Unwind_Ptr) ue_header;
+  _Unwind_SetGR (context, 12, ip);
+
+#else  /* !__ARM_EABI_UNWINDER.  */
   /* Interface version check.  */
   if (version != 1)
     return _URC_FATAL_PHASE1_ERROR;
+  
+  foreign_exception = (exception_class != __objc_exception_class);
+#endif
 
   /* Shortcut for phase 2 found handler for domestic exception.  */
   if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
-      && exception_class == __objc_exception_class)
+      && !foreign_exception)
     {
+#ifdef __ARM_EABI_UNWINDER__
+      handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
+      landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
+#else
       handler_switch_value = xh->handlerSwitchValue;
       landing_pad = xh->landingPad;
+#endif
       goto install_context;
     }
 
@@ -186,12 +287,18 @@ PERSONALITY_FUNCTION (int version,
 
   /* If no LSDA, then there are no handlers or cleanups.  */
   if (! language_specific_data)
-    return _URC_CONTINUE_UNWIND;
+    CONTINUE_UNWINDING;
 
   /* Parse the LSDA header.  */
   p = parse_lsda_header (context, language_specific_data, &info);
   info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
+#ifdef HAVE_GETIPINFO
+  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
   ip = _Unwind_GetIP (context) - 1;
+#endif
+  if (!ip_before_insn)
+    --ip;
   landing_pad = 0;
   action_record = 0;
   handler_switch_value = 0;
@@ -250,7 +357,7 @@ PERSONALITY_FUNCTION (int version,
   /* If ip is not present in the table, C++ would call terminate.  */
   /* ??? As with Java, it's perhaps better to tweek the LSDA to
      that no-action is mapped to no-entry.  */
-  return _URC_CONTINUE_UNWIND;
+  CONTINUE_UNWINDING;
 
  found_something:
   saw_cleanup = 0;
@@ -287,8 +394,7 @@ PERSONALITY_FUNCTION (int version,
 
 	  /* During forced unwinding, we only run cleanups.  With a
 	     foreign exception class, we have no class info to match.  */
-	  else if ((actions & _UA_FORCE_UNWIND)
-		   || exception_class != __objc_exception_class)
+	  else if ((actions & _UA_FORCE_UNWIND) || foreign_exception)
 	    ;
 
 	  else if (ar_filter > 0)
@@ -318,18 +424,24 @@ PERSONALITY_FUNCTION (int version,
     }
 
   if (! saw_handler && ! saw_cleanup)
-    return _URC_CONTINUE_UNWIND;
+    CONTINUE_UNWINDING;
 
   if (actions & _UA_SEARCH_PHASE)
     {
       if (!saw_handler)
-	return _URC_CONTINUE_UNWIND;
+	CONTINUE_UNWINDING;
 
       /* For domestic exceptions, we cache data from phase 1 for phase 2.  */
-      if (exception_class == __objc_exception_class)
+      if (!foreign_exception)
         {
+#ifdef __ARM_EABI_UNWINDER__
+	  ue_header->barrier_cache.sp = _Unwind_GetGR (context, 13);
+	  ue_header->barrier_cache.bitpattern[1] = (_uw) handler_switch_value;
+	  ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
+#else
           xh->handlerSwitchValue = handler_switch_value;
           xh->landingPad = landing_pad;
+#endif
 	}
       return _URC_HANDLER_FOUND;
     }
@@ -361,7 +473,9 @@ void
 objc_exception_throw (id value)
 {
   struct ObjcException *header = calloc (1, sizeof (*header));
-  header->base.exception_class = __objc_exception_class;
+  
+  memcpy (&header->base.exception_class, &__objc_exception_class,
+	  sizeof (__objc_exception_class));
   header->base.exception_cleanup = __objc_exception_cleanup;
   header->value = value;
 

Reply to: