decode.c (41477B)
1 #include "wasm/wasm.h" 2 #include "wasm/wasm_insn_table.h" 3 4 typedef struct BinReader { 5 KitCompiler* c; 6 const uint8_t* data; 7 size_t len; 8 size_t pos; 9 WasmModule* module; 10 } BinReader; 11 12 static uint8_t bin_u8(BinReader* r) { 13 if (r->pos >= r->len) 14 wasm_error(r->c, wasm_loc(0, 0), "wasm: unexpected end of file"); 15 return r->data[r->pos++]; 16 } 17 18 static uint32_t bin_uleb(BinReader* r) { 19 uint32_t result = 0, shift = 0; 20 uint32_t nbytes = 0; 21 for (;;) { 22 uint8_t b = bin_u8(r); 23 if (nbytes++ >= 5u || (shift == 28u && (b & 0xf0u))) 24 wasm_error(r->c, wasm_loc(0, 0), "wasm: invalid uleb128"); 25 result |= (uint32_t)(b & 0x7fu) << shift; 26 if (!(b & 0x80u)) return result; 27 shift += 7u; 28 } 29 } 30 31 static uint64_t bin_uleb64(BinReader* r) { 32 uint64_t result = 0; 33 uint32_t shift = 0; 34 uint32_t nbytes = 0; 35 for (;;) { 36 uint8_t b = bin_u8(r); 37 if (nbytes++ >= 10u || (shift == 63u && (b & 0xfeu))) 38 wasm_error(r->c, wasm_loc(0, 0), "wasm: invalid uleb128"); 39 result |= (uint64_t)(b & 0x7fu) << shift; 40 if (!(b & 0x80u)) return result; 41 shift += 7u; 42 } 43 } 44 45 static int64_t bin_sleb(BinReader* r, uint32_t bits) { 46 /* Accumulate in the unsigned domain: a 7-bit group can land in bit 63 47 (shift == 63 for a 10-byte i64), where a signed left shift is UB. */ 48 uint64_t result = 0; 49 uint32_t shift = 0; 50 uint32_t max_bytes = (bits + 6u) / 7u; 51 uint32_t nbytes = 0; 52 uint8_t b; 53 do { 54 if (nbytes++ >= max_bytes) 55 wasm_error(r->c, wasm_loc(0, 0), "wasm: invalid sleb128"); 56 b = bin_u8(r); 57 result |= (uint64_t)(b & 0x7fu) << shift; 58 shift += 7u; 59 } while (b & 0x80u); 60 if (shift < bits && (b & 0x40u)) result |= ~(uint64_t)0 << shift; 61 return (int64_t)result; 62 } 63 64 static double bin_f32(BinReader* r) { 65 uint32_t bits = 0; 66 float f; 67 for (uint32_t i = 0; i < 4u; ++i) bits |= (uint32_t)bin_u8(r) << (i * 8u); 68 memcpy(&f, &bits, sizeof f); 69 return (double)f; 70 } 71 72 static double bin_f64(BinReader* r) { 73 uint64_t bits = 0; 74 double d; 75 for (uint32_t i = 0; i < 8u; ++i) bits |= (uint64_t)bin_u8(r) << (i * 8u); 76 memcpy(&d, &bits, sizeof d); 77 return d; 78 } 79 80 static void bin_memarg(BinReader* r, uint32_t* align, uint64_t* offset, 81 uint32_t* memidx) { 82 uint32_t a = bin_uleb(r); 83 *memidx = 0; 84 if (a >= 64u && a < 128u) { 85 *align = a - 64u; 86 *memidx = bin_uleb(r); 87 } else if (a < 64u) { 88 *align = a; 89 } else { 90 wasm_error(r->c, wasm_loc(0, 0), "wasm: bad memory alignment"); 91 } 92 *offset = bin_uleb64(r); 93 } 94 95 static void bin_need(BinReader* r, size_t n) { 96 if (n > r->len || r->pos > r->len - n) 97 wasm_error(r->c, wasm_loc(0, 0), "wasm: section length out of bounds"); 98 } 99 100 static char* bin_name(BinReader* r, uint32_t* len_out) { 101 uint32_t n = bin_uleb(r); 102 char* name; 103 bin_need(r, n); 104 name = wasm_strdup(r->module->heap, (const char*)(r->data + r->pos), n); 105 if (!name) wasm_error(r->c, wasm_loc(0, 0), "wasm: out of memory"); 106 r->pos += n; 107 if (len_out) *len_out = n; 108 return name; 109 } 110 111 static WasmValType bin_val_type(BinReader* r, int refs_ok) { 112 uint8_t b = bin_u8(r); 113 switch (b) { 114 case WASM_VAL_I32: 115 case WASM_VAL_I64: 116 case WASM_VAL_F32: 117 case WASM_VAL_F64: 118 return (WasmValType)b; 119 case WASM_VAL_FUNCREF: 120 case WASM_VAL_EXTERNREF: 121 if (refs_ok) return (WasmValType)b; 122 break; 123 default: 124 break; 125 } 126 wasm_error(r->c, wasm_loc(0, 0), "wasm: unsupported value type 0x%02x", b); 127 return WASM_VAL_I32; 128 } 129 130 /* Decode a structured-control blocktype immediate into `in` (already appended). 131 * The blocktype is an s33: a negative value is the shorthand form (0x40 -> void, 132 * a value-type byte for a single result), a non-negative value is a function- 133 * type index (the multi-value form: block params and/or multiple results). 134 * The shorthand result type lands in in->type (0 == void); the typeidx form is 135 * recorded via wasm_insn_set_blocktype_typeidx (sentinel in type, index in 136 * imm). */ 137 static void bin_blocktype(BinReader* r, WasmModule* out, WasmInsn* in) { 138 int64_t s = bin_sleb(r, 33); 139 if (s < 0) { 140 uint8_t b = (uint8_t)(s & 0x7fu); 141 if (b == 0x40u) { 142 in->type = 0; 143 return; 144 } 145 if (wasm_is_frontend_value_type((WasmValType)b)) { 146 in->type = b; 147 return; 148 } 149 wasm_error(r->c, wasm_loc(0, 0), 150 "wasm: unsupported block result type 0x%02x", b); 151 in->type = 0; 152 return; 153 } 154 if ((uint64_t)s >= out->ntypes) 155 wasm_error(r->c, wasm_loc(0, 0), "wasm: block type index out of range"); 156 wasm_insn_set_blocktype_typeidx(in, (uint32_t)s); 157 } 158 159 /* Decode a memarg operand (align/offset/memidx) and append a single memory 160 * instruction of `kind`. Every WASM_OC_MEMARG opcode decodes identically; only 161 * the kind differs, so the base loads/stores (0x28..0x3e) and the 0xfe atomics 162 * share this body, reading their kind from WASM_INSN_TABLE rather than each 163 * spelling out its own arm. */ 164 static void decode_memarg_insn(BinReader* r, KitCompiler* c, WasmModule* out, 165 WasmFunc* f, WasmInsnKind kind) { 166 uint32_t ma, mi; 167 uint64_t mo; 168 bin_memarg(r, &ma, &mo, &mi); 169 wasm_func_add_mem_insn(c, out, f, kind, ma, mo, mi); 170 } 171 172 /* Decode one instruction opcode body (everything except the body-terminating 173 * 0x0b end) into f's instruction list, advancing *rp. Shared verbatim with the 174 * function-body decode loop so the opcode mapping has a single source of truth; 175 * reused by wasm_decode_one_insn for the disassembler. */ 176 static void decode_body_insn(BinReader* rp, WasmModule* out, WasmFunc* f, 177 uint8_t op, uint32_t* pcontrol_depth) { 178 BinReader r = *rp; 179 KitCompiler* c = r.c; 180 uint32_t control_depth = *pcontrol_depth; 181 switch (op) { 182 case 0x00: 183 wasm_func_add_insn(c, out, f, WASM_INSN_UNREACHABLE, 0); 184 break; 185 case 0x01: 186 wasm_func_add_insn(c, out, f, WASM_INSN_NOP, 0); 187 break; 188 case 0x02: 189 control_depth++; 190 wasm_func_add_insn(c, out, f, WASM_INSN_BLOCK, 0); 191 bin_blocktype(&r, out, &f->insns[f->ninsns - 1u]); 192 break; 193 case 0x03: 194 control_depth++; 195 wasm_func_add_insn(c, out, f, WASM_INSN_LOOP, 0); 196 bin_blocktype(&r, out, &f->insns[f->ninsns - 1u]); 197 break; 198 case 0x04: 199 control_depth++; 200 wasm_func_add_insn(c, out, f, WASM_INSN_IF, 0); 201 bin_blocktype(&r, out, &f->insns[f->ninsns - 1u]); 202 break; 203 case 0x05: 204 wasm_func_add_insn(c, out, f, WASM_INSN_ELSE, 0); 205 break; 206 case 0x0c: 207 wasm_func_add_insn(c, out, f, WASM_INSN_BR, bin_uleb(&r)); 208 break; 209 case 0x0d: 210 wasm_func_add_insn(c, out, f, WASM_INSN_BR_IF, bin_uleb(&r)); 211 break; 212 case 0x0e: { 213 WasmInsn* in; 214 uint32_t n = bin_uleb(&r); 215 /* Each target is at least one byte, so a count exceeding the 216 * remaining input is malformed — reject before allocating. */ 217 if ((uint64_t)n >= r.len - r.pos) 218 wasm_error(c, wasm_loc(0, 0), 219 "wasm: br_table target count exceeds input"); 220 wasm_func_add_insn(c, out, f, WASM_INSN_BR_TABLE, 0); 221 in = &f->insns[f->ninsns - 1u]; 222 wasm_insn_set_targets(c, out, in, NULL, n + 1u); 223 for (uint32_t k = 0; k < n; ++k) in->targets[k] = bin_uleb(&r); 224 in->targets[n] = bin_uleb(&r); 225 break; 226 } 227 case 0x0f: 228 wasm_func_add_insn(c, out, f, WASM_INSN_RETURN, 0); 229 break; 230 case 0x1a: 231 wasm_func_add_insn(c, out, f, WASM_INSN_DROP, 0); 232 break; 233 case 0x1b: 234 wasm_func_add_insn(c, out, f, WASM_INSN_SELECT, 0); 235 break; 236 case 0x3f: 237 wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_SIZE, 0); 238 f->insns[f->ninsns - 1u].memidx = bin_uleb(&r); 239 break; 240 case 0x40: 241 wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_GROW, 0); 242 f->insns[f->ninsns - 1u].memidx = bin_uleb(&r); 243 break; 244 case 0x10: 245 wasm_func_add_insn(c, out, f, WASM_INSN_CALL, bin_uleb(&r)); 246 break; 247 case 0x11: { 248 WasmInsn* in; 249 wasm_func_add_insn(c, out, f, WASM_INSN_CALL_INDIRECT, bin_uleb(&r)); 250 in = &f->insns[f->ninsns - 1u]; 251 in->align = bin_uleb(&r); 252 break; 253 } 254 case 0x12: 255 wasm_func_add_insn(c, out, f, WASM_INSN_RETURN_CALL, bin_uleb(&r)); 256 break; 257 case 0x13: { 258 WasmInsn* in; 259 wasm_func_add_insn(c, out, f, WASM_INSN_RETURN_CALL_INDIRECT, 260 bin_uleb(&r)); 261 in = &f->insns[f->ninsns - 1u]; 262 in->align = bin_uleb(&r); 263 break; 264 } 265 case 0x14: 266 wasm_func_add_insn(c, out, f, WASM_INSN_CALL_REF, bin_uleb(&r)); 267 break; 268 case 0x15: 269 wasm_func_add_insn(c, out, f, WASM_INSN_RETURN_CALL_REF, bin_uleb(&r)); 270 break; 271 case 0x20: 272 wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_GET, bin_uleb(&r)); 273 break; 274 case 0x21: 275 wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_SET, bin_uleb(&r)); 276 break; 277 case 0x22: 278 wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_TEE, bin_uleb(&r)); 279 break; 280 case 0x23: 281 wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_GET, bin_uleb(&r)); 282 break; 283 case 0x24: 284 wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_SET, bin_uleb(&r)); 285 break; 286 case 0x41: 287 wasm_func_add_insn(c, out, f, WASM_INSN_I32_CONST, bin_sleb(&r, 32)); 288 break; 289 case 0x42: 290 wasm_func_add_insn(c, out, f, WASM_INSN_I64_CONST, bin_sleb(&r, 64)); 291 break; 292 case 0x43: 293 wasm_func_add_fp_insn(c, out, f, WASM_INSN_F32_CONST, bin_f32(&r)); 294 break; 295 case 0x44: 296 wasm_func_add_fp_insn(c, out, f, WASM_INSN_F64_CONST, bin_f64(&r)); 297 break; 298 case 0xd0: 299 wasm_func_add_insn(c, out, f, WASM_INSN_REF_NULL, bin_val_type(&r, 1)); 300 break; 301 case 0xd1: 302 wasm_func_add_insn(c, out, f, WASM_INSN_REF_IS_NULL, 0); 303 break; 304 case 0xd2: 305 wasm_func_add_insn(c, out, f, WASM_INSN_REF_FUNC, bin_uleb(&r)); 306 break; 307 case 0x45: 308 wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQZ, 0); 309 break; 310 case 0x46: 311 wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQ, 0); 312 break; 313 case 0x47: 314 wasm_func_add_insn(c, out, f, WASM_INSN_I32_NE, 0); 315 break; 316 case 0x48: 317 wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_S, 0); 318 break; 319 case 0x49: 320 wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_U, 0); 321 break; 322 case 0x4a: 323 wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_S, 0); 324 break; 325 case 0x4b: 326 wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_U, 0); 327 break; 328 case 0x4c: 329 wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_S, 0); 330 break; 331 case 0x4d: 332 wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_U, 0); 333 break; 334 case 0x4e: 335 wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_S, 0); 336 break; 337 case 0x4f: 338 wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_U, 0); 339 break; 340 case 0x50: 341 wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQZ, 0); 342 break; 343 case 0x51: 344 wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQ, 0); 345 break; 346 case 0x52: 347 wasm_func_add_insn(c, out, f, WASM_INSN_I64_NE, 0); 348 break; 349 case 0x53: 350 wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_S, 0); 351 break; 352 case 0x54: 353 wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_U, 0); 354 break; 355 case 0x55: 356 wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_S, 0); 357 break; 358 case 0x56: 359 wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_U, 0); 360 break; 361 case 0x57: 362 wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_S, 0); 363 break; 364 case 0x58: 365 wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_U, 0); 366 break; 367 case 0x59: 368 wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_S, 0); 369 break; 370 case 0x5a: 371 wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_U, 0); 372 break; 373 case 0x6a: 374 wasm_func_add_insn(c, out, f, WASM_INSN_I32_ADD, 0); 375 break; 376 case 0x6b: 377 wasm_func_add_insn(c, out, f, WASM_INSN_I32_SUB, 0); 378 break; 379 case 0x6c: 380 wasm_func_add_insn(c, out, f, WASM_INSN_I32_MUL, 0); 381 break; 382 case 0x6d: 383 wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_S, 0); 384 break; 385 case 0x6e: 386 wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_U, 0); 387 break; 388 case 0x6f: 389 wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_S, 0); 390 break; 391 case 0x70: 392 wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_U, 0); 393 break; 394 case 0x71: 395 wasm_func_add_insn(c, out, f, WASM_INSN_I32_AND, 0); 396 break; 397 case 0x72: 398 wasm_func_add_insn(c, out, f, WASM_INSN_I32_OR, 0); 399 break; 400 case 0x73: 401 wasm_func_add_insn(c, out, f, WASM_INSN_I32_XOR, 0); 402 break; 403 case 0x74: 404 wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHL, 0); 405 break; 406 case 0x75: 407 wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_S, 0); 408 break; 409 case 0x76: 410 wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_U, 0); 411 break; 412 case 0x67: 413 wasm_func_add_insn(c, out, f, WASM_INSN_I32_CLZ, 0); 414 break; 415 case 0x68: 416 wasm_func_add_insn(c, out, f, WASM_INSN_I32_CTZ, 0); 417 break; 418 case 0x69: 419 wasm_func_add_insn(c, out, f, WASM_INSN_I32_POPCNT, 0); 420 break; 421 case 0x77: 422 wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTL, 0); 423 break; 424 case 0x78: 425 wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTR, 0); 426 break; 427 case 0x79: 428 wasm_func_add_insn(c, out, f, WASM_INSN_I64_CLZ, 0); 429 break; 430 case 0x7a: 431 wasm_func_add_insn(c, out, f, WASM_INSN_I64_CTZ, 0); 432 break; 433 case 0x7b: 434 wasm_func_add_insn(c, out, f, WASM_INSN_I64_POPCNT, 0); 435 break; 436 case 0x7c: 437 wasm_func_add_insn(c, out, f, WASM_INSN_I64_ADD, 0); 438 break; 439 case 0x7d: 440 wasm_func_add_insn(c, out, f, WASM_INSN_I64_SUB, 0); 441 break; 442 case 0x7e: 443 wasm_func_add_insn(c, out, f, WASM_INSN_I64_MUL, 0); 444 break; 445 case 0x7f: 446 wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_S, 0); 447 break; 448 case 0x80: 449 wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_U, 0); 450 break; 451 case 0x81: 452 wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_S, 0); 453 break; 454 case 0x82: 455 wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_U, 0); 456 break; 457 case 0x83: 458 wasm_func_add_insn(c, out, f, WASM_INSN_I64_AND, 0); 459 break; 460 case 0x84: 461 wasm_func_add_insn(c, out, f, WASM_INSN_I64_OR, 0); 462 break; 463 case 0x85: 464 wasm_func_add_insn(c, out, f, WASM_INSN_I64_XOR, 0); 465 break; 466 case 0x86: 467 wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHL, 0); 468 break; 469 case 0x87: 470 wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_S, 0); 471 break; 472 case 0x88: 473 wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_U, 0); 474 break; 475 case 0x89: 476 wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTL, 0); 477 break; 478 case 0x8a: 479 wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTR, 0); 480 break; 481 case 0x92: 482 wasm_func_add_insn(c, out, f, WASM_INSN_F32_ADD, 0); 483 break; 484 case 0x93: 485 wasm_func_add_insn(c, out, f, WASM_INSN_F32_SUB, 0); 486 break; 487 case 0x94: 488 wasm_func_add_insn(c, out, f, WASM_INSN_F32_MUL, 0); 489 break; 490 case 0x95: 491 wasm_func_add_insn(c, out, f, WASM_INSN_F32_DIV, 0); 492 break; 493 case 0xa0: 494 wasm_func_add_insn(c, out, f, WASM_INSN_F64_ADD, 0); 495 break; 496 case 0xa1: 497 wasm_func_add_insn(c, out, f, WASM_INSN_F64_SUB, 0); 498 break; 499 case 0xa2: 500 wasm_func_add_insn(c, out, f, WASM_INSN_F64_MUL, 0); 501 break; 502 case 0xa3: 503 wasm_func_add_insn(c, out, f, WASM_INSN_F64_DIV, 0); 504 break; 505 case 0x5b: 506 wasm_func_add_insn(c, out, f, WASM_INSN_F32_EQ, 0); 507 break; 508 case 0x5c: 509 wasm_func_add_insn(c, out, f, WASM_INSN_F32_NE, 0); 510 break; 511 case 0x5d: 512 wasm_func_add_insn(c, out, f, WASM_INSN_F32_LT, 0); 513 break; 514 case 0x5e: 515 wasm_func_add_insn(c, out, f, WASM_INSN_F32_GT, 0); 516 break; 517 case 0x5f: 518 wasm_func_add_insn(c, out, f, WASM_INSN_F32_LE, 0); 519 break; 520 case 0x60: 521 wasm_func_add_insn(c, out, f, WASM_INSN_F32_GE, 0); 522 break; 523 case 0x61: 524 wasm_func_add_insn(c, out, f, WASM_INSN_F64_EQ, 0); 525 break; 526 case 0x62: 527 wasm_func_add_insn(c, out, f, WASM_INSN_F64_NE, 0); 528 break; 529 case 0x63: 530 wasm_func_add_insn(c, out, f, WASM_INSN_F64_LT, 0); 531 break; 532 case 0x64: 533 wasm_func_add_insn(c, out, f, WASM_INSN_F64_GT, 0); 534 break; 535 case 0x65: 536 wasm_func_add_insn(c, out, f, WASM_INSN_F64_LE, 0); 537 break; 538 case 0x66: 539 wasm_func_add_insn(c, out, f, WASM_INSN_F64_GE, 0); 540 break; 541 case 0x8c: 542 wasm_func_add_insn(c, out, f, WASM_INSN_F32_NEG, 0); 543 break; 544 case 0x9a: 545 wasm_func_add_insn(c, out, f, WASM_INSN_F64_NEG, 0); 546 break; 547 case 0xa7: 548 wasm_func_add_insn(c, out, f, WASM_INSN_I32_WRAP_I64, 0); 549 break; 550 case 0xa8: 551 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_S, 0); 552 break; 553 case 0xa9: 554 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_U, 0); 555 break; 556 case 0xaa: 557 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_S, 0); 558 break; 559 case 0xab: 560 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_U, 0); 561 break; 562 case 0xac: 563 wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_S, 0); 564 break; 565 case 0xad: 566 wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_U, 0); 567 break; 568 case 0xae: 569 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_S, 0); 570 break; 571 case 0xaf: 572 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_U, 0); 573 break; 574 case 0xb0: 575 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_S, 0); 576 break; 577 case 0xb1: 578 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_U, 0); 579 break; 580 case 0xb2: 581 wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_S, 0); 582 break; 583 case 0xb3: 584 wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_U, 0); 585 break; 586 case 0xb4: 587 wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_S, 0); 588 break; 589 case 0xb5: 590 wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_U, 0); 591 break; 592 case 0xb6: 593 wasm_func_add_insn(c, out, f, WASM_INSN_F32_DEMOTE_F64, 0); 594 break; 595 case 0xb7: 596 wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_S, 0); 597 break; 598 case 0xb8: 599 wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_U, 0); 600 break; 601 case 0xb9: 602 wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_S, 0); 603 break; 604 case 0xba: 605 wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_U, 0); 606 break; 607 case 0xbb: 608 wasm_func_add_insn(c, out, f, WASM_INSN_F64_PROMOTE_F32, 0); 609 break; 610 case 0xbc: 611 wasm_func_add_insn(c, out, f, WASM_INSN_I32_REINTERPRET_F32, 0); 612 break; 613 case 0xbd: 614 wasm_func_add_insn(c, out, f, WASM_INSN_I64_REINTERPRET_F64, 0); 615 break; 616 case 0xbe: 617 wasm_func_add_insn(c, out, f, WASM_INSN_F32_REINTERPRET_I32, 0); 618 break; 619 case 0xbf: 620 wasm_func_add_insn(c, out, f, WASM_INSN_F64_REINTERPRET_I64, 0); 621 break; 622 case 0xc0: 623 wasm_func_add_insn(c, out, f, WASM_INSN_I32_EXTEND8_S, 0); 624 break; 625 case 0xc1: 626 wasm_func_add_insn(c, out, f, WASM_INSN_I32_EXTEND16_S, 0); 627 break; 628 case 0xc2: 629 wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND8_S, 0); 630 break; 631 case 0xc3: 632 wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND16_S, 0); 633 break; 634 case 0xc4: 635 wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND32_S, 0); 636 break; 637 case 0xfc: { 638 uint32_t sub = bin_uleb(&r); 639 switch (sub) { 640 case 0x00: 641 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F32_S, 0); 642 break; 643 case 0x01: 644 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F32_U, 0); 645 break; 646 case 0x02: 647 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F64_S, 0); 648 break; 649 case 0x03: 650 wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_SAT_F64_U, 0); 651 break; 652 case 0x04: 653 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F32_S, 0); 654 break; 655 case 0x05: 656 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F32_U, 0); 657 break; 658 case 0x06: 659 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F64_S, 0); 660 break; 661 case 0x07: 662 wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_SAT_F64_U, 0); 663 break; 664 case 0x08: { /* memory.init dataidx memidx */ 665 uint32_t dataidx = bin_uleb(&r); 666 uint32_t mi = bin_uleb(&r); 667 wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_INIT, 668 (int64_t)dataidx); 669 f->insns[f->ninsns - 1u].memidx = mi; 670 break; 671 } 672 case 0x09: { /* data.drop dataidx */ 673 uint32_t dataidx = bin_uleb(&r); 674 wasm_func_add_insn(c, out, f, WASM_INSN_DATA_DROP, (int64_t)dataidx); 675 break; 676 } 677 case 0x0a: { /* memory.copy dst_memidx src_memidx */ 678 uint32_t dst = bin_uleb(&r); 679 uint32_t src = bin_uleb(&r); 680 wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_COPY, 0); 681 f->insns[f->ninsns - 1u].memidx = dst; 682 f->insns[f->ninsns - 1u].aux_idx = src; 683 break; 684 } 685 case 0x0b: { /* memory.fill memidx */ 686 uint32_t mi = bin_uleb(&r); 687 wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_FILL, 0); 688 f->insns[f->ninsns - 1u].memidx = mi; 689 break; 690 } 691 case 0x0c: { /* table.init elemidx tableidx */ 692 uint32_t elemidx = bin_uleb(&r); 693 uint32_t ti = bin_uleb(&r); 694 wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_INIT, (int64_t)elemidx); 695 f->insns[f->ninsns - 1u].aux_idx = ti; 696 break; 697 } 698 case 0x0d: { /* elem.drop elemidx */ 699 uint32_t elemidx = bin_uleb(&r); 700 wasm_func_add_insn(c, out, f, WASM_INSN_ELEM_DROP, (int64_t)elemidx); 701 break; 702 } 703 case 0x0e: { /* table.copy dst_tableidx src_tableidx */ 704 uint32_t dst = bin_uleb(&r); 705 uint32_t src = bin_uleb(&r); 706 wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_COPY, (int64_t)dst); 707 f->insns[f->ninsns - 1u].aux_idx = src; 708 break; 709 } 710 case 0x0f: { /* table.grow tableidx */ 711 uint32_t ti = bin_uleb(&r); 712 wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_GROW, (int64_t)ti); 713 break; 714 } 715 case 0x10: { /* table.size tableidx */ 716 uint32_t ti = bin_uleb(&r); 717 wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_SIZE, (int64_t)ti); 718 break; 719 } 720 case 0x11: { /* table.fill tableidx */ 721 uint32_t ti = bin_uleb(&r); 722 wasm_func_add_insn(c, out, f, WASM_INSN_TABLE_FILL, (int64_t)ti); 723 break; 724 } 725 default: 726 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported 0xfc opcode 0x%x", 727 sub); 728 } 729 break; 730 } 731 case 0xfe: { 732 uint32_t sub = bin_uleb(&r); 733 /* atomic.fence is the lone irregular 0xfe op (its operand is a single 734 * 0x00 byte, not a memarg); every other 0xfe op is a memarg atomic and 735 * decodes uniformly via the table. */ 736 if (sub == 0x03u) { 737 if (bin_u8(&r) != 0) 738 wasm_error(c, wasm_loc(0, 0), "wasm: bad atomic.fence"); 739 wasm_func_add_insn(c, out, f, WASM_INSN_ATOMIC_FENCE, 0); 740 } else { 741 const WasmInsnInfo* info = 742 sub <= 0xffu ? wasm_insn_by_byte(WASM_PREFIX_FE, (uint8_t)sub) 743 : NULL; 744 if (!info || info->operand_class != WASM_OC_MEMARG) 745 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported threads opcode 0x%x", 746 sub); 747 decode_memarg_insn(&r, c, out, f, (WasmInsnKind)info->kind); 748 } 749 break; 750 } 751 default: { 752 /* The base loads/stores (0x28..0x3e) are a contiguous run of memarg ops; 753 * each decodes identically save for its kind, which the table carries. 754 * Everything else here is genuinely unknown. */ 755 const WasmInsnInfo* info = wasm_insn_by_byte(WASM_PREFIX_NONE, op); 756 if (!info || info->operand_class != WASM_OC_MEMARG) 757 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported opcode 0x%02x", op); 758 decode_memarg_insn(&r, c, out, f, (WasmInsnKind)info->kind); 759 } 760 } 761 762 *pcontrol_depth = control_depth; 763 *rp = r; 764 } 765 766 /* Canonical known-section ordering rank. Section ids otherwise appear in 767 * strictly increasing order, except the bulk-memory DataCount section (id 12), 768 * which the spec places between the Element (9) and Code (10) sections. Map ids 769 * to a rank so the monotonicity check accepts the standard sequence 770 * ...,9,12,10,11 (emitted by clang/wasm-ld and emscripten whenever passive data 771 * segments or memory.init are used) while still rejecting genuinely 772 * out-of-order or duplicated sections. Custom sections (id 0) are unordered and 773 * handled separately by the caller. */ 774 static uint32_t wasm_section_rank(uint8_t id) { 775 switch (id) { 776 case 12: return 10; /* DataCount: after Element, before Code */ 777 case 10: return 11; /* Code */ 778 case 11: return 12; /* Data */ 779 default: return id; /* 1..9 keep their natural rank */ 780 } 781 } 782 783 void wasm_decode_binary(KitCompiler* c, const KitSlice* input, 784 WasmModule* out) { 785 BinReader r; 786 uint32_t nfunc_types = 0; 787 uint8_t last_id = 0; 788 memset(&r, 0, sizeof r); 789 r.c = c; 790 r.data = input->data; 791 r.len = input->len; 792 r.module = out; 793 if (r.len < 8 || memcmp(r.data, "\0asm\1\0\0\0", 8) != 0) 794 wasm_error(c, wasm_loc(0, 0), "wasm: bad magic or version"); 795 r.pos = 8; 796 while (r.pos < r.len) { 797 uint8_t id = bin_u8(&r); 798 uint32_t size = bin_uleb(&r); 799 size_t end; 800 bin_need(&r, size); 801 end = r.pos + size; 802 if (id != 0 && wasm_section_rank(id) <= wasm_section_rank(last_id)) 803 wasm_error(c, wasm_loc(0, 0), "wasm: sections out of order"); 804 if (id != 0) last_id = id; 805 if (id == 0) { 806 uint32_t name_len = bin_uleb(&r); 807 bin_need(&r, name_len); 808 if (name_len == 7u && memcmp(r.data + r.pos, "linking", 7) == 0) 809 wasm_error(c, wasm_loc(0, 0), 810 "wasm: relocatable object metadata is not frontend input"); 811 { 812 WasmCustom* cs = wasm_add_custom(c, out); 813 cs->name = 814 wasm_strdup(out->heap, (const char*)(r.data + r.pos), name_len); 815 if (!cs->name) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); 816 r.pos += name_len; 817 if (kit_slice_eq_cstr(kit_slice_cstr(cs->name), "target_features") || 818 kit_slice_eq_cstr(kit_slice_cstr(cs->name), "target-feature")) 819 out->has_target_features = 1; 820 cs->len = (uint32_t)(end - r.pos); 821 if (cs->len) { 822 cs->data = (uint8_t*)out->heap->alloc(out->heap, cs->len, 1); 823 if (!cs->data) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); 824 memcpy(cs->data, r.data + r.pos, cs->len); 825 } 826 } 827 r.pos = end; 828 continue; 829 } 830 if (id == 1) { 831 uint32_t i, count = bin_uleb(&r); 832 for (i = 0; i < count; ++i) { 833 WasmFuncType* t = wasm_add_type(c, out); 834 uint32_t j, nparam, nresult; 835 if (bin_u8(&r) != 0x60u) 836 wasm_error(c, wasm_loc(0, 0), "wasm: expected function type"); 837 nparam = bin_uleb(&r); 838 for (j = 0; j < nparam; ++j) 839 wasm_type_push_param(c, out, t, bin_val_type(&r, 1)); 840 nresult = bin_uleb(&r); 841 for (j = 0; j < nresult; ++j) 842 wasm_type_push_result(c, out, t, bin_val_type(&r, 1)); 843 } 844 } else if (id == 2) { 845 uint32_t i, count = bin_uleb(&r); 846 for (i = 0; i < count; ++i) { 847 char* mod = bin_name(&r, NULL); 848 char* name = bin_name(&r, NULL); 849 uint8_t kind = bin_u8(&r); 850 if (kind == 0) { 851 uint32_t typeidx = bin_uleb(&r); 852 WasmFunc* f; 853 if (typeidx >= out->ntypes) 854 wasm_error(c, wasm_loc(0, 0), "wasm: bad import type index"); 855 f = wasm_add_func(c, out); 856 f->is_import = 1; 857 f->import_module = mod; 858 f->import_name = name; 859 f->typeidx = typeidx; 860 f->has_typeidx = 1; 861 wasm_func_set_params(c, out, f, out->types[typeidx].params, 862 out->types[typeidx].nparams); 863 wasm_func_set_results(c, out, f, out->types[typeidx].results, 864 out->types[typeidx].nresults); 865 } else if (kind == 1) { 866 WasmTable* t = wasm_add_table(c, out); 867 t->is_import = 1; 868 t->import_module = mod; 869 t->import_name = name; 870 t->elem_type = bin_val_type(&r, 1); 871 { 872 uint32_t flags = bin_uleb(&r); 873 if (flags & ~1u) 874 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported table limits"); 875 t->has_max = (flags & 1u) != 0; 876 t->min = bin_uleb(&r); 877 if (t->has_max) t->max = bin_uleb(&r); 878 } 879 } else if (kind == 2) { 880 uint32_t flags; 881 WasmMemory* mem = wasm_add_memory(c, out); 882 mem->is_import = 1; 883 mem->import_module = mod; 884 mem->import_name = name; 885 flags = bin_uleb(&r); 886 if (flags & ~7u) 887 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported memory limits"); 888 mem->has_max = (flags & 1u) != 0; 889 mem->shared = (flags & 2u) != 0; 890 mem->is64 = (flags & 4u) != 0; 891 mem->min_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r); 892 if (mem->has_max) 893 mem->max_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r); 894 } else if (kind == 3) { 895 WasmGlobal* g = wasm_add_global(c, out); 896 g->is_import = 1; 897 g->import_module = mod; 898 g->import_name = name; 899 g->type = bin_val_type(&r, 0); 900 g->mutable_ = bin_u8(&r); 901 if (g->mutable_ > 1u) 902 wasm_error(c, wasm_loc(0, 0), "wasm: bad global mutability"); 903 } else { 904 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported import kind"); 905 } 906 } 907 } else if (id == 3) { 908 uint32_t i, count = bin_uleb(&r); 909 for (i = 0; i < count; ++i) { 910 uint32_t typeidx = bin_uleb(&r); 911 WasmFunc* f; 912 if (typeidx >= out->ntypes) 913 wasm_error(c, wasm_loc(0, 0), "wasm: bad function type index"); 914 f = wasm_add_func(c, out); 915 f->typeidx = typeidx; 916 f->has_typeidx = 1; 917 wasm_func_set_params(c, out, f, out->types[typeidx].params, 918 out->types[typeidx].nparams); 919 wasm_func_set_results(c, out, f, out->types[typeidx].results, 920 out->types[typeidx].nresults); 921 nfunc_types++; 922 } 923 } else if (id == 5) { 924 uint32_t count = bin_uleb(&r); 925 for (uint32_t mi = 0; mi < count; ++mi) { 926 uint32_t flags = bin_uleb(&r); 927 WasmMemory* mem = wasm_add_memory(c, out); 928 if (flags & ~7u) 929 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported memory limits"); 930 mem->has_max = (flags & 1u) != 0; 931 mem->shared = (flags & 2u) != 0; 932 mem->is64 = (flags & 4u) != 0; 933 mem->min_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r); 934 if (mem->has_max) 935 mem->max_pages = mem->is64 ? bin_uleb64(&r) : bin_uleb(&r); 936 } 937 } else if (id == 4) { 938 uint32_t i, count = bin_uleb(&r); 939 for (i = 0; i < count; ++i) { 940 WasmTable* t = wasm_add_table(c, out); 941 uint32_t flags; 942 t->elem_type = bin_val_type(&r, 1); 943 flags = bin_uleb(&r); 944 if (flags & ~1u) 945 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported table limits"); 946 t->has_max = (flags & 1u) != 0; 947 t->min = bin_uleb(&r); 948 if (t->has_max) t->max = bin_uleb(&r); 949 } 950 } else if (id == 6) { 951 uint32_t i, count = bin_uleb(&r); 952 for (i = 0; i < count; ++i) { 953 WasmGlobal* g = wasm_add_global(c, out); 954 uint8_t op; 955 g->type = bin_val_type(&r, 0); 956 g->mutable_ = bin_u8(&r); 957 if (g->mutable_ > 1u) 958 wasm_error(c, wasm_loc(0, 0), "wasm: bad global mutability"); 959 op = bin_u8(&r); 960 switch (op) { 961 case 0x41: 962 g->init.kind = WASM_INSN_I32_CONST; 963 g->init.imm = bin_sleb(&r, 32); 964 break; 965 case 0x42: 966 g->init.kind = WASM_INSN_I64_CONST; 967 g->init.imm = bin_sleb(&r, 64); 968 break; 969 case 0x43: 970 g->init.kind = WASM_INSN_F32_CONST; 971 g->init.fp = bin_f32(&r); 972 break; 973 case 0x44: 974 g->init.kind = WASM_INSN_F64_CONST; 975 g->init.fp = bin_f64(&r); 976 break; 977 default: 978 wasm_error(c, wasm_loc(0, 0), 979 "wasm: unsupported global initializer"); 980 } 981 if (bin_u8(&r) != 0x0bu) 982 wasm_error(c, wasm_loc(0, 0), "wasm: malformed global initializer"); 983 } 984 } else if (id == 7) { 985 uint32_t i, count = bin_uleb(&r); 986 for (i = 0; i < count; ++i) { 987 char* name; 988 uint8_t kind; 989 uint32_t idx; 990 WasmExport* ex; 991 name = bin_name(&r, NULL); 992 kind = bin_u8(&r); 993 idx = bin_uleb(&r); 994 if (kind > 3u) wasm_error(c, wasm_loc(0, 0), "wasm: bad export kind"); 995 ex = wasm_add_export(c, out); 996 ex->name = name; 997 ex->kind = kind; 998 ex->index = idx; 999 if (kind == 0 && idx < out->nfuncs) { 1000 out->funcs[idx].export_name = 1001 wasm_strdup(out->heap, name, kit_slice_cstr(name).len); 1002 } else if (kind == 1 && idx < out->ntables) { 1003 out->tables[idx].export_name = 1004 wasm_strdup(out->heap, name, kit_slice_cstr(name).len); 1005 } else if (kind == 2 && idx < out->nmemories) { 1006 out->memories[idx].export_name = 1007 wasm_strdup(out->heap, name, kit_slice_cstr(name).len); 1008 } else if (kind == 3 && idx < out->nglobals) { 1009 out->globals[idx].export_name = 1010 wasm_strdup(out->heap, name, kit_slice_cstr(name).len); 1011 } 1012 } 1013 } else if (id == 8) { 1014 out->has_start = 1; 1015 out->start_func = bin_uleb(&r); 1016 } else if (id == 9) { 1017 uint32_t i, count = bin_uleb(&r); 1018 for (i = 0; i < count; ++i) { 1019 WasmElemSegment* e = wasm_add_elem(c, out); 1020 uint32_t flags = bin_uleb(&r); 1021 uint32_t n; 1022 e->elem_type = WASM_VAL_FUNCREF; 1023 if (flags == 0u) { 1024 e->mode = WASM_SEG_ACTIVE; 1025 e->tableidx = 0; 1026 if (bin_u8(&r) != 0x41) 1027 wasm_error(c, wasm_loc(0, 0), 1028 "wasm: expected i32.const element offset"); 1029 e->offset = bin_sleb(&r, 32); 1030 if (bin_u8(&r) != 0x0b || e->offset < 0) 1031 wasm_error(c, wasm_loc(0, 0), "wasm: bad element offset"); 1032 } else if (flags == 1u) { 1033 e->mode = WASM_SEG_PASSIVE; 1034 if (bin_u8(&r) != 0x00) 1035 wasm_error(c, wasm_loc(0, 0), 1036 "wasm: unsupported passive element kind"); 1037 } else if (flags == 2u) { 1038 e->mode = WASM_SEG_ACTIVE; 1039 e->tableidx = bin_uleb(&r); 1040 if (bin_u8(&r) != 0x41) 1041 wasm_error(c, wasm_loc(0, 0), 1042 "wasm: expected i32.const element offset"); 1043 e->offset = bin_sleb(&r, 32); 1044 if (bin_u8(&r) != 0x0b || e->offset < 0) 1045 wasm_error(c, wasm_loc(0, 0), "wasm: bad element offset"); 1046 if (bin_u8(&r) != 0x00) 1047 wasm_error(c, wasm_loc(0, 0), "wasm: unsupported element kind"); 1048 } else if (flags == 3u) { 1049 e->mode = WASM_SEG_DECLARATIVE; 1050 if (bin_u8(&r) != 0x00) 1051 wasm_error(c, wasm_loc(0, 0), 1052 "wasm: unsupported declarative element kind"); 1053 } else { 1054 wasm_error(c, wasm_loc(0, 0), 1055 "wasm: unsupported element segment flags 0x%x", flags); 1056 } 1057 n = bin_uleb(&r); 1058 for (uint32_t k = 0; k < n; ++k) 1059 wasm_elem_push_func(c, out, e, bin_uleb(&r)); 1060 } 1061 } else if (id == 10) { 1062 uint32_t i, count = bin_uleb(&r); 1063 uint32_t func_index = 0; 1064 if (count != nfunc_types) 1065 wasm_error(c, wasm_loc(0, 0), "wasm: function/code count mismatch"); 1066 for (i = 0; i < count; ++i) { 1067 uint32_t body_size = bin_uleb(&r); 1068 size_t body_end; 1069 uint32_t local_groups, j; 1070 uint32_t control_depth = 0; 1071 int saw_body_end = 0; 1072 WasmFunc* f; 1073 while (func_index < out->nfuncs && out->funcs[func_index].is_import) 1074 func_index++; 1075 if (func_index >= out->nfuncs) 1076 wasm_error(c, wasm_loc(0, 0), "wasm: code body without function"); 1077 f = &out->funcs[func_index++]; 1078 bin_need(&r, body_size); 1079 body_end = r.pos + body_size; 1080 local_groups = bin_uleb(&r); 1081 for (j = 0; j < local_groups; ++j) { 1082 uint32_t k, nlocals = bin_uleb(&r); 1083 WasmValType vt = bin_val_type(&r, 1); 1084 for (k = 0; k < nlocals; ++k) wasm_func_push_local(c, out, f, vt); 1085 } 1086 while (r.pos < body_end) { 1087 uint8_t op = bin_u8(&r); 1088 if (op == 0x0bu) { 1089 if (!control_depth) { 1090 saw_body_end = 1; 1091 break; 1092 } 1093 control_depth--; 1094 wasm_func_add_insn(c, out, f, WASM_INSN_END, 0); 1095 continue; 1096 } 1097 decode_body_insn(&r, out, f, op, &control_depth); 1098 } 1099 if (!saw_body_end) 1100 wasm_error(c, wasm_loc(0, 0), "wasm: function body missing end"); 1101 r.pos = body_end; 1102 } 1103 } else if (id == 11) { 1104 uint32_t i, count = bin_uleb(&r); 1105 for (i = 0; i < count; ++i) { 1106 WasmDataSegment* d = wasm_add_data(c, out); 1107 uint32_t flags = bin_uleb(&r); 1108 uint32_t n; 1109 if (flags == 0u) { 1110 d->mode = WASM_SEG_ACTIVE; 1111 d->memidx = 0; 1112 { 1113 uint8_t op = bin_u8(&r); 1114 if (op == 0x41) 1115 d->offset = bin_sleb(&r, 32); 1116 else if (op == 0x42) 1117 d->offset = bin_sleb(&r, 64); 1118 else 1119 wasm_error(c, wasm_loc(0, 0), "wasm: expected const data offset"); 1120 } 1121 if (bin_u8(&r) != 0x0b || d->offset < 0) 1122 wasm_error(c, wasm_loc(0, 0), "wasm: bad data offset"); 1123 } else if (flags == 1u) { 1124 d->mode = WASM_SEG_PASSIVE; 1125 } else if (flags == 2u) { 1126 d->mode = WASM_SEG_ACTIVE; 1127 d->memidx = bin_uleb(&r); 1128 { 1129 uint8_t op = bin_u8(&r); 1130 if (op == 0x41) 1131 d->offset = bin_sleb(&r, 32); 1132 else if (op == 0x42) 1133 d->offset = bin_sleb(&r, 64); 1134 else 1135 wasm_error(c, wasm_loc(0, 0), "wasm: expected const data offset"); 1136 } 1137 if (bin_u8(&r) != 0x0b || d->offset < 0) 1138 wasm_error(c, wasm_loc(0, 0), "wasm: bad data offset"); 1139 } else { 1140 wasm_error(c, wasm_loc(0, 0), 1141 "wasm: unsupported data segment flags 0x%x", flags); 1142 } 1143 n = bin_uleb(&r); 1144 bin_need(&r, n); 1145 wasm_data_set_bytes(c, out, d, r.data + r.pos, (uint64_t)n); 1146 r.pos += n; 1147 } 1148 } else if (id == 12) { 1149 /* Data count section. Conservatively accept and discard; bulk-memory 1150 * validation only needs it for forward-references during streaming 1151 * validation, which we don't do here. */ 1152 (void)bin_uleb(&r); 1153 } else { 1154 r.pos = end; 1155 } 1156 if (r.pos != end) 1157 wasm_error(c, wasm_loc(0, 0), "wasm: malformed section length"); 1158 } 1159 } 1160 1161 int wasm_is_binary(const KitSlice* input) { 1162 return input->len >= 4u && input->data[0] == 0x00 && input->data[1] == 0x61 && 1163 input->data[2] == 0x73 && input->data[3] == 0x6d; 1164 } 1165 1166 /* Decode exactly one instruction at data[pos..] into *out, returning the number 1167 * of bytes consumed (0 if none). The control-flow opcodes block/loop/if/end are 1168 * returned as plain instructions; callers that care about nesting track depth 1169 * themselves. `scratch` is a caller-owned reusable module (init via 1170 * wasm_module_init); its first function is reused as a decode buffer so this is 1171 * allocation-free after the first call. Malformed input is fatal, matching 1172 * wasm_decode_binary. */ 1173 size_t wasm_decode_one_insn(KitCompiler* c, WasmModule* scratch, 1174 const uint8_t* data, size_t len, size_t pos, 1175 WasmInsn* out) { 1176 BinReader r; 1177 WasmFunc* f; 1178 uint8_t op; 1179 uint32_t control_depth = 0; 1180 if (pos >= len) return 0; 1181 if (scratch->nfuncs == 0) (void)wasm_add_func(c, scratch); 1182 f = &scratch->funcs[0]; 1183 f->ninsns = 0; 1184 memset(&r, 0, sizeof r); 1185 r.c = c; 1186 r.data = data; 1187 r.len = len; 1188 r.pos = pos; 1189 r.module = scratch; 1190 op = bin_u8(&r); 1191 if (op == 0x0bu) { 1192 memset(out, 0, sizeof *out); 1193 out->kind = WASM_INSN_END; 1194 return r.pos - pos; 1195 } 1196 decode_body_insn(&r, scratch, f, op, &control_depth); 1197 if (f->ninsns == 0) return 0; 1198 *out = f->insns[f->ninsns - 1u]; 1199 return r.pos - pos; 1200 }