Skip to content

Commit 02ea6ec

Browse files
author
Pascal Beyer
committed
Fix unwind information and implement _exception_code and _exception_info intrinsics. wasm3 now compiles.
1 parent d33a40b commit 02ea6ec

File tree

3 files changed

+51
-8
lines changed

3 files changed

+51
-8
lines changed

examples/wasm3.bat

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
git clone https://github.com/wasm3/wasm3.git --recursive --depth 1 --branch v0.5.0
3+
cd wasm3 || exit /b 1
4+
5+
git clean -xdf
6+
7+
cmake -B build -G Ninja -D CMAKE_C_COMPILER="%~dp0..\hlc.exe" || exit /b 1
8+
cd build || exit /b 1
9+
10+
ninja || exit /b 1
11+
12+
cd ..\..

src/emit_x64.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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){

src/obj_writer.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -862,19 +862,25 @@ func void *push_unwind_information_for_function(struct memory_arena *arena, stru
862862
*push_struct(arena, u32) = (u32)stack_space_needed;
863863
}
864864

865-
u8 amount_of_pushed_registers = (u8)__popcnt(function->pushed_register_mask);
865+
// @incomplete: Pushing r8-r15 needs 2 bytes each.
866+
u8 big_pushes = (u8)__popcnt((function->pushed_register_mask >> 8) & 0xff);
867+
u8 small_pushes = (u8)__popcnt((function->pushed_register_mask >> 0) & 0xff);
868+
869+
u8 push_offset_in_prolog = 2 * big_pushes + small_pushes;
866870

867871
struct unwind_code *frame_pointer_code = push_struct(arena, struct unwind_code);
868-
frame_pointer_code->offset_in_prolog = (u8)(amount_of_pushed_registers + /*mov rbp, rsp*/3);
872+
frame_pointer_code->offset_in_prolog = (u8)(push_offset_in_prolog + /*mov rbp, rsp*/3);
869873
frame_pointer_code->operation_code = /*UWOP_SET_FPREG*/3;
870874

871-
for(u8 register_index = 0, offset_in_prolog = amount_of_pushed_registers; register_index < 16; register_index++){
875+
for(u8 register_index = 0, offset_in_prolog = push_offset_in_prolog; register_index < 16; register_index++){
872876
if(!(function->pushed_register_mask & (1u << register_index))) continue;
873877

874878
struct unwind_code *pushed_register_code = push_struct(arena, struct unwind_code);
875-
pushed_register_code->offset_in_prolog = offset_in_prolog--;
879+
pushed_register_code->offset_in_prolog = offset_in_prolog;
876880
pushed_register_code->operation_code = /*UWOP_PUSH_NONVOL*/0;
877881
pushed_register_code->operation_info = register_index;
882+
883+
offset_in_prolog -= 1 + (register_index >= 8);
878884
}
879885

880886
unwind_info->count_of_codes = (u8)((struct unwind_code *)arena_current(arena) - unwind_info->codes);

0 commit comments

Comments
 (0)