diff --git a/runtime/GCCLibraries/crtend/C++-Exception.cpp b/runtime/GCCLibraries/crtend/C++-Exception.cpp new file mode 100644 index 00000000000..7ed78688eaa --- /dev/null +++ b/runtime/GCCLibraries/crtend/C++-Exception.cpp @@ -0,0 +1,223 @@ +//===- c++-exception.cpp - Exception handling support for C++ exceptions --===// +// +// This file defines the methods used to implement C++ exception handling in +// terms of the invoke and %llvm.unwind intrinsic. These primitives implement +// an exception handling ABI similar (but simpler and more efficient than) the +// Itanium C++ ABI exception handling standard. +// +//===----------------------------------------------------------------------===// + +#include "c++-exception.h" +#include +#include + +//===----------------------------------------------------------------------===// +// Generic exception support +// + +// Thread local state for exception handling. +// FIXME: This should really be made thread-local! +// +static llvm_exception *CaughtExceptionStack = 0; + +// UncaughtExceptionStack - The stack of exceptions currently being thrown. +static llvm_exception *UncaughtExceptionStack = 0; + +// __llvm_eh_has_uncaught_exception - This is used to implement +// std::uncaught_exception. +// +bool __llvm_eh_has_uncaught_exception(void) { + return UncaughtExceptionStack != 0; +} + +// __llvm_eh_current_uncaught_exception - This function checks to see if the +// current uncaught exception is of the specified language type. If so, it +// returns a pointer to the exception area data. +// +void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType) { + assert(UncaughtExceptionStack && "No uncaught exception!"); + if (UncaughtExceptionStack->ExceptionType == HandlerType) + return UncaughtExceptionStack+1; + return 0; +} + + +/*===----------------------------------------------------------------------===** + * C++ Specific exception handling support... + */ + +// __llvm_cxxeh_allocate_exception - This function allocates space for the +// specified number of bytes, plus a C++ exception object header. +// +void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) { + // FIXME: This should eventually have back-up buffers for out-of-memory + // situations. + // + llvm_cxx_exception *E = + (llvm_cxx_exception *)malloc(NumBytes+sizeof(llvm_cxx_exception)); + E->BaseException.ExceptionType = 0; // intialize to invalid + + return E+1; // return the pointer after the header +} + +// __llvm_cxxeh_free_exception - Low-level function to free an exception. This +// is called directly from generated C++ code if evaluating the exception value +// into the exception location throws. Otherwise it is called from the C++ +// exception object destructor. +// +void __llvm_cxxeh_free_exception(void *ObjectPtr) { + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + free(E); +} + +// cxx_destructor - This function is called through the generic +// exception->ExceptionDestructor function pointer to destroy a caught +// exception. +// +static void cxx_destructor(llvm_exception *LE) { + void *ObjectPtr = LE+1; + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + + // The exception is no longer caught. + assert(CaughtExceptionStack == LE && + "Destroying an exception which is not the current caught exception?"); + CaughtExceptionStack = LE->Next; + + struct ExceptionFreer { + void *Ptr; + ExceptionFreer(void *P) : Ptr(P) {} + ~ExceptionFreer() { + // Free the memory for the exception, when the function is left, even if + // the exception object dtor throws its own exception! + __llvm_cxxeh_free_exception(Ptr); + } + } EF(E+1); + + // Run the exception object dtor if it exists. */ + if (E->ExceptionObjectDestructor) + E->ExceptionObjectDestructor(E); +} + +// __llvm_cxxeh_throw - Given a pointer to memory which has an exception object +// evaluated into it, this sets up all of the fields of the exception allowing +// it to be thrown. After calling this, the code should call %llvm.unwind +// +void __llvm_cxxeh_throw(void *ObjectPtr, const std::type_info *TypeInfoPtr, + void (*DtorPtr)(void*)) { + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + E->BaseException.ExceptionDestructor = cxx_destructor; + E->BaseException.ExceptionType = CXXException; + E->BaseException.Next = UncaughtExceptionStack; + UncaughtExceptionStack = &E->BaseException; + E->BaseException.HandlerCount = 0; + + E->TypeInfo = TypeInfoPtr; + E->ExceptionObjectDestructor = DtorPtr; + E->UnexpectedHandler = 0; /* FIXME */ + E->TerminateHandler = 0; /* FIXME */ +} + +// __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if +// the current uncaught exception is a C++ exception, and if it is of the +// specified type id. If so, it returns a pointer to the object adjusted as +// appropriate, otherwise it returns null. +// +void *__llvm_cxxeh_current_uncaught_exception_isa( + const std::type_info *CatchType) { + assert(UncaughtExceptionStack && "No uncaught exception!"); + if (UncaughtExceptionStack->ExceptionType != CXXException) + return 0; /* If it's not a c++ exception, it doesn't match! */ + + // If it is a C++ exception, use the type info object stored in the exception + // to see if TypeID matches and, if so, to adjust the exception object + // pointer. + // + llvm_cxx_exception *E = (llvm_cxx_exception*)UncaughtExceptionStack; + + // ThrownPtr is a pointer to the object being thrown... + void *ThrownPtr = E+1; + const std::type_info *ThrownType = E->TypeInfo; + + // FIXME: this code exists in the GCC exception handling library: I haven't + // thought about this yet, so it should be verified at some point! +#if 1 + // Pointer types need to adjust the actual pointer, not + // the pointer to pointer that is the exception object. + // This also has the effect of passing pointer types + // "by value" through the __cxa_begin_catch return value. + if (ThrownType->__is_pointer_p()) + ThrownPtr = *(void **)ThrownPtr; +#endif + + if (CatchType->__do_catch(ThrownType, &ThrownPtr, 1)) + return ThrownPtr; + + return 0; +} + + +/* __llvm_cxxeh_begin_catch - This function is called by "exception handlers", + * which transition an exception from being uncaught to being caught. It + * returns a pointer to the exception object portion of the exception. This + * function must work with foreign exceptions. + */ +void *__llvm_cxxeh_begin_catch(void) { + llvm_exception *E = UncaughtExceptionStack; + assert(UncaughtExceptionStack && "There are no uncaught exceptions!?!?"); + + /* The exception is now no longer uncaught... */ + UncaughtExceptionStack = E->Next; + + /* The exception is now caught... */ + E->Next = CaughtExceptionStack; + CaughtExceptionStack = E->Next; + + /* Increment the handler count for this exception. */ + E->HandlerCount++; + + /* Return a pointer to the exception object */ + return E+1; +} + +/* __llvm_cxxeh_end_catch - This function decrements the HandlerCount of the + * top-level caught exception, destroying it if this is the last handler for the + * exception. + */ +void __llvm_cxxeh_end_catch(void) { + llvm_exception *E = CaughtExceptionStack; + assert(E && "There are no caught exceptions!"); + + /* If this is the last handler using the exception, destroy it now! */ + if (--E->HandlerCount == 0) { + CaughtExceptionStack = E->Next; /* Unlink from the stack */ + E->ExceptionDestructor(E); /* Release memory for the exception */ + } +} + +/* __llvm_cxxeh_rethrow - This function turns the top-level caught exception + * into an uncaught exception, in preparation for an llvm.unwind, which should + * follow immediately after the call to this function. This function must be + * prepared to deal with foreign exceptions. + */ +void __llvm_cxxeh_rethrow(void) { + llvm_exception *E = CaughtExceptionStack; + if (E == 0) { + /* 15.1.8 - If there are no uncaught exceptions being thrown, 'throw;' + * should call terminate. + */ + /* FIXME */assert(0 && "FIXME: this should call E->Terminate!"); + } + + /* Otherwise we have an exception to rethrow. Move it back to the uncaught + * stack. + */ + CaughtExceptionStack = E->Next; + E->Next = UncaughtExceptionStack; + UncaughtExceptionStack = E; + + /* Decrement the number of handlers which are using the exception. */ + --E->HandlerCount; + + /* Return to the caller, which should perform the unwind now. */ +} + diff --git a/runtime/GCCLibraries/crtend/C++-Exception.h b/runtime/GCCLibraries/crtend/C++-Exception.h new file mode 100644 index 00000000000..cc37294572e --- /dev/null +++ b/runtime/GCCLibraries/crtend/C++-Exception.h @@ -0,0 +1,62 @@ +//===- c++-exception.h - C++ Specific exception Handling --------*- C++ -*-===// +// +// This file defines the data structures and API used by the C++ exception +// handling runtime library. +// +//===----------------------------------------------------------------------===// + +#ifndef CXX_EXCEPTION_H +#define CXX_EXCEPTION_H + +#include "exception.h" +#include + +typedef struct llvm_cxx_exception { + /* TypeInfo - A pointer to the C++ std::type_info object for this exception + * class. This is required because the class may not be polymorphic. + */ + const std::type_info *TypeInfo; + + /* ExceptionObjectDestructor - A pointer to the function which destroys the + * object represented by this exception. This is required because the class + * may not be polymorphic. This may be null if there is no cleanup required. + */ + void (*ExceptionObjectDestructor)(void *); + + /* UnexpectedHandler - This contains a pointer to the "unexpected" handler + * which may be registered by the user program with set_unexpected. Calls to + * unexpected which are a result of an exception throw are supposed to use the + * value of the handler at the time of the throw, not the currently set value. + */ + void *UnexpectedHandler; + + /* TerminateHandler - This contains a pointer to the "terminate" handler which + * may be registered by the user program with set_terminate. Calls to + * unexpected which are a result of an exception throw are supposed to use the + * value of the handler at the time of the throw, not the currently set value. + */ + void *TerminateHandler; + + /* BaseException - The language independent portion of the exception state. + * This is at the end of the record so that we can add additional members to + * this structure without breaking binary compatibility. + */ + llvm_exception BaseException; +} llvm_cxx_exception; + + + +extern "C" { + void *__llvm_cxxeh_allocate_exception(unsigned NumBytes); + void __llvm_cxxeh_free_exception(void *ObjectPtr); + void __llvm_cxxeh_throw(void *ObjectPtr, const std::type_info *TypeInfoPtr, + void (*DtorPtr)(void*)); + + void * __llvm_cxxeh_current_uncaught_exception_isa(const std::type_info *Ty); + void *__llvm_cxxeh_begin_catch(void); + void __llvm_cxxeh_end_catch(void); + + void __llvm_cxxeh_rethrow(void); +} + +#endif diff --git a/runtime/GCCLibraries/crtend/Exception.h b/runtime/GCCLibraries/crtend/Exception.h new file mode 100644 index 00000000000..a0357b54c54 --- /dev/null +++ b/runtime/GCCLibraries/crtend/Exception.h @@ -0,0 +1,49 @@ +//===- exception.h - Generic language-independent exceptions ----*- C++ -*-===// +// +// This file defines the the shared data structures used by all language +// specific exception handling runtime libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef EXCEPTION_H +#define EXCEPTION_H + +typedef struct llvm_exception { + // ExceptionDestructor - This call-back function is used to destroy the + // current exception, without requiring the caller to know what the concrete + // exception type is. + // + void (*ExceptionDestructor)(struct llvm_exception *); + + // ExceptionType - This field identifies what runtime library this exception + // came from. Currently defined values are: + // 0 - Error + // 1 - longjmp exception (see longjmp-exception.c) + // 2 - C++ exception (see c++-exception.c) + // + unsigned ExceptionType; + + // Next - This points to the next exception in the current stack. + struct llvm_exception *Next; + + // HandlerCount - This is a count of the number of handlers which have + // currently caught this exception. If the handler is caught and this number + // falls to zero, the exception is destroyed. + // + unsigned HandlerCount; +} llvm_exception; + +enum { + ErrorException = 0, + LongjmpException = 1, + CXXException = 2, +}; + +// Language independent exception handling API... +// +extern "C" { + bool __llvm_eh_has_uncaught_exception(void); + void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType); +} + +#endif diff --git a/runtime/GCCLibraries/libexception/C++-Exception.cpp b/runtime/GCCLibraries/libexception/C++-Exception.cpp new file mode 100644 index 00000000000..7ed78688eaa --- /dev/null +++ b/runtime/GCCLibraries/libexception/C++-Exception.cpp @@ -0,0 +1,223 @@ +//===- c++-exception.cpp - Exception handling support for C++ exceptions --===// +// +// This file defines the methods used to implement C++ exception handling in +// terms of the invoke and %llvm.unwind intrinsic. These primitives implement +// an exception handling ABI similar (but simpler and more efficient than) the +// Itanium C++ ABI exception handling standard. +// +//===----------------------------------------------------------------------===// + +#include "c++-exception.h" +#include +#include + +//===----------------------------------------------------------------------===// +// Generic exception support +// + +// Thread local state for exception handling. +// FIXME: This should really be made thread-local! +// +static llvm_exception *CaughtExceptionStack = 0; + +// UncaughtExceptionStack - The stack of exceptions currently being thrown. +static llvm_exception *UncaughtExceptionStack = 0; + +// __llvm_eh_has_uncaught_exception - This is used to implement +// std::uncaught_exception. +// +bool __llvm_eh_has_uncaught_exception(void) { + return UncaughtExceptionStack != 0; +} + +// __llvm_eh_current_uncaught_exception - This function checks to see if the +// current uncaught exception is of the specified language type. If so, it +// returns a pointer to the exception area data. +// +void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType) { + assert(UncaughtExceptionStack && "No uncaught exception!"); + if (UncaughtExceptionStack->ExceptionType == HandlerType) + return UncaughtExceptionStack+1; + return 0; +} + + +/*===----------------------------------------------------------------------===** + * C++ Specific exception handling support... + */ + +// __llvm_cxxeh_allocate_exception - This function allocates space for the +// specified number of bytes, plus a C++ exception object header. +// +void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) { + // FIXME: This should eventually have back-up buffers for out-of-memory + // situations. + // + llvm_cxx_exception *E = + (llvm_cxx_exception *)malloc(NumBytes+sizeof(llvm_cxx_exception)); + E->BaseException.ExceptionType = 0; // intialize to invalid + + return E+1; // return the pointer after the header +} + +// __llvm_cxxeh_free_exception - Low-level function to free an exception. This +// is called directly from generated C++ code if evaluating the exception value +// into the exception location throws. Otherwise it is called from the C++ +// exception object destructor. +// +void __llvm_cxxeh_free_exception(void *ObjectPtr) { + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + free(E); +} + +// cxx_destructor - This function is called through the generic +// exception->ExceptionDestructor function pointer to destroy a caught +// exception. +// +static void cxx_destructor(llvm_exception *LE) { + void *ObjectPtr = LE+1; + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + + // The exception is no longer caught. + assert(CaughtExceptionStack == LE && + "Destroying an exception which is not the current caught exception?"); + CaughtExceptionStack = LE->Next; + + struct ExceptionFreer { + void *Ptr; + ExceptionFreer(void *P) : Ptr(P) {} + ~ExceptionFreer() { + // Free the memory for the exception, when the function is left, even if + // the exception object dtor throws its own exception! + __llvm_cxxeh_free_exception(Ptr); + } + } EF(E+1); + + // Run the exception object dtor if it exists. */ + if (E->ExceptionObjectDestructor) + E->ExceptionObjectDestructor(E); +} + +// __llvm_cxxeh_throw - Given a pointer to memory which has an exception object +// evaluated into it, this sets up all of the fields of the exception allowing +// it to be thrown. After calling this, the code should call %llvm.unwind +// +void __llvm_cxxeh_throw(void *ObjectPtr, const std::type_info *TypeInfoPtr, + void (*DtorPtr)(void*)) { + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + E->BaseException.ExceptionDestructor = cxx_destructor; + E->BaseException.ExceptionType = CXXException; + E->BaseException.Next = UncaughtExceptionStack; + UncaughtExceptionStack = &E->BaseException; + E->BaseException.HandlerCount = 0; + + E->TypeInfo = TypeInfoPtr; + E->ExceptionObjectDestructor = DtorPtr; + E->UnexpectedHandler = 0; /* FIXME */ + E->TerminateHandler = 0; /* FIXME */ +} + +// __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if +// the current uncaught exception is a C++ exception, and if it is of the +// specified type id. If so, it returns a pointer to the object adjusted as +// appropriate, otherwise it returns null. +// +void *__llvm_cxxeh_current_uncaught_exception_isa( + const std::type_info *CatchType) { + assert(UncaughtExceptionStack && "No uncaught exception!"); + if (UncaughtExceptionStack->ExceptionType != CXXException) + return 0; /* If it's not a c++ exception, it doesn't match! */ + + // If it is a C++ exception, use the type info object stored in the exception + // to see if TypeID matches and, if so, to adjust the exception object + // pointer. + // + llvm_cxx_exception *E = (llvm_cxx_exception*)UncaughtExceptionStack; + + // ThrownPtr is a pointer to the object being thrown... + void *ThrownPtr = E+1; + const std::type_info *ThrownType = E->TypeInfo; + + // FIXME: this code exists in the GCC exception handling library: I haven't + // thought about this yet, so it should be verified at some point! +#if 1 + // Pointer types need to adjust the actual pointer, not + // the pointer to pointer that is the exception object. + // This also has the effect of passing pointer types + // "by value" through the __cxa_begin_catch return value. + if (ThrownType->__is_pointer_p()) + ThrownPtr = *(void **)ThrownPtr; +#endif + + if (CatchType->__do_catch(ThrownType, &ThrownPtr, 1)) + return ThrownPtr; + + return 0; +} + + +/* __llvm_cxxeh_begin_catch - This function is called by "exception handlers", + * which transition an exception from being uncaught to being caught. It + * returns a pointer to the exception object portion of the exception. This + * function must work with foreign exceptions. + */ +void *__llvm_cxxeh_begin_catch(void) { + llvm_exception *E = UncaughtExceptionStack; + assert(UncaughtExceptionStack && "There are no uncaught exceptions!?!?"); + + /* The exception is now no longer uncaught... */ + UncaughtExceptionStack = E->Next; + + /* The exception is now caught... */ + E->Next = CaughtExceptionStack; + CaughtExceptionStack = E->Next; + + /* Increment the handler count for this exception. */ + E->HandlerCount++; + + /* Return a pointer to the exception object */ + return E+1; +} + +/* __llvm_cxxeh_end_catch - This function decrements the HandlerCount of the + * top-level caught exception, destroying it if this is the last handler for the + * exception. + */ +void __llvm_cxxeh_end_catch(void) { + llvm_exception *E = CaughtExceptionStack; + assert(E && "There are no caught exceptions!"); + + /* If this is the last handler using the exception, destroy it now! */ + if (--E->HandlerCount == 0) { + CaughtExceptionStack = E->Next; /* Unlink from the stack */ + E->ExceptionDestructor(E); /* Release memory for the exception */ + } +} + +/* __llvm_cxxeh_rethrow - This function turns the top-level caught exception + * into an uncaught exception, in preparation for an llvm.unwind, which should + * follow immediately after the call to this function. This function must be + * prepared to deal with foreign exceptions. + */ +void __llvm_cxxeh_rethrow(void) { + llvm_exception *E = CaughtExceptionStack; + if (E == 0) { + /* 15.1.8 - If there are no uncaught exceptions being thrown, 'throw;' + * should call terminate. + */ + /* FIXME */assert(0 && "FIXME: this should call E->Terminate!"); + } + + /* Otherwise we have an exception to rethrow. Move it back to the uncaught + * stack. + */ + CaughtExceptionStack = E->Next; + E->Next = UncaughtExceptionStack; + UncaughtExceptionStack = E; + + /* Decrement the number of handlers which are using the exception. */ + --E->HandlerCount; + + /* Return to the caller, which should perform the unwind now. */ +} + diff --git a/runtime/GCCLibraries/libexception/C++-Exception.h b/runtime/GCCLibraries/libexception/C++-Exception.h new file mode 100644 index 00000000000..cc37294572e --- /dev/null +++ b/runtime/GCCLibraries/libexception/C++-Exception.h @@ -0,0 +1,62 @@ +//===- c++-exception.h - C++ Specific exception Handling --------*- C++ -*-===// +// +// This file defines the data structures and API used by the C++ exception +// handling runtime library. +// +//===----------------------------------------------------------------------===// + +#ifndef CXX_EXCEPTION_H +#define CXX_EXCEPTION_H + +#include "exception.h" +#include + +typedef struct llvm_cxx_exception { + /* TypeInfo - A pointer to the C++ std::type_info object for this exception + * class. This is required because the class may not be polymorphic. + */ + const std::type_info *TypeInfo; + + /* ExceptionObjectDestructor - A pointer to the function which destroys the + * object represented by this exception. This is required because the class + * may not be polymorphic. This may be null if there is no cleanup required. + */ + void (*ExceptionObjectDestructor)(void *); + + /* UnexpectedHandler - This contains a pointer to the "unexpected" handler + * which may be registered by the user program with set_unexpected. Calls to + * unexpected which are a result of an exception throw are supposed to use the + * value of the handler at the time of the throw, not the currently set value. + */ + void *UnexpectedHandler; + + /* TerminateHandler - This contains a pointer to the "terminate" handler which + * may be registered by the user program with set_terminate. Calls to + * unexpected which are a result of an exception throw are supposed to use the + * value of the handler at the time of the throw, not the currently set value. + */ + void *TerminateHandler; + + /* BaseException - The language independent portion of the exception state. + * This is at the end of the record so that we can add additional members to + * this structure without breaking binary compatibility. + */ + llvm_exception BaseException; +} llvm_cxx_exception; + + + +extern "C" { + void *__llvm_cxxeh_allocate_exception(unsigned NumBytes); + void __llvm_cxxeh_free_exception(void *ObjectPtr); + void __llvm_cxxeh_throw(void *ObjectPtr, const std::type_info *TypeInfoPtr, + void (*DtorPtr)(void*)); + + void * __llvm_cxxeh_current_uncaught_exception_isa(const std::type_info *Ty); + void *__llvm_cxxeh_begin_catch(void); + void __llvm_cxxeh_end_catch(void); + + void __llvm_cxxeh_rethrow(void); +} + +#endif diff --git a/runtime/GCCLibraries/libexception/Exception.h b/runtime/GCCLibraries/libexception/Exception.h new file mode 100644 index 00000000000..a0357b54c54 --- /dev/null +++ b/runtime/GCCLibraries/libexception/Exception.h @@ -0,0 +1,49 @@ +//===- exception.h - Generic language-independent exceptions ----*- C++ -*-===// +// +// This file defines the the shared data structures used by all language +// specific exception handling runtime libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef EXCEPTION_H +#define EXCEPTION_H + +typedef struct llvm_exception { + // ExceptionDestructor - This call-back function is used to destroy the + // current exception, without requiring the caller to know what the concrete + // exception type is. + // + void (*ExceptionDestructor)(struct llvm_exception *); + + // ExceptionType - This field identifies what runtime library this exception + // came from. Currently defined values are: + // 0 - Error + // 1 - longjmp exception (see longjmp-exception.c) + // 2 - C++ exception (see c++-exception.c) + // + unsigned ExceptionType; + + // Next - This points to the next exception in the current stack. + struct llvm_exception *Next; + + // HandlerCount - This is a count of the number of handlers which have + // currently caught this exception. If the handler is caught and this number + // falls to zero, the exception is destroyed. + // + unsigned HandlerCount; +} llvm_exception; + +enum { + ErrorException = 0, + LongjmpException = 1, + CXXException = 2, +}; + +// Language independent exception handling API... +// +extern "C" { + bool __llvm_eh_has_uncaught_exception(void); + void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType); +} + +#endif diff --git a/runtime/GCCLibraries/libexception/Makefile b/runtime/GCCLibraries/libexception/Makefile new file mode 100644 index 00000000000..3715b143093 --- /dev/null +++ b/runtime/GCCLibraries/libexception/Makefile @@ -0,0 +1,17 @@ +LEVEL = ../../.. +BYTECODE_LIBRARY=1 +DONT_BUILD_RELINKED=1 +LIBRARYNAME=exception + +#Source = crtend.c listend.ll + +###EXPORTED_SYMBOL_LIST = __main,llvm.global_ctors,llvm.global_dtors + +include $(LEVEL)/Makefile.common + + +$(LLVMGCCDIR)/bytecode-libs/crtend.o: $(LIBNAME_BC) + @cp $< $@ + +install:: $(LLVMGCCDIR)/bytecode-libs/crtend.o + @rm $(LLVMGCCDIR)/bytecode-libs/libcrtend.bc