This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

APCS ARM NPTL port


Similar to the EABI port, the only interesting bits here are EH related.  We
don't need unwind tables for cancellable syscalls, since this is
setjmp-longjmp based.  We do need custom versions of various files since the
names and set of required routines for EH are different (_Unwind_SjLj_Resume
for instance).

For best results, you need GCC 4.1, the two patches for SJLJ exception
handling that I posted to gcc-patches this week, and the testsuite patch I'm
going to post to libc-alpha next.  A couple of ELF tests fail; I believe
this is because they do not expect libgcc_s.so.1 to be loaded, which it is,
because of the wrapper for _Unwind_SjLj_Register.

Enjoy!

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-11-16  Daniel Jacobowitz  <dan@codesourcery.com>

	* sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h,
	sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c,
	sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c,
	sysdeps/unix/sysv/linux/arm/nptl/unwind.h,
	sysdeps/arm/unwind-dw2-fde-glibc.c,
	sysdeps/arm/unwind-pe.c, sysdeps/arm/framestate.c: New files.

Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/sysdep-cancel.h	2005-11-16 10:51:16.000000000 -0500
@@ -0,0 +1,128 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				\
+  .section ".text";							\
+    PSEUDO_PROLOGUE;							\
+  .type __##syscall_name##_nocancel,%function;				\
+  .globl __##syscall_name##_nocancel;					\
+  __##syscall_name##_nocancel:						\
+    DO_CALL (syscall_name, args);					\
+    PSEUDO_RET;								\
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	\
+  ENTRY (name);								\
+    SINGLE_THREAD_P;							\
+    DOARGS_##args;							\
+    bne .Lpseudo_cancel;						\
+    DO_CALL (syscall_name, 0);						\
+    UNDOARGS_##args;							\
+    cmn r0, $4096;							\
+    PSEUDO_RET;								\
+  .Lpseudo_cancel:							\
+    DOCARGS_##args;	/* save syscall args etc. around CENABLE.  */	\
+    CENABLE;								\
+    mov ip, r0;		/* put mask in safe place.  */			\
+    UNDOCARGS_##args;	/* restore syscall args.  */			\
+    swi SYS_ify (syscall_name);	/* do the call.  */			\
+    str r0, [sp, $-4]!; /* save syscall return value.  */		\
+    mov r0, ip;		/* get mask back.  */				\
+    CDISABLE;								\
+    ldmfd sp!, {r0, lr}; /* retrieve return value and address.  */	\
+    UNDOARGS_##args;							\
+    cmn r0, $4096;
+
+# define DOCARGS_0	str lr, [sp, #-4]!;
+# define UNDOCARGS_0
+
+# define DOCARGS_1	stmfd sp!, {r0, lr};
+# define UNDOCARGS_1	ldr r0, [sp], #4;
+
+# define DOCARGS_2	stmfd sp!, {r0, r1, lr};
+# define UNDOCARGS_2	ldmfd sp!, {r0, r1};
+
+# define DOCARGS_3	stmfd sp!, {r0, r1, r2, lr};
+# define UNDOCARGS_3	ldmfd sp!, {r0, r1, r2};
+
+# define DOCARGS_4	stmfd sp!, {r0, r1, r2, r3, lr};
+# define UNDOCARGS_4	ldmfd sp!, {r0, r1, r2, r3};
+
+# define DOCARGS_5	DOCARGS_4
+# define UNDOCARGS_5	UNDOCARGS_4
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	bl PLTJMP(__pthread_enable_asynccancel)
+#  define CDISABLE	bl PLTJMP(__pthread_disable_asynccancel)
+#  define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+#  define CENABLE	bl PLTJMP(__libc_enable_asynccancel)
+#  define CDISABLE	bl PLTJMP(__libc_disable_asynccancel)
+#  define __local_multiple_threads __libc_multiple_threads
+# elif defined IS_IN_librt
+#  define CENABLE	bl PLTJMP(__librt_enable_asynccancel)
+#  define CDISABLE	bl PLTJMP(__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# if defined IS_IN_libpthread || !defined NOT_IN_libc
+#  ifndef __ASSEMBLER__
+extern int __local_multiple_threads attribute_hidden;
+#   define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
+#  else
+#   define SINGLE_THREAD_P						\
+  ldr ip, 1b;								\
+2:									\
+  ldr ip, [pc, ip];							\
+  teq ip, #0;
+#   define PSEUDO_PROLOGUE						\
+  1:  .word __local_multiple_threads - 2f - 8;
+#  endif
+# else
+/*  There is no __local_multiple_threads for librt, so use the TCB.  */
+#  ifndef __ASSEMBLER__
+#   define SINGLE_THREAD_P						\
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\
+				   header.multiple_threads) == 0, 1)
+#  else
+#   define PSEUDO_PROLOGUE
+#   define SINGLE_THREAD_P						\
+  stmfd	sp!, {r0, lr};							\
+  bl	__aeabi_read_tp;						\
+  ldr	ip, [r0, #MULTIPLE_THREADS_OFFSET];				\
+  ldmfd	sp!, {r0, lr};							\
+  teq	ip, #0
+#   define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
+#  endif
+# endif
+
+#elif !defined __ASSEMBLER__
+
+/* For rtld, et cetera.  */
+# define SINGLE_THREAD_P 1
+# define NO_CANCELLATION 1
+
+#endif
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c	2005-11-16 10:51:16.000000000 -0500
@@ -0,0 +1,117 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unwind.h>
+#include <pthreadP.h>
+
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+   struct _Unwind_Context *);
+static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
+  (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
+static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
+static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *);
+static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *);
+
+void
+pthread_cancel_init (void)
+{
+  void *resume, *personality, *forcedunwind, *getcfa;
+  void *handle;
+  void *sjlj_register, *sjlj_unregister;
+
+  if (__builtin_expect (libgcc_s_getcfa != NULL, 1))
+    return;
+
+  handle = __libc_dlopen ("libgcc_s.so.1");
+
+  if (handle == NULL
+      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL
+      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL
+      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL
+      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL
+      || (forcedunwind = __libc_dlsym (handle, "_Unwind_SjLj_ForcedUnwind"))
+	 == NULL
+      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
+      )
+    __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n");
+
+  libgcc_s_resume = resume;
+  libgcc_s_personality = personality;
+  libgcc_s_forcedunwind = forcedunwind;
+  libgcc_s_getcfa = getcfa;
+  libgcc_s_sjlj_register = sjlj_register;
+  libgcc_s_sjlj_unregister = sjlj_unregister;
+}
+
+void
+_Unwind_Resume (struct _Unwind_Exception *exc)
+{
+  if (__builtin_expect (libgcc_s_resume == NULL, 0))
+    pthread_cancel_init ();
+  libgcc_s_resume (exc);
+}
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (int version, _Unwind_Action actions,
+		      _Unwind_Exception_Class exception_class,
+                      struct _Unwind_Exception *ue_header,
+                      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+    pthread_cancel_init ();
+  return libgcc_s_personality (version, actions, exception_class,
+			       ue_header, context);
+}
+
+_Unwind_Reason_Code
+_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
+		      void *stop_argument)
+{
+  if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0))
+    pthread_cancel_init ();
+  return libgcc_s_forcedunwind (exc, stop, stop_argument);
+}
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_getcfa == NULL, 0))
+    pthread_cancel_init ();
+  return libgcc_s_getcfa (context);
+}
+
+void
+_Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0))
+    pthread_cancel_init ();
+  libgcc_s_sjlj_register (fc);
+}
+
+void
+_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0))
+    pthread_cancel_init ();
+  libgcc_s_sjlj_unregister (fc);
+}
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c	2005-11-16 10:51:16.000000000 -0500
@@ -0,0 +1,87 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unwind.h>
+
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
+   struct _Unwind_Context *);
+static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *);
+static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *);
+
+static void
+init (void)
+{
+  void *resume, *personality;
+  void *handle;
+  void *sjlj_register, *sjlj_unregister;
+
+  handle = __libc_dlopen ("libgcc_s.so.1");
+
+  if (handle == NULL
+      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL
+      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL
+      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL
+      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL)
+    __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n");
+
+  libgcc_s_resume = resume;
+  libgcc_s_personality = personality;
+  libgcc_s_sjlj_register = sjlj_register;
+  libgcc_s_sjlj_unregister = sjlj_unregister;
+}
+
+void
+_Unwind_Resume (struct _Unwind_Exception *exc)
+{
+  if (__builtin_expect (libgcc_s_resume == NULL, 0))
+    init ();
+  libgcc_s_resume (exc);
+}
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (int version, _Unwind_Action actions,
+		      _Unwind_Exception_Class exception_class,
+                      struct _Unwind_Exception *ue_header,
+                      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+    init ();
+  return libgcc_s_personality (version, actions, exception_class,
+			       ue_header, context);
+}
+
+void
+_Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0))
+    init ();
+  libgcc_s_sjlj_register (fc);
+}
+
+void
+_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
+{
+  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0))
+    init ();
+  libgcc_s_sjlj_unregister (fc);
+}
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind.h	2005-11-16 10:51:16.000000000 -0500
@@ -0,0 +1,31 @@
+/* Exception handling and frame unwind runtime interface routines.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _ARM_UNWIND_H
+#define _ARM_UNWIND_H	1
+
+#include <sysdeps/generic/unwind.h>
+
+/* Call the SjLj versions of these functions.  */
+#define _Unwind_ForcedUnwind _Unwind_SjLj_ForcedUnwind
+#define _Unwind_Resume _Unwind_SjLj_Resume
+#define __gcc_personality_v0 __gcc_personality_sj0
+
+#endif	/* unwind.h */
Index: glibc/ports/sysdeps/arm/unwind-dw2-fde-glibc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/unwind-dw2-fde-glibc.c	2005-11-16 10:51:16.000000000 -0500
@@ -0,0 +1,80 @@
+/* Dummy exception handling and frame unwind runtime interface routines.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* ARM uses setjmp-longjmp exceptions.  However, previous versions of
+   GNU libc exported some DWARF-2 exception handling support routines.
+   They are not necessary, but older (or broken) configurations of GCC
+   will do so.  Even though all references to these are weak, because
+   they refer to versioned symbols, they must be provided.  */
+
+#include <stdlib.h>
+#include <unwind.h>
+#include <unwind-dw2-fde.h>
+
+/* These may be called from startup code, but don't need to do
+   anything.  */
+
+void __register_frame_info_bases (void *a1, struct object *a2,
+				  void *a3, void *a4)
+{
+}
+
+void __register_frame_info (void *a1, struct object *a2)
+{
+}
+
+void __register_frame (void *a1)
+{
+}
+
+void __register_frame_info_table_bases (void *a1, struct object *a2,
+					void *a3, void *a4)
+{
+}
+
+void __register_frame_info_table (void *a1, struct object *a2)
+{
+}
+
+void __register_frame_table (void *a1)
+{
+}
+
+void *__deregister_frame_info (void *a1)
+{
+  return NULL;
+}
+
+void *__deregister_frame_info_bases (void *a1)
+{
+  return NULL;
+}
+
+void __deregister_frame (void *a1)
+{
+}
+
+/* This should not be called.  */
+
+fde *
+_Unwind_Find_FDE (void *a1, struct dwarf_eh_bases *a2)
+{
+  abort ();
+}
Index: glibc/ports/sysdeps/arm/unwind-pe.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/unwind-pe.c	2005-11-16 10:51:16.000000000 -0500
@@ -0,0 +1 @@
+/* Empty */
Index: glibc/ports/sysdeps/arm/framestate.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/framestate.c	2005-11-16 10:51:16.000000000 -0500
@@ -0,0 +1 @@
+/* Empty */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]