wasm.h (15792B)
1 2 #ifndef PROTOVERSE_WASM_H 3 #define PROTOVERSE_WASM_H 4 5 static const unsigned char WASM_MAGIC[] = {0,'a','s','m'}; 6 7 #define WASM_VERSION 0x01 8 #define MAX_U32_LEB128_BYTES 5 9 #define MAX_U64_LEB128_BYTES 10 10 #define MAX_CUSTOM_SECTIONS 32 11 #define MAX_BUILTINS 64 12 #define BUILTIN_SUSPEND 42 13 14 #define FUNC_TYPE_TAG 0x60 15 16 17 #include "cursor.h" 18 #include "error.h" 19 20 #ifdef NOINLINE 21 #define INLINE __attribute__((noinline)) 22 #else 23 #define INLINE inline 24 #endif 25 26 27 #define interp_error(p, fmt, ...) note_error(&((p)->errors), interp_codeptr(p), fmt, ##__VA_ARGS__) 28 #define parse_err(p, fmt, ...) note_error(&((p)->errs), &(p)->cur, fmt, ##__VA_ARGS__) 29 30 enum valtype { 31 val_i32 = 0x7F, 32 val_i64 = 0x7E, 33 val_f32 = 0x7D, 34 val_f64 = 0x7C, 35 val_ref_null = 0xD0, 36 val_ref_func = 0x70, 37 val_ref_extern = 0x6F, 38 }; 39 40 enum const_instr { 41 ci_const_i32 = 0x41, 42 ci_const_i64 = 0x42, 43 ci_const_f32 = 0x43, 44 ci_const_f64 = 0x44, 45 ci_ref_null = 0xD0, 46 ci_ref_func = 0xD2, 47 ci_global_get = 0x23, 48 ci_end = 0x0B, 49 }; 50 51 enum limit_type { 52 limit_min = 0x00, 53 limit_min_max = 0x01, 54 }; 55 56 struct limits { 57 u32 min; 58 u32 max; 59 enum limit_type type; 60 }; 61 62 enum section_tag { 63 section_custom, 64 section_type, 65 section_import, 66 section_function, 67 section_table, 68 section_memory, 69 section_global, 70 section_export, 71 section_start, 72 section_element, 73 section_code, 74 section_data, 75 section_data_count, 76 section_name, 77 num_sections, 78 }; 79 80 enum name_subsection_tag { 81 name_subsection_module, 82 name_subsection_funcs, 83 name_subsection_locals, 84 num_name_subsections, 85 }; 86 87 enum reftype { 88 funcref = 0x70, 89 externref = 0x6F, 90 }; 91 92 struct resulttype { 93 unsigned char *valtypes; /* enum valtype */ 94 u32 num_valtypes; 95 }; 96 97 struct functype { 98 struct resulttype params; 99 struct resulttype result; 100 }; 101 102 struct table { 103 enum reftype reftype; 104 struct limits limits; 105 }; 106 107 struct tablesec { 108 struct table *tables; 109 u32 num_tables; 110 }; 111 112 enum elem_mode { 113 elem_mode_passive, 114 elem_mode_active, 115 elem_mode_declarative, 116 }; 117 118 struct expr { 119 u8 *code; 120 u32 code_len; 121 }; 122 123 struct refval { 124 u32 addr; 125 }; 126 127 struct table_inst { 128 struct refval *refs; 129 enum reftype reftype; 130 u32 num_refs; 131 }; 132 133 struct numval { 134 union { 135 int i32; 136 u32 u32; 137 int64_t i64; 138 uint64_t u64; 139 float f32; 140 double f64; 141 }; 142 }; 143 144 struct val { 145 enum valtype type; 146 union { 147 struct numval num; 148 struct refval ref; 149 }; 150 }; 151 152 struct elem_inst { 153 struct val val; 154 u16 elem; 155 u16 init; 156 }; 157 158 struct elem { 159 struct expr offset; 160 u32 tableidx; 161 struct expr *inits; 162 u32 num_inits; 163 enum elem_mode mode; 164 enum reftype reftype; 165 struct val val; 166 }; 167 168 struct customsec { 169 const char *name; 170 unsigned char *data; 171 u32 data_len; 172 }; 173 174 struct elemsec { 175 struct elem *elements; 176 u32 num_elements; 177 }; 178 179 struct memsec { 180 struct limits *mems; /* memtype */ 181 u32 num_mems; 182 }; 183 184 struct funcsec { 185 u32 *type_indices; 186 u32 num_indices; 187 }; 188 189 enum mut { 190 mut_const, 191 mut_var, 192 }; 193 194 struct globaltype { 195 enum valtype valtype; 196 enum mut mut; 197 }; 198 199 struct globalsec { 200 struct global *globals; 201 u32 num_globals; 202 }; 203 204 struct typesec { 205 struct functype *functypes; 206 u32 num_functypes; 207 }; 208 209 enum import_type { 210 import_func, 211 import_table, 212 import_mem, 213 import_global, 214 }; 215 216 struct importdesc { 217 enum import_type type; 218 union { 219 u32 typeidx; 220 struct limits tabletype; 221 struct limits memtype; 222 struct globaltype globaltype; 223 }; 224 }; 225 226 struct import { 227 const char *module_name; 228 const char *name; 229 struct importdesc desc; 230 int resolved_builtin; 231 }; 232 233 struct importsec { 234 struct import *imports; 235 u32 num_imports; 236 }; 237 238 struct global { 239 struct globaltype type; 240 struct expr init; 241 struct val val; 242 }; 243 244 struct local_def { 245 u32 num_types; 246 enum valtype type; 247 }; 248 249 /* "code" */ 250 struct wasm_func { 251 struct expr code; 252 struct local_def *local_defs; 253 u32 num_local_defs; 254 }; 255 256 enum func_type { 257 func_type_wasm, 258 func_type_builtin, 259 }; 260 261 struct func { 262 union { 263 struct wasm_func *wasm_func; 264 struct builtin *builtin; 265 }; 266 u32 num_locals; 267 struct functype *functype; 268 enum func_type type; 269 const char *name; 270 u32 idx; 271 }; 272 273 struct codesec { 274 struct wasm_func *funcs; 275 u32 num_funcs; 276 }; 277 278 enum exportdesc { 279 export_func, 280 export_table, 281 export_mem, 282 export_global, 283 }; 284 285 struct wexport { 286 const char *name; 287 u32 index; 288 enum exportdesc desc; 289 }; 290 291 struct exportsec { 292 struct wexport *exports; 293 u32 num_exports; 294 }; 295 296 struct nameassoc { 297 u32 index; 298 const char *name; 299 }; 300 301 struct namemap { 302 struct nameassoc *names; 303 u32 num_names; 304 }; 305 306 struct namesec { 307 const char *module_name; 308 struct namemap func_names; 309 int parsed; 310 }; 311 312 struct wsection { 313 enum section_tag tag; 314 }; 315 316 enum bulk_tag { 317 i_memory_copy = 10, 318 i_memory_fill = 11, 319 i_table_init = 12, 320 i_elem_drop = 13, 321 i_table_copy = 14, 322 i_table_grow = 15, 323 i_table_size = 16, 324 i_table_fill = 17, 325 }; 326 327 enum instr_tag { 328 /* control instructions */ 329 i_unreachable = 0x00, 330 i_nop = 0x01, 331 i_block = 0x02, 332 i_loop = 0x03, 333 i_if = 0x04, 334 i_else = 0x05, 335 i_end = 0x0B, 336 i_br = 0x0C, 337 i_br_if = 0x0D, 338 i_br_table = 0x0E, 339 i_return = 0x0F, 340 i_call = 0x10, 341 i_call_indirect = 0x11, 342 343 /* parametric instructions */ 344 i_drop = 0x1A, 345 i_select = 0x1B, 346 i_selects = 0x1C, 347 348 /* variable instructions */ 349 i_local_get = 0x20, 350 i_local_set = 0x21, 351 i_local_tee = 0x22, 352 i_global_get = 0x23, 353 i_global_set = 0x24, 354 i_table_get = 0x25, 355 i_table_set = 0x26, 356 357 /* memory instructions */ 358 i_i32_load = 0x28, 359 i_i64_load = 0x29, 360 i_f32_load = 0x2A, 361 i_f64_load = 0x2B, 362 i_i32_load8_s = 0x2C, 363 i_i32_load8_u = 0x2D, 364 i_i32_load16_s = 0x2E, 365 i_i32_load16_u = 0x2F, 366 i_i64_load8_s = 0x30, 367 i_i64_load8_u = 0x31, 368 i_i64_load16_s = 0x32, 369 i_i64_load16_u = 0x33, 370 i_i64_load32_s = 0x34, 371 i_i64_load32_u = 0x35, 372 i_i32_store = 0x36, 373 i_i64_store = 0x37, 374 i_f32_store = 0x38, 375 i_f64_store = 0x39, 376 i_i32_store8 = 0x3A, 377 i_i32_store16 = 0x3B, 378 i_i64_store8 = 0x3C, 379 i_i64_store16 = 0x3D, 380 i_i64_store32 = 0x3E, 381 i_memory_size = 0x3F, 382 i_memory_grow = 0x40, 383 384 /* numeric instructions */ 385 i_i32_const = 0x41, 386 i_i64_const = 0x42, 387 i_f32_const = 0x43, 388 i_f64_const = 0x44, 389 390 i_i32_eqz = 0x45, 391 i_i32_eq = 0x46, 392 i_i32_ne = 0x47, 393 i_i32_lt_s = 0x48, 394 i_i32_lt_u = 0x49, 395 i_i32_gt_s = 0x4A, 396 i_i32_gt_u = 0x4B, 397 i_i32_le_s = 0x4C, 398 i_i32_le_u = 0x4D, 399 i_i32_ge_s = 0x4E, 400 i_i32_ge_u = 0x4F, 401 402 i_i64_eqz = 0x50, 403 i_i64_eq = 0x51, 404 i_i64_ne = 0x52, 405 i_i64_lt_s = 0x53, 406 i_i64_lt_u = 0x54, 407 i_i64_gt_s = 0x55, 408 i_i64_gt_u = 0x56, 409 i_i64_le_s = 0x57, 410 i_i64_le_u = 0x58, 411 i_i64_ge_s = 0x59, 412 i_i64_ge_u = 0x5A, 413 414 i_f32_eq = 0x5B, 415 i_f32_ne = 0x5C, 416 i_f32_lt = 0x5D, 417 i_f32_gt = 0x5E, 418 i_f32_le = 0x5F, 419 i_f32_ge = 0x60, 420 421 i_f64_eq = 0x61, 422 i_f64_ne = 0x62, 423 i_f64_lt = 0x63, 424 i_f64_gt = 0x64, 425 i_f64_le = 0x65, 426 i_f64_ge = 0x66, 427 428 i_i32_clz = 0x67, 429 i_i32_ctz = 0x68, 430 i_i32_popcnt = 0x69, 431 432 i_i32_add = 0x6A, 433 i_i32_sub = 0x6B, 434 i_i32_mul = 0x6C, 435 i_i32_div_s = 0x6D, 436 i_i32_div_u = 0x6E, 437 i_i32_rem_s = 0x6F, 438 i_i32_rem_u = 0x70, 439 i_i32_and = 0x71, 440 i_i32_or = 0x72, 441 i_i32_xor = 0x73, 442 i_i32_shl = 0x74, 443 i_i32_shr_s = 0x75, 444 i_i32_shr_u = 0x76, 445 i_i32_rotl = 0x77, 446 i_i32_rotr = 0x78, 447 448 i_i64_clz = 0x79, 449 i_i64_ctz = 0x7A, 450 i_i64_popcnt = 0x7B, 451 i_i64_add = 0x7C, 452 i_i64_sub = 0x7D, 453 i_i64_mul = 0x7E, 454 i_i64_div_s = 0x7F, 455 i_i64_div_u = 0x80, 456 i_i64_rem_s = 0x81, 457 i_i64_rem_u = 0x82, 458 i_i64_and = 0x83, 459 i_i64_or = 0x84, 460 i_i64_xor = 0x85, 461 i_i64_shl = 0x86, 462 i_i64_shr_s = 0x87, 463 i_i64_shr_u = 0x88, 464 i_i64_rotl = 0x89, 465 i_i64_rotr = 0x8A, 466 467 i_f32_abs = 0x8b, 468 i_f32_neg = 0x8c, 469 i_f32_ceil = 0x8d, 470 i_f32_floor = 0x8e, 471 i_f32_trunc = 0x8f, 472 i_f32_nearest = 0x90, 473 i_f32_sqrt = 0x91, 474 i_f32_add = 0x92, 475 i_f32_sub = 0x93, 476 i_f32_mul = 0x94, 477 i_f32_div = 0x95, 478 i_f32_min = 0x96, 479 i_f32_max = 0x97, 480 i_f32_copysign = 0x98, 481 482 i_f64_abs = 0x99, 483 i_f64_neg = 0x9a, 484 i_f64_ceil = 0x9b, 485 i_f64_floor = 0x9c, 486 i_f64_trunc = 0x9d, 487 i_f64_nearest = 0x9e, 488 i_f64_sqrt = 0x9f, 489 i_f64_add = 0xa0, 490 i_f64_sub = 0xa1, 491 i_f64_mul = 0xa2, 492 i_f64_div = 0xa3, 493 i_f64_min = 0xa4, 494 i_f64_max = 0xa5, 495 i_f64_copysign = 0xa6, 496 497 i_i32_wrap_i64 = 0xa7, 498 i_i32_trunc_f32_s = 0xa8, 499 i_i32_trunc_f32_u = 0xa9, 500 i_i32_trunc_f64_s = 0xaa, 501 i_i32_trunc_f64_u = 0xab, 502 i_i64_extend_i32_s = 0xac, 503 i_i64_extend_i32_u = 0xad, 504 i_i64_trunc_f32_s = 0xae, 505 i_i64_trunc_f32_u = 0xaf, 506 i_i64_trunc_f64_s = 0xb0, 507 i_i64_trunc_f64_u = 0xb1, 508 i_f32_convert_i32_s = 0xb2, 509 i_f32_convert_i32_u = 0xb3, 510 i_f32_convert_i64_s = 0xb4, 511 i_f32_convert_i64_u = 0xb5, 512 i_f32_demote_f64 = 0xb6, 513 i_f64_convert_i32_s = 0xb7, 514 i_f64_convert_i32_u = 0xb8, 515 i_f64_convert_i64_s = 0xb9, 516 i_f64_convert_i64_u = 0xba, 517 i_f64_promote_f32 = 0xbb, 518 519 i_i32_reinterpret_f32 = 0xbc, 520 i_i64_reinterpret_f64 = 0xbd, 521 i_f32_reinterpret_i32 = 0xbe, 522 i_f64_reinterpret_i64 = 0xbf, 523 524 i_i32_extend8_s = 0xc0, 525 i_i32_extend16_s = 0xc1, 526 i_i64_extend8_s = 0xc2, 527 i_i64_extend16_s = 0xc3, 528 i_i64_extend32_s = 0xc4, 529 530 i_ref_null = 0xD0, 531 i_ref_is_null = 0xD1, 532 i_ref_func = 0xD2, 533 534 i_bulk_op = 0xFC, 535 /* TODO: more instrs */ 536 537 }; 538 539 enum blocktype_tag { 540 blocktype_empty, 541 blocktype_valtype, 542 blocktype_index, 543 }; 544 545 struct blocktype { 546 enum blocktype_tag tag; 547 union { 548 enum valtype valtype; 549 int type_index; 550 }; 551 }; 552 553 struct instrs { 554 unsigned char *data; 555 u32 len; 556 }; 557 558 struct block { 559 struct blocktype type; 560 struct expr instrs; 561 }; 562 563 struct memarg { 564 u32 offset; 565 u32 align; 566 }; 567 568 struct br_table { 569 u32 num_label_indices; 570 u32 label_indices[512]; 571 u32 default_label; 572 }; 573 574 struct call_indirect { 575 u32 tableidx; 576 u32 typeidx; 577 }; 578 579 struct table_init { 580 u32 tableidx; 581 u32 elemidx; 582 }; 583 584 struct table_copy { 585 u32 from; 586 u32 to; 587 }; 588 589 struct bulk_op { 590 enum bulk_tag tag; 591 union { 592 struct table_init table_init; 593 struct table_copy table_copy; 594 u32 idx; 595 }; 596 }; 597 598 struct select_instr { 599 u8 *valtypes; 600 u32 num_valtypes; 601 }; 602 603 struct instr { 604 enum instr_tag tag; 605 int pos; 606 union { 607 struct br_table br_table; 608 struct bulk_op bulk_op; 609 struct call_indirect call_indirect; 610 struct memarg memarg; 611 struct select_instr select; 612 struct block block; 613 struct expr else_block; 614 double f64; 615 float f32; 616 int i32; 617 u32 u32; 618 int64_t i64; 619 u64 u64; 620 unsigned char memidx; 621 enum reftype reftype; 622 }; 623 }; 624 625 enum datamode { 626 datamode_active, 627 datamode_passive, 628 }; 629 630 struct wdata_active { 631 u32 mem_index; 632 struct expr offset_expr; 633 }; 634 635 struct wdata { 636 struct wdata_active active; 637 u8 *bytes; 638 u32 bytes_len; 639 enum datamode mode; 640 }; 641 642 struct datasec { 643 struct wdata *datas; 644 u32 num_datas; 645 }; 646 647 struct startsec { 648 u32 start_fn; 649 }; 650 651 struct module { 652 unsigned int parsed; 653 unsigned int custom_sections; 654 655 struct func *funcs; 656 657 u32 num_funcs; 658 659 struct customsec custom_section[MAX_CUSTOM_SECTIONS]; 660 struct typesec type_section; 661 struct funcsec func_section; 662 struct importsec import_section; 663 struct exportsec export_section; 664 struct codesec code_section; 665 struct tablesec table_section; 666 struct memsec memory_section; 667 struct globalsec global_section; 668 struct startsec start_section; 669 struct elemsec element_section; 670 struct datasec data_section; 671 struct namesec name_section; 672 }; 673 674 // make sure the struct is packed so that 675 struct label { 676 u32 instr_pos; // resolved status is stored in HOB of pos 677 u32 jump; 678 }; 679 680 struct callframe { 681 struct cursor code; 682 struct val *locals; 683 struct func *func; 684 u16 prev_stack_items; 685 }; 686 687 struct resolver { 688 u16 label; 689 u8 end_tag; 690 u8 start_tag; 691 }; 692 693 struct global_inst { 694 struct val val; 695 }; 696 697 struct module_inst { 698 struct table_inst *tables; 699 struct global_inst *globals; 700 struct elem_inst *elements; 701 702 u32 num_tables; 703 u32 num_globals; 704 u32 num_elements; 705 706 int start_fn; 707 unsigned char *globals_init; 708 }; 709 710 struct wasi { 711 int argc; 712 const char **argv; 713 714 int environc; 715 const char **environ; 716 }; 717 718 struct wasm_interp; 719 720 struct builtin { 721 const char *name; 722 int (*fn)(struct wasm_interp *); 723 int (*prepare_args)(struct wasm_interp *); 724 }; 725 726 struct wasm_interp { 727 struct module *module; 728 struct module_inst module_inst; 729 struct wasi wasi; 730 void *context; 731 732 struct builtin builtins[MAX_BUILTINS]; 733 int num_builtins; 734 735 int prev_resolvers, quitting; 736 737 struct errors errors; /* struct error */ 738 size_t ops; 739 740 struct cursor callframes; /* struct callframe */ 741 struct cursor stack; /* struct val */ 742 struct cursor mem; /* u8/mixed */ 743 744 struct cursor memory; /* memory pages (65536 blocks) */ 745 746 struct cursor locals; /* struct val */ 747 struct cursor labels; /* struct labels */ 748 struct cursor num_labels; 749 750 // resolve stack for the current function. every time a control 751 // instruction is encountered, the label index is pushed. When an 752 // instruction is popped, we can resolve the label 753 struct cursor resolver_stack; /* struct resolver */ 754 struct cursor resolver_offsets; /* int */ 755 }; 756 757 struct wasm_parser { 758 struct module module; 759 struct builtin *builtins; 760 u32 num_builtins; 761 struct cursor cur; 762 struct cursor mem; 763 struct errors errs; 764 }; 765 766 767 int run_wasm(unsigned char *wasm, unsigned long len, int argc, const char **argv, char **env, int *retval); 768 int parse_wasm(struct wasm_parser *p); 769 int wasm_interp_init(struct wasm_interp *interp, struct module *module); 770 void wasm_parser_free(struct wasm_parser *parser); 771 void wasm_parser_init(struct wasm_parser *p, u8 *wasm, size_t wasm_len, size_t arena_size, struct builtin *, int num_builtins); 772 void wasm_interp_free(struct wasm_interp *interp); 773 int interp_wasm_module(struct wasm_interp *interp, int *retval); 774 int interp_wasm_module_resume(struct wasm_interp *interp, int *retval); 775 void print_error_backtrace(struct errors *errors); 776 void setup_wasi(struct wasm_interp *interp, int argc, const char **argv, char **env); 777 void print_callstack(struct wasm_interp *interp); 778 779 // builtin helpers 780 int get_params(struct wasm_interp *interp, struct val** vals, u32 num_vals); 781 int get_var_params(struct wasm_interp *interp, struct val** vals, u32 *num_vals); 782 u8 *interp_mem_ptr(struct wasm_interp *interp, u32 ptr, int size); 783 784 static INLINE struct callframe *top_callframe(struct cursor *cur) 785 { 786 return (struct callframe*)cursor_top(cur, sizeof(struct callframe)); 787 } 788 789 790 static INLINE struct cursor *interp_codeptr(struct wasm_interp *interp) 791 { 792 struct callframe *frame; 793 if (unlikely(!(frame = top_callframe(&interp->callframes)))) 794 return 0; 795 return &frame->code; 796 } 797 798 799 static INLINE int mem_ptr_str(struct wasm_interp *interp, u32 ptr, 800 const char **str) 801 { 802 // still technically unsafe if the string runs over the end of memory... 803 if (!(*str = (const char*)interp_mem_ptr(interp, ptr, 1))) { 804 return interp_error(interp, "int memptr"); 805 } 806 return 1; 807 } 808 809 static INLINE int mem_ptr_i32(struct wasm_interp *interp, u32 ptr, int **i) 810 { 811 if (!(*i = (int*)interp_mem_ptr(interp, ptr, sizeof(int)))) 812 return interp_error(interp, "int memptr"); 813 return 1; 814 } 815 816 static INLINE int cursor_pushval(struct cursor *cur, struct val *val) 817 { 818 return cursor_push(cur, (u8*)val, sizeof(*val)); 819 } 820 821 static INLINE int cursor_push_i32(struct cursor *stack, int i) 822 { 823 struct val val; 824 val.type = val_i32; 825 val.num.i32 = i; 826 827 return cursor_pushval(stack, &val); 828 } 829 830 static INLINE int stack_push_i32(struct wasm_interp *interp, int i) 831 { 832 return cursor_push_i32(&interp->stack, i); 833 } 834 835 static INLINE struct callframe *top_callframes(struct cursor *cur, int top) 836 { 837 return (struct callframe*)cursor_topn(cur, sizeof(struct callframe), top); 838 } 839 840 #endif /* PROTOVERSE_WASM_H */