This is the mail archive of the crossgcc@sources.redhat.com mailing list for the crossgcc project.
See the CrossGCC FAQ for lots more information.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
On Thursday 12 May 2005 6:54 pm, Richard Sewards wrote: > Hi, > > Does support for C++ exceptions depend on the particular target GCC is > built for? there are two implementations of c++ exceptions, the setjump/longjump method, --enable-sjlj-exceptions, which works on all platforms but is very slow and crap and the libunwind method which is much better, faster but only works on certain platforms. there are many implications of c++ support, global constructors (are you using them ?), exception handling, rtti (for dynamic_cast) and implementing platform spesific locking in gcc. i would *really* recomend that you dont use c++ exceptions in embedded projects, however i did, but its quite a lot of work. i would recomend that you start by reading the code in gcc/unwind.XXX and preferably understanding it. > I have been building gcc for powerpc-unknown-eabi for a while and I have > been trying to get exceptions to work on our embedded target (which uses > a commercial RTOS). The compiler builds, my program builds and runs, > but when it throws an exception it crashes inside the libgcc exception > code and apparently it cannot find the exception frame. Is exception > handling disabled/unimplemented for powerpc-unknown-eabi targets, or > should I look elsewhere for the problem. i develop with an i486-unknown-elf target and a commerical RTOS (Nucleus in this case). Here are some pointers to what you need to do for c++ support. 1) for c++ exception support, using libunwind. // header from gcc, that defines the dwarf2 object format used for stack unwinding #include "unwind-dw2-fde.h" #define EH_FRAME_SECTION_ASM_OP ".section\t.eh_frame,\"aw\"" // pointer to begin of .eh_frame section extern "C" void * __eh_frame_start; static struct object object; // exception handling frame information __register_frame_info ((void *)&__eh_frame_start, &object); // test code try { try { try { throw (float) 1.2; } catch (float) { throw (int) 1; } } catch (int) { throw; } } catch (...) { double here; } 2) global constructors / destructors /* gas code to access elf sections */ #define CTORS_SECTION_ASM_OP ".section\t.ctors,\"aw\"" #define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\"" /* create a __CTOR_LIST__ from the section .dtors */ asm (CTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */ static void (* __CTOR_LIST__[1]) (void) __attribute__ ((section (".ctors"))) = { (void (*) (void)) -1 }; asm (".previous"); /* go back */ /* create a __DTOR_LIST__ from the section .dtors */ asm (DTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */ static void (* __DTOR_LIST__[1]) (void) __attribute__ ((section (".dtors"))) = { (void (*) (void)) -1 }; asm (".previous"); /* go back */ /* run global destructors */ static void __attribute__((used)) do_global_dtors_aux (void) { static func_ptr *p = __DTOR_LIST__ + 1; static bool completed =0; func_ptr f; if (completed) return; while ((f = *p)) { p++; f (); } // exception handling shutdown __deregister_frame_info ((void *)&__eh_frame_start); completed = 1; } /* run global constructors */ static void __attribute__((used)) do_global_ctors_aux (void) { static func_ptr *p = __CTOR_LIST__ + 1; static int completed = 0; if (completed) return; /* mjf - now run through and find end marker (null) and then execute the fuction pointers backwards, just like linux does :-) */ while ((*p) && (*p != (func_ptr)-1)) { p++; } // there is a trailing null, so go back one p--; // run all the functions in the list, right back to the start of list (0xfffffff) while (*p != (func_ptr)-1) { (*(p)) (); p--; } static struct object object; // exception handling frame information __register_frame_info ((void *)&__eh_frame_start, &object); completed = 1; } somepalce before main() call do_global_ctors_aux(); 3) threading and locks, you can either patch gcc to support your platform, or use an exisiting target to enable your platform spesific threads/locking system for your RTOS, (this is required for c++ exceptions). Here is my example code. --enable-threads=rtems // will be 2, if task switching started extern "C" INT INC_Initialize_State; /* avoid depedency on rtems specific headers */ typedef void *__gthread_key_t; typedef int __gthread_once_t; typedef void *__gthread_mutex_t; /* mutex support */ unsigned int rtems_gxx_mutex_lock_calls =0, rtems_gxx_mutex_trylock_calls =0, rtems_gxx_mutex_unlock_calls =0, rtems_gxx_mutex_init_calls =0; extern "C" void rtems_gxx_mutex_init(__gthread_mutex_t *mutex) { rtems_gxx_mutex_init_calls++; *mutex = malloc(sizeof(NU_SEMAPHORE)); NU_Create_Semaphore((NU_SEMAPHORE *)(*mutex), "GCC Sema", 1, NU_PRIORITY); } extern "C" int rtems_gxx_mutex_lock(__gthread_mutex_t *mutex) { rtems_gxx_mutex_lock_calls++; int Status = -1; if (INC_Initialize_State == 2) { if (NU_Obtain_Semaphore((NU_SEMAPHORE *)(*mutex), NU_SUSPEND) == NU_SUCCESS) { Status = 0; } } else { Status = 0; } return Status; } extern "C" int rtems_gxx_mutex_trylock(__gthread_mutex_t *mutex) { rtems_gxx_mutex_trylock_calls++; int Status = -1; if (INC_Initialize_State == 2) { // Don't currently own the lock see whether it can be obtained if (NU_Obtain_Semaphore((NU_SEMAPHORE *)(*mutex),NU_NO_SUSPEND) == NU_SUCCESS) { Status = 0; } } else { Status = 0; } return Status; } extern "C" int rtems_gxx_mutex_unlock(__gthread_mutex_t *mutex) { rtems_gxx_mutex_unlock_calls++; int Status = -1; if (INC_Initialize_State == 2) { if (NU_Release_Semaphore((NU_SEMAPHORE *)(*mutex)) == NU_SUCCESS) { Status = 0; } } else { Status = 0; } return Status; } // // file i/o locking functions for newlib // /* avoid depedency on newlib specific headers */ typedef void * _LOCK_T; typedef void * _LOCK_RECURSIVE_T; //#define __LOCK_INIT(class,lock) class _LOCK_T lock; //#define __LOCK_INIT_RECURSIVE(class,lock) class _LOCK_RECURSIVE_T lock; /* typedef struct stub_critical_section { NU_SEMAPHORE CriticalSection; // Locks the int count; NU_TASK * thread; critical_section() { CriticalSection.sm_id = 0; thread = NULL; count = 0; }; } CRITICAL_SECTION; */ // will be 2, if task switching started // extern "C" INT INC_Initialize_State; extern "C" void __local_lock_init(_LOCK_T lock) { if (INC_Initialize_State == 2) { // only first time if (*((void **)lock) == 0) { *((void **)lock) = malloc(sizeof(CRITICAL_SECTION)); SCXInitializeCriticalSection(*(CRITICAL_SECTION **)lock); } } } extern "C" void __local_lock_init_recursive(_LOCK_T lock) { if (INC_Initialize_State == 2) { // only first time if (*((void **)lock) == 0) { *((void **)lock) = malloc(sizeof(CRITICAL_SECTION)); SCXInitializeCriticalSection(*(CRITICAL_SECTION **)lock); } } } extern "C" void __local_lock_close(_LOCK_T lock) { if (INC_Initialize_State == 2) { SCXDeleteCriticalSection(*(CRITICAL_SECTION **)lock); // free when no longer held if ( (*(CRITICAL_SECTION **)lock)->count == 0) { free(*((void **)lock)); *((void **)lock) = 0; } } } extern "C" void __local_lock_close_recursive(_LOCK_T lock) { if (INC_Initialize_State == 2) { SCXDeleteCriticalSection(*(CRITICAL_SECTION **)lock); // free when no longer held if ( (*(CRITICAL_SECTION **)lock)->count == 0) { free(*((void **)lock)); *((void **)lock) = 0; } } } extern "C" void __local_lock_acquire(_LOCK_T lock) { if (INC_Initialize_State == 2) { SCXEnterCriticalSection(*(CRITICAL_SECTION **)lock); } } extern "C" void __local_lock_acquire_recursive(_LOCK_T lock) { if (INC_Initialize_State == 2) { SCXEnterCriticalSection(*(CRITICAL_SECTION **)lock); } } /* not used by newlib extern "C" int __lock_try_acquire(_LOCK_T lock) { } extern "C" int __lock_try_acquire_recursive(_LOCK_T lock) { } */ extern "C" void __local_lock_release(_LOCK_T lock) { if (INC_Initialize_State == 2) { SCXLeaveCriticalSection(*(CRITICAL_SECTION **)lock); } } extern "C" void __local_lock_release_recursive(_LOCK_T lock) { if (INC_Initialize_State == 2) { SCXLeaveCriticalSection(*(CRITICAL_SECTION **)lock); } } note the SCX?? calls allow reqursive calls, and the NU (Nucleus) ones dont. > I did not use crosstool to build gcc, but I suspect that this list is > the best place to ask. regards --- Matthew J Fletcher Embedded Software Serck Controls Ltd --- ********************************************************************** Serck Controls Ltd, Rowley Drive, Coventry, CV3 4FH, UK Tel: +44 (0) 24 7630 5050 Fax: +44 (0) 24 7630 2437 Web: www.serck-controls.com Admin: post@serck-controls.co.uk A subsidiary of Serck Controls Pty. Ltd. Reg. in England No. 4353634 ********************************************************************** This email and files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the above. Any views or opinions presented are those of the author and do not necessarily represent those of Serck Controls Ltd. This message has been checked by MessageLabs ****************************************************************** ------ Want more information? See the CrossGCC FAQ, http://www.objsw.com/CrossGCC/ Want to unsubscribe? Send a note to crossgcc-unsubscribe@sources.redhat.com
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |