diff --git a/src/sections.inc b/src/sections.inc index e6ca116..285b642 100644 --- a/src/sections.inc +++ b/src/sections.inc @@ -50,16 +50,38 @@ parse_sections: mov eax, [sec_id] cmp eax, SECT_TYPE je .type + cmp eax, SECT_IMPORT + je .import + cmp eax, SECT_FUNCTION + je .func + cmp eax, SECT_EXPORT + je .export + cmp eax, SECT_CODE + je .code jmp .skip .type: call parse_type_section + jmp .skip +.import: + call parse_import_section + jmp .skip +.func: + call parse_func_section + jmp .skip +.export: + call parse_export_section + jmp .skip +.code: + call parse_code_section .skip: mov esi, [sec_next] jmp .next .done: + call build_func_index + call print_func_signatures popad ret @@ -205,3 +227,573 @@ print_valtype: call print_str pop esi ret + +MAX_FUNCS = 64 +MAX_EXPORTS = 64 +MAX_IMPORTS = 64 + +IMPORT_KIND_FUNC = 0 +IMPORT_KIND_TABLE = 1 +IMPORT_KIND_MEMORY = 2 +IMPORT_KIND_GLOBAL = 3 + +parse_import_section: + pushad + mov esi, [sec_content] + + call decode_leb128_u32 + mov [import_count], eax + mov ecx, eax + xor ebx, ebx + mov dword [import_func_count], 0 + +.next_import: + test ecx, ecx + jz .imports_done + push ecx + + ; module name + call decode_leb128_u32 + mov edx, eax + mov [import_mod_name_lens + ebx*4], eax + mov [import_mod_name_ptrs + ebx*4], esi + + push esi edx + mov esi, msg_indent + call print_str + mov esi, msg_import_word + call print_str + mov esi, msg_quote + call print_str + pop edx esi + push edx + mov ecx, edx + call print_n + push esi + mov esi, msg_quote + call print_str + mov esi, msg_dot + call print_str + pop esi + pop edx + + add esi, edx + + ; field name + call decode_leb128_u32 + mov edx, eax + mov [import_field_name_lens + ebx*4], eax + mov [import_field_name_ptrs + ebx*4], esi + + push esi edx + mov esi, msg_quote + call print_str + pop edx esi + push edx + mov ecx, edx + call print_n + push esi + mov esi, msg_quote + call print_str + pop esi + pop edx + + add esi, edx + + ; kind byte + movzx eax, byte [esi] + inc esi + mov [import_kinds + ebx*4], eax + + cmp eax, IMPORT_KIND_FUNC + je .imp_func + cmp eax, IMPORT_KIND_TABLE + je .imp_table + cmp eax, IMPORT_KIND_MEMORY + je .imp_memory + cmp eax, IMPORT_KIND_GLOBAL + je .imp_global + jmp .imp_next + +.imp_func: + call decode_leb128_u32 + mov [import_desc + ebx*4], eax + push esi + mov esi, msg_arrow + call print_str + mov esi, msg_func_word + call print_str + pop esi + push esi + mov esi, msg_type_word + call print_str + mov eax, [import_desc + ebx*4] + call print_dec + mov esi, msg_newline + call print_str + pop esi + inc dword [import_func_count] + jmp .imp_next + +.imp_table: + inc esi + movzx eax, byte [esi] + inc esi + push eax + call decode_leb128_u32 + pop edx + test edx, 1 + jz .imp_table_print + call decode_leb128_u32 +.imp_table_print: + push esi + mov esi, msg_arrow + call print_str + mov esi, msg_ek_table + call print_str + mov esi, msg_newline + call print_str + pop esi + jmp .imp_next + +.imp_memory: + movzx eax, byte [esi] + inc esi + push eax + call decode_leb128_u32 + pop edx + test edx, 1 + jz .imp_mem_print + call decode_leb128_u32 +.imp_mem_print: + push esi + mov esi, msg_arrow + call print_str + mov esi, msg_ek_memory + call print_str + mov esi, msg_newline + call print_str + pop esi + jmp .imp_next + +.imp_global: + add esi, 2 + push esi + mov esi, msg_arrow + call print_str + mov esi, msg_ek_global + call print_str + mov esi, msg_newline + call print_str + pop esi + +.imp_next: + pop ecx + inc ebx + dec ecx + jmp .next_import + +.imports_done: + popad + ret + +parse_func_section: + pushad + mov esi, [sec_content] + + call decode_leb128_u32 + mov [func_count], eax + mov ecx, eax + xor ebx, ebx + +.next_func: + test ecx, ecx + jz .funcs_done + + push ecx + call decode_leb128_u32 + mov [func_type_idx + ebx*4], eax + mov edx, eax + + push esi + mov esi, msg_indent + call print_str + mov esi, msg_func_word + call print_str + mov eax, ebx + call print_dec + mov esi, msg_arrow_type + call print_str + mov eax, edx + call print_dec + mov esi, msg_newline + call print_str + pop esi + pop ecx + + inc ebx + dec ecx + jmp .next_func + +.funcs_done: + popad + ret + +parse_export_section: + pushad + mov esi, [sec_content] + + call decode_leb128_u32 + mov [export_count], eax + mov ecx, eax + xor ebx, ebx + +.next_export: + test ecx, ecx + jz .exports_done + push ecx + + call decode_leb128_u32 + mov edx, eax + mov [export_name_lens + ebx*4], eax + mov [export_name_ptrs + ebx*4], esi + + push esi edx + mov esi, msg_indent + call print_str + mov esi, msg_export_q + call print_str + pop edx esi + push edx + mov ecx, edx + call print_n + push esi + mov esi, msg_quote + call print_str + pop esi + pop edx + + add esi, edx + + movzx eax, byte [esi] + inc esi + mov [export_kinds + ebx*4], eax + push eax + + call decode_leb128_u32 + mov [export_indices + ebx*4], eax + mov edx, eax + + push esi + mov esi, msg_arrow + call print_str + pop esi + pop eax + push esi + call print_export_kind + mov eax, edx + call print_dec + mov esi, msg_newline + call print_str + pop esi + + pop ecx + inc ebx + dec ecx + jmp .next_export + +.exports_done: + popad + ret + +print_export_kind: + push esi + cmp eax, 0 + je .ek_func + cmp eax, 1 + je .ek_table + cmp eax, 2 + je .ek_memory + cmp eax, 3 + je .ek_global + mov esi, msg_ek_unknown + call print_str + pop esi + ret +.ek_func: + mov esi, msg_ek_func + jmp .ek_print +.ek_table: + mov esi, msg_ek_table + jmp .ek_print +.ek_memory: + mov esi, msg_ek_memory + jmp .ek_print +.ek_global: + mov esi, msg_ek_global +.ek_print: + call print_str + pop esi + ret + +parse_code_section: + pushad + mov esi, [sec_content] + + call decode_leb128_u32 + mov [code_count], eax + mov ecx, eax + xor ebx, ebx + +.next_body: + test ecx, ecx + jz .bodies_done + push ecx + + call decode_leb128_u32 + mov edx, eax + mov [code_body_sizes + ebx*4], eax + mov [code_body_ptrs + ebx*4], esi + + push esi edx + mov esi, msg_indent + call print_str + mov esi, msg_body_word + call print_str + mov eax, ebx + call print_dec + mov esi, msg_colon + call print_str + pop edx esi + push esi + mov eax, edx + call print_dec + mov esi, msg_bytes + call print_str + pop esi + + add esi, edx + + pop ecx + inc ebx + dec ecx + jmp .next_body + +.bodies_done: + popad + ret + +build_func_index: + pushad + xor ebx, ebx + xor edx, edx + + mov ecx, [import_count] + xor eax, eax +.imp_loop: + test ecx, ecx + jz .imp_done + cmp dword [import_kinds + eax*4], IMPORT_KIND_FUNC + jne .imp_skip + push dword [import_desc + eax*4] + pop dword [fidx_type + ebx*4] + mov dword [fidx_is_import + ebx*4], 1 + mov [fidx_import_idx + ebx*4], eax + inc ebx +.imp_skip: + inc eax + dec ecx + jmp .imp_loop +.imp_done: + + mov ecx, [func_count] + xor edx, edx +.local_loop: + test ecx, ecx + jz .local_done + push dword [func_type_idx + edx*4] + pop dword [fidx_type + ebx*4] + mov dword [fidx_is_import + ebx*4], 0 + mov [fidx_local_idx + ebx*4], edx + inc ebx + inc edx + dec ecx + jmp .local_loop +.local_done: + mov [fidx_total], ebx + + push esi + mov esi, msg_fidx_hdr + call print_str + mov eax, ebx + call print_dec + mov esi, msg_fidx_entries + call print_str + + xor ecx, ecx +.print_loop: + cmp ecx, [fidx_total] + jae .print_done + push ecx + mov esi, msg_indent + call print_str + mov esi, msg_func_word + call print_str + mov eax, ecx + call print_dec + mov esi, msg_arrow_type + call print_str + mov eax, [fidx_type + ecx*4] + call print_dec + cmp dword [fidx_is_import + ecx*4], 0 + je .not_imported + mov esi, msg_fidx_imported + call print_str + jmp .entry_done +.not_imported: + mov esi, msg_fidx_local + call print_str +.entry_done: + pop ecx + inc ecx + jmp .print_loop +.print_done: + pop esi + popad + ret + +print_func_signatures: + pushad + mov esi, msg_funcsig_hdr + call print_str + + xor ecx, ecx +.next_sig: + cmp ecx, [fidx_total] + jae .sigs_done + push ecx + + mov eax, [fidx_type + ecx*4] + mov [sig_cur_type], eax + + mov esi, msg_indent + call print_str + mov edx, [sig_cur_type] + mov eax, [type_result_counts + edx*4] + test eax, eax + jz .void_ret + mov esi, [type_result_ptrs + edx*4] + movzx eax, byte [esi] + call print_valtype + jmp .print_name +.void_ret: + mov esi, msg_vt_void + call print_str + +.print_name: + mov esi, msg_space + call print_str + + pop ecx + push ecx + call find_func_name + test edx, edx + jz .anon_name + mov esi, eax + push ecx + mov ecx, edx + call print_n + pop ecx + jmp .print_params + +.anon_name: + push ecx + mov esi, msg_func_word + call print_str + pop ecx + push ecx + mov eax, ecx + call print_dec + pop ecx + +.print_params: + mov esi, msg_oparen + call print_str + + mov edx, [sig_cur_type] + mov eax, [type_param_counts + edx*4] + test eax, eax + jz .no_params + mov edi, [type_param_ptrs + edx*4] + xor ebx, ebx +.param_loop: + cmp ebx, [type_param_counts + edx*4] + jae .no_params + test ebx, ebx + jz .no_comma + push esi + mov esi, msg_comma + call print_str + pop esi +.no_comma: + movzx eax, byte [edi + ebx] + call print_valtype + inc ebx + jmp .param_loop + +.no_params: + mov esi, msg_cparen_nl + call print_str + + pop ecx + inc ecx + jmp .next_sig + +.sigs_done: + popad + ret + +; ecx = function index +; returns: eax = name pointer, edx = name length (0 if anonymous) +find_func_name: + push ebx esi edi + + cmp dword [fidx_is_import + ecx*4], 0 + je .check_exports + mov eax, [fidx_import_idx + ecx*4] + mov edx, [import_field_name_lens + eax*4] + mov eax, [import_field_name_ptrs + eax*4] + jmp .found + +.check_exports: + xor ebx, ebx +.exp_loop: + cmp ebx, [export_count] + jae .not_found + cmp dword [export_kinds + ebx*4], 0 + jne .exp_next + cmp [export_indices + ebx*4], ecx + jne .exp_next + mov edx, [export_name_lens + ebx*4] + mov eax, [export_name_ptrs + ebx*4] + jmp .found +.exp_next: + inc ebx + jmp .exp_loop + +.not_found: + xor edx, edx +.found: + pop edi esi ebx + ret + +; esi = bytes, ecx = count +print_n: + push eax ebx ecx edx + mov edx, ecx + mov ecx, esi + mov ebx, STDOUT + mov eax, SYS_WRITE + int 0x80 + pop edx ecx ebx eax + ret diff --git a/src/wasm.asm b/src/wasm.asm index 3aa4b14..831d355 100644 --- a/src/wasm.asm +++ b/src/wasm.asm @@ -219,7 +219,28 @@ msg_vt_i32 db 'i32', 0 msg_vt_i64 db 'i64', 0 msg_vt_f32 db 'f32', 0 msg_vt_f64 db 'f64', 0 +msg_vt_void db 'void', 0 msg_vt_unknown db '?', 0 +msg_space db ' ', 0 +msg_func_word db 'func ', 0 +msg_body_word db 'body ', 0 +msg_export_q db 'export "', 0 +msg_quote db '"', 0 +msg_arrow db ' -> ', 0 +msg_arrow_type db ' -> type ', 0 +msg_import_word db 'import ', 0 +msg_dot db '.', 0 +msg_fidx_hdr db 'Function index: ', 0 +msg_fidx_entries db ' entries', 10, 0 +msg_fidx_imported db ' (imported)', 10, 0 +msg_fidx_local db ' (local)', 10, 0 +msg_funcsig_hdr db 'Function signatures:', 10, 0 + +msg_ek_func db 'func ', 0 +msg_ek_table db 'table ', 0 +msg_ek_memory db 'memory ', 0 +msg_ek_global db 'global ', 0 +msg_ek_unknown db 'unknown ', 0 sec_name_tbl dd sn_custom, sn_type, sn_import, sn_func, sn_table dd sn_memory, sn_global, sn_export, sn_start, sn_element @@ -256,4 +277,34 @@ type_result_counts rd MAX_TYPES type_param_ptrs rd MAX_TYPES type_result_ptrs rd MAX_TYPES +func_count dd 0 +func_type_idx rd MAX_FUNCS + +export_count dd 0 +export_name_ptrs rd MAX_EXPORTS +export_name_lens rd MAX_EXPORTS +export_kinds rd MAX_EXPORTS +export_indices rd MAX_EXPORTS + +import_count dd 0 +import_func_count dd 0 +import_mod_name_ptrs rd MAX_IMPORTS +import_mod_name_lens rd MAX_IMPORTS +import_field_name_ptrs rd MAX_IMPORTS +import_field_name_lens rd MAX_IMPORTS +import_kinds rd MAX_IMPORTS +import_desc rd MAX_IMPORTS + +code_count dd 0 +code_body_ptrs rd MAX_FUNCS +code_body_sizes rd MAX_FUNCS + +fidx_total dd 0 +fidx_type rd MAX_FUNCS +fidx_is_import rd MAX_FUNCS +fidx_import_idx rd MAX_FUNCS +fidx_local_idx rd MAX_FUNCS + +sig_cur_type dd 0 + file_buf rb FILE_BUF_SIZE diff --git a/test/run_tests.sh b/test/run_tests.sh index 085dfc2..b846aaf 100755 --- a/test/run_tests.sh +++ b/test/run_tests.sh @@ -31,6 +31,9 @@ check "bad version" "unsupported wasm" $WASM test/wasm/badver.wasm check "section list" "(Type)" $WASM test/wasm/valid.wasm check "type no params" "() -> (i32)" $WASM test/wasm/valid.wasm check "type two params" "(i32, i32) -> (i32)" $WASM test/wasm/add.wasm +check "import parsed" 'import "env"."print_i32"' $WASM test/wasm/import.wasm +check "func index" "func 0 -> type 0 (imported)" $WASM test/wasm/import.wasm +check "signature" "i32 add(i32, i32)" $WASM test/wasm/add.wasm echo "" echo "Results: $PASS/$TESTS passed, $FAIL failed" diff --git a/test/wasm/import.wasm b/test/wasm/import.wasm new file mode 100644 index 0000000..4b46565 Binary files /dev/null and b/test/wasm/import.wasm differ diff --git a/test/wat/import.wat b/test/wat/import.wat new file mode 100644 index 0000000..22da44f --- /dev/null +++ b/test/wat/import.wat @@ -0,0 +1,9 @@ +(module + (import "env" "print_i32" (func $print_i32 (param i32))) + (import "env" "memory" (memory 1)) + (func (export "main") (result i32) + i32.const 42 + call $print_i32 + i32.const 0 + ) +)