Guys, I've been digging in gcc internals and succeeded in implementing stuff that allows us to write code such as int main(int argc, char *argv[]) __attribute__((__exception_handler__(handler))); to indicate that handler is the exception handler for function main.
The patch is attached, it only affects four files in gcc. What this gcc patch does is to generate an additional couple of lines of assembler code for those functions that have an exception handler. Attached is an example in C and the assembler code generated for it. In the arm-wince-mingw32ce world, only patches to gcc are required, no changes to any runtime are needed. (I need to look into the cegcc environment, things are slightly different there because a default exception handler is in place there.) Comments are welcome as always. Pedro, is it ok to commit this to SVN ? Danny -- Danny Backx ; danny.backx - at - scarlet.be ; http://danny.backx.info
#include <windows.h> #include <stdio.h> #include <stdlib.h> struct _DISPATCHER_CONTEXT; void handler(struct _EXCEPTION_RECORD *ExceptionRecord, void *EstablisherFrame, struct _CONTEXT *ContextRecord, struct _DISPATCHER_CONTEXT *DispatcherContext) { MessageBoxW(0, L"Crash Handler", L"WinCE Exception", 0); exit(0); } int main(int argc, char *argv[]) __attribute__((__exception_handler__(handler))); int main(int argc, char *argv[]) { int *i; i = 0; *i = 1; MessageBoxW(0, L"Main", L"Survived", 0); exit(0); }
.file "syntax.c" .section .rdata .align 0 .LC0: .ascii "C\000r\000a\000s\000h\000 \000H\000a\000n\000d\000l" .ascii "\000e\000r\000\000\000" .align 0 .LC1: .ascii "W\000i\000n\000C\000E\000 \000E\000x\000c\000e\000p" .ascii "\000t\000i\000o\000n\000\000\000" .text .align 0 .global handler .def handler; .scl 2; .type 32; .endef handler: @ args = 0, pretend = 0, frame = 16 @ frame_needed = 1, uses_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 sub sp, sp, #16 str r0, [fp, #-16] str r1, [fp, #-20] str r2, [fp, #-24] str r3, [fp, #-28] mov r0, #0 ldr r1, .L3 ldr r2, .L3+4 mov r3, #0 bl MessageBoxW mov r0, #0 bl exit .L4: .align 0 .L3: .word .LC0 .word .LC1 .def __gccmain; .scl 2; .type 32; .endef .section .rdata .align 0 .LC2: .ascii "M\000a\000i\000n\000\000\000" .align 0 .LC3: .ascii "S\000u\000r\000v\000i\000v\000e\000d\000\000\000" .text .align 0 .global main @ main has exception handler handler .section .pdata .word main .word 0xc0000002 | ((((_cegcc_main_end - main) / 4) & 0x3ffffff) << 8) /* _cegcc_main size */ .text @ .global _cegcc_main_data _cegcc_main_data: .word handler /* _cegcc_main_handler */ .word 0 /* _cegcc_main_handler_data */ .def main; .scl 2; .type 32; .endef main: @ args = 0, pretend = 0, frame = 12 @ frame_needed = 1, uses_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 sub sp, sp, #12 str r0, [fp, #-20] str r1, [fp, #-24] bl __gccmain mov r3, #0 str r3, [fp, #-16] ldr r2, [fp, #-16] mov r3, #1 str r3, [r2, #0] mov r0, #0 ldr r1, .L7 ldr r2, .L7+4 mov r3, #0 bl MessageBoxW mov r0, #0 bl exit .L8: .align 0 .L7: .word .LC2 .word .LC3 _cegcc_main_end: .def exit; .scl 2; .type 32; .endef .def MessageBoxW; .scl 2; .type 32; .endef
Index: gcc/gcc/c-common.c =================================================================== --- gcc/gcc/c-common.c (revision 1020) +++ gcc/gcc/c-common.c (working copy) @@ -505,6 +505,8 @@ static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree handle_always_inline_attribute (tree *, tree, tree, int, bool *); +static tree handle_exception_handler_attribute (tree *, tree, tree, int, + bool *); static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); static tree handle_used_attribute (tree *, tree, tree, int, bool *); static tree handle_unused_attribute (tree *, tree, tree, int, bool *); @@ -633,6 +635,8 @@ handle_cleanup_attribute }, { "warn_unused_result", 0, 0, false, true, true, handle_warn_unused_result_attribute }, + { "exception_handler", 1, 1, true, false, false, + handle_exception_handler_attribute }, { "sentinel", 0, 1, false, true, true, handle_sentinel_attribute }, { NULL, 0, 0, false, false, false, NULL } @@ -4216,6 +4220,59 @@ return NULL_TREE; } +/* + * Handle a "exception_handler" attribute. + * + * One argument is required : the name of a function to call in case of exceptions. + * Example syntax : + * + * int main(int argc, char *argv[]) + * __attribute__((__exception_handler__(handler))); + */ + +static tree +handle_exception_handler_attribute (tree *node, tree name, + tree args, + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + /* + * We need to pass the name of the exception handler. The + * right code then gets generated from config/arm/mingw32.h + * or similar, the assembler and linker will do the hard work. + * + * FIX ME We don't support passing data to the exception handler. + * + * This should be possible though, by using an additional argument + * which needs to fit in the dword (e.g. a pointer) and storing that + * in the right field as we do with the exception handler. + */ + + /* Handle mode attribute, handle_section_attribute, .. use args */ + tree id = TREE_VALUE (args); + tree attr = NULL_TREE; + + const char *x = IDENTIFIER_POINTER(id); + +#if 1 + attr = tree_cons (get_identifier ("exception_handler"), args, attr); +#else + /* Works too */ + attr = tree_cons (get_identifier ("exception_handler"), + build_string(strlen(x), x), attr); +#endif + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + /* Handle a "flatten" attribute; arguments as in struct attribute_spec.handler. */ Index: gcc/gcc/config/arm/arm.c =================================================================== --- gcc/gcc/config/arm/arm.c (revision 1020) +++ gcc/gcc/config/arm/arm.c (working copy) @@ -15553,4 +15553,31 @@ return (insn_flags & FL_THUMB) == FL_THUMB; } +/* + * called from + * #define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) + */ +char * +arm_exception_handler(FILE *fp, char *name, tree decl) +{ + tree attr, a2; + + attr = DECL_ATTRIBUTES(decl); + if (! attr) + return NULL; + a2 = lookup_attribute("__exception_handler__", attr); + if (! a2) + return NULL; + if (a2) { +#if 0 + fprintf(stderr, "Receive (arm_exception_handler) : \n"); + debug_tree(a2); + fprintf(stderr, "IP(TV(TV(a2))) %s\n", IDENTIFIER_POINTER(TREE_VALUE(TREE_VALUE(a2)))); +#endif + return IDENTIFIER_POINTER(TREE_VALUE(TREE_VALUE(a2))); + } + /* FIX ME */ + return NULL; +} + #include "gt-arm.h" Index: gcc/gcc/config/arm/mingw32.h =================================================================== --- gcc/gcc/config/arm/mingw32.h (revision 1020) +++ gcc/gcc/config/arm/mingw32.h (working copy) @@ -93,3 +93,55 @@ \ putc ('\"', asm_file); \ } while (0) + +/* + * An ARM specific header for function declarations. + * + * This one is needed for exception handlers : the entry in the pdata section + * needs to know the size of the function for which we handle exceptions. + */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ + do \ + { \ + char *eh; \ + eh = arm_exception_handler(STREAM, NAME, DECL); \ + if (eh) { \ + asm_fprintf (STREAM, "%@ %s has exception handler %s\n", \ + NAME, eh); \ + asm_fprintf (STREAM, "\t.section .pdata\n"); \ + asm_fprintf (STREAM, "\t.word %s\n", NAME); \ + asm_fprintf (STREAM, "\t.word 0xc0000002 | " \ + "((((_cegcc_%s_end - %s) / 4) & 0x3ffffff) << 8) " \ + "/* _cegcc_%s size */\n", NAME, NAME, NAME); \ + asm_fprintf (STREAM, "\t.text\n"); \ + asm_fprintf (STREAM, "@\t.global _cegcc_%s_data\n", NAME); \ + asm_fprintf (STREAM, "_cegcc_%s_data:\n", NAME); \ + asm_fprintf (STREAM, "\t.word %s /* _cegcc_%s_handler */\n", \ + eh, NAME); \ + asm_fprintf (STREAM, "\t.word 0 " \ + "/* _cegcc_%s_handler_data */\n", NAME); \ + } \ + if (arm_pe_dllexport_name_p (NAME)) \ + arm_pe_record_exported_symbol (NAME, 0); \ + if (write_symbols != SDB_DEBUG) \ + arm_pe_declare_function_type (STREAM, NAME, TREE_PUBLIC (DECL)); \ + ARM_DECLARE_FUNCTION_NAME (STREAM, NAME, DECL); \ + if (TARGET_THUMB) \ + fprintf (STREAM, "\t.code 16\n"); \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + } \ + while (0) + +/* + * An ARM specific trailer for function declarations. + * + * This one is needed for exception handlers : the entry in the pdata section + * needs to know the size of the function for which we handle exceptions. + */ +#undef ASM_DECLARE_FUNCTION_SIZE +#define ASM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL) \ + { \ + if (arm_exception_handler(STREAM, NAME, DECL)) \ + asm_fprintf (STREAM, "_cegcc_%s_end:\n", NAME); \ + } Index: gcc/gcc/config/arm/wince-cegcc.h =================================================================== --- gcc/gcc/config/arm/wince-cegcc.h (revision 1020) +++ gcc/gcc/config/arm/wince-cegcc.h (working copy) @@ -64,3 +64,55 @@ %{static:-Bstatic} %{!static:-Bdynamic} \ %{shared|mdll: -e DllMainCRTStartup} \ " + +/* + * An ARM specific header for function declarations. + * + * This one is needed for exception handlers : the entry in the pdata section + * needs to know the size of the function for which we handle exceptions. + */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \ + do \ + { \ + char *eh; \ + eh = arm_exception_handler(STREAM, NAME, DECL); \ + if (eh) { \ + asm_fprintf (STREAM, "%@ %s has exception handler %s\n", \ + NAME, eh); \ + asm_fprintf (STREAM, "\t.section .pdata\n"); \ + asm_fprintf (STREAM, "\t.word %s\n", NAME); \ + asm_fprintf (STREAM, "\t.word 0xc0000002 | " \ + "((((_cegcc_%s_end - %s) / 4) & 0x3ffffff) << 8) " \ + "/* _cegcc_%s size */\n", NAME, NAME, NAME); \ + asm_fprintf (STREAM, "\t.text\n"); \ + asm_fprintf (STREAM, "\t.global _cegcc_%s_data\n", NAME); \ + asm_fprintf (STREAM, "_cegcc_%s_data:\n", NAME); \ + asm_fprintf (STREAM, "\t.word %s /* _cegcc_%s_handler */\n", \ + eh, NAME); \ + asm_fprintf (STREAM, "\t.word 0 " \ + "/* _cegcc_%s_handler_data */\n", NAME); \ + } \ + if (arm_pe_dllexport_name_p (NAME)) \ + arm_pe_record_exported_symbol (NAME, 0); \ + if (write_symbols != SDB_DEBUG) \ + arm_pe_declare_function_type (STREAM, NAME, TREE_PUBLIC (DECL)); \ + ARM_DECLARE_FUNCTION_NAME (STREAM, NAME, DECL); \ + if (TARGET_THUMB) \ + fprintf (STREAM, "\t.code 16\n"); \ + ASM_OUTPUT_LABEL (STREAM, NAME); \ + } \ + while (0) + +/* + * An ARM specific trailer for function declarations. + * + * This one is needed for exception handlers : the entry in the pdata section + * needs to know the size of the function for which we handle exceptions. + */ +#undef ASM_DECLARE_FUNCTION_SIZE +#define ASM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL) \ + { \ + if (arm_exception_handler(STREAM, NAME, DECL)) \ + asm_fprintf (STREAM, "_cegcc_%s_end:\n", NAME); \ + }
signature.asc
Description: This is a digitally signed message part
------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________ Cegcc-devel mailing list Cegcc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/cegcc-devel