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