@@ -2413,8 +2413,12 @@ func struct emit_location *emit_intrinsic(struct context *context, struct ast_fu
24132413 emit (0xcc );
24142414 return emit_location_invalid (context );
24152415 }else if (string_match (identifier , string ("_AddressOfReturnAddress" ))){
2416- struct emit_location * return_address = emit_location_stack_relative (context , - (8 + 8 * /*amount_of_saved_registers*/ 2 ), /*size*/ 8 );
2416+ struct emit_location * return_address = emit_location_stack_relative (context , - (8 * ( s32 ) __popcnt ( context -> current_function -> pushed_register_mask ) ), /*size*/ 8 );
24172417 return emit_load_address (context , return_address , allocate_register (context , REGISTER_KIND_gpr ));
2418+ }else if (string_match (identifier , string ("_exception_info" ))){
2419+ return emit_location_loaded (context , REGISTER_KIND_gpr , REGISTER_R13 , 8 );
2420+ }else if (string_match (identifier , string ("_exception_code" ))){
2421+ return emit_location_loaded (context , REGISTER_KIND_gpr , REGISTER_R12 , 4 );
24182422 }else {
24192423 invalid_code_path ;
24202424 }
@@ -4755,15 +4759,31 @@ func void emit_code_for_function(struct context *context, struct ast_function *f
47554759 // maybe the large struct code should live in the epilog?
47564760 // @incomplete: we do not honor the calling convention here...
47574761 // @WARNING: If you change this code you have to also change the implementation of `_AddressOfReturnAddress`.
4758- s32 amount_of_saved_registers = 2 ;
4762+
4763+ if (function -> type -> flags & FUNCTION_TYPE_FLAGS_is_seh_filter ){
4764+ emit (0x41 ); emit (0x55 ); // push r13
4765+ emit (0x41 ); emit (0x54 ); // push r12
4766+ function -> pushed_register_mask |= (1 << REGISTER_R12 ) | (1 << REGISTER_R13 );
4767+ }
4768+
47594769 emit (PUSH_REGISTER_DI );
47604770 emit (PUSH_REGISTER_SI );
4771+ emit (PUSH_REGISTER_BP );
47614772
4762- function -> pushed_register_mask = (1 << REGISTER_SI ) | (1 << REGISTER_DI ) | (1 << REGISTER_BP );
4773+ function -> pushed_register_mask | = (1 << REGISTER_SI ) | (1 << REGISTER_DI ) | (1 << REGISTER_BP );
47634774
4764- emit ( PUSH_REGISTER_BP ) ;
4775+ s32 amount_of_saved_registers = __popcnt ( function -> pushed_register_mask ) - /*rbp*/ 1 ;
47654776 emit_reg_reg__ (context , REXW , MOVE_REG_REGM , REGISTER_BP , REGISTER_SP );
47664777
4778+ if (function -> type -> flags & FUNCTION_TYPE_FLAGS_is_seh_filter ){
4779+ // mov r13, rdx
4780+ // mov r12, [rdx]
4781+ // mov r12d, [r12]
4782+ emit (0x49 ); emit (0x89 ); emit (0xcd );
4783+ emit (0x4c ); emit (0x8b ); emit (0x21 );
4784+ emit (0x45 ); emit (0x8b ); emit (0x24 ); emit (0x24 );
4785+ }
4786+
47674787 {
47684788 // at this point we have pushed rbp so the memory layout is as follows:
47694789 // | memory for the function | old rbp | saved non-volitiles | ret ptr | arg0 | arg1 | arg2 | ...
@@ -4921,6 +4941,11 @@ func void emit_code_for_function(struct context *context, struct ast_function *f
49214941 emit (POP_REGISTER_SI );
49224942 emit (POP_REGISTER_DI );
49234943
4944+ if (function -> type -> flags & FUNCTION_TYPE_FLAGS_is_seh_filter ){
4945+ emit (0x41 ); emit (0x5c ); // push r12
4946+ emit (0x41 ); emit (0x5d ); // push r13
4947+ }
4948+
49244949 emit (NEAR_RET_INSTRUCTION );
49254950
49264951 if (context -> alloca_patch_nodes .first ){
0 commit comments