hex2pp.P1 (66900B)
1 ## hex2pp.P1 -- P1 implementation of the hex2++ assembler/linker. 2 ## 3 ## Mirrors hex2pp/hex2pp.c. See docs/HEX2pp.md for the full spec; brief: 4 ## 5 ## Input is scanned once. Label definitions are recorded into a table 6 ## on the fly; label references emit zero placeholders and append a 7 ## fixup record. After the scan, fixups are resolved against the 8 ## completed label table and patched into the output buffer. 9 ## 10 ## Active syntax: 11 ## digits in current byte mode -> raw bytes (HEX or BINARY) 12 ## :NAME -> label definition 13 ## SIGIL NAME [- OTHER] -> label reference (! @ $ ~ % &) 14 ## .align N [PATTERN] -> pad to N-byte boundary 15 ## .fill N B -> N copies of byte B 16 ## .scope / .endscope -> nestable local-label scope 17 ## .ptrsize N -> width of '%' and '&' (4 or 8) 18 ## # ... / ; ... -> line comment 19 ## 20 ## Multi-byte reference values are emitted little-endian by default. 21 ## 22 ## Invocation: hex2pp [-B ADDR] [-E|-e] [-b] [-N] IN OUT 23 ## 24 ## P1 ABI: a0..a3 arg/return, t0..t2 caller-saved temps. Non-leaf 25 ## functions use enter_0 / eret. Entry is the portable p1_main 26 ## (a0=argc, a1=argv); the backend-owned :_start stub captures argc/argv 27 ## from the native entry state and sys_exits p1_main's return value. 28 ## 29 ## chmod note: the seed P1 mnemonic table only exposes openat/read/write/ 30 ## exit. We encode the desired final mode (0750 or 0640) directly in 31 ## openat's mode argument at file-creation time, achieving the same 32 ## resulting file permissions as the C reference's fopen+chmod. 33 34 ## --- Caps ------------------------------------------------------------------ 35 ## Mirrors hex2pp.c constants. Stored as 8-byte little-endian. 36 DEFINE H2_INPUT_CAP 0000000100000000 37 DEFINE H2_OUTPUT_CAP 0000000800000000 38 DEFINE H2_TEXT_CAP 0000800000000000 39 DEFINE H2_LABEL_CAP 0000100000000000 40 DEFINE H2_TOKEN_CAP 0010000000000000 41 DEFINE H2_SCOPE_CAP 2000000000000000 42 DEFINE H2_FIXUP_CAP 0000100000000000 43 DEFINE H2_SCOPE_HISTORY_CAP 0000400000000000 44 45 ## openat / mode constants (Linux generic). 46 DEFINE H2_O_WRONLY_CREAT_TRUNC 4102000000000000 47 DEFINE H2_O_RDONLY 0000000000000000 48 DEFINE H2_MODE_0750 E801000000000000 49 DEFINE H2_MODE_0640 A001000000000000 50 DEFINE H2_AT_FDCWD 9CFFFFFFFFFFFFFF 51 52 DEFINE ZERO8 '0000000000000000' 53 DEFINE ZERO4 '00000000' 54 55 ## --- BSS layout (offsets from ELF_end) ------------------------------------- 56 ## Each "_ptr" is a one-word slot in the executable's static data; p1_main's 57 ## bss_init_loop initializes each to ELF_end + OFF_*. Arenas live past 58 ## ELF_end (covered by the segment's memsz; the loader zero-initializes). 59 ## 60 ## Region sizes (matching the C caps): 61 ## scope_stack 32 * 8 = 256 B 62 ## line_scratch = 64 B 63 ## name_buf = 4096 B (used by read_directive_name) 64 ## label_buf = 4096 B (unused since single-pass refactor) 65 ## other_buf = 4096 B (unused since single-pass refactor) 66 ## pat_buf = 4096 B 67 ## ev_bytes = 8 B 68 ## df_byte = 8 B 69 ## input_buf = 16 MiB 70 ## output_buf = 128 MiB 71 ## text_buf = 8 MiB 72 ## labels = 32 MiB (1<<20 * 32 B) 73 ## fixups = 96 MiB (1<<20 * 96 B) 74 ## scope_history = 32 MiB (1<<22 * 8 B) 75 ## 76 ## Compact cumulative offsets in 8-byte little-endian hex. 77 DEFINE H2_OFF_scope_stack 0000000000000000 78 DEFINE H2_OFF_line_scratch 0001000000000000 79 DEFINE H2_OFF_name_buf 4001000000000000 80 DEFINE H2_OFF_label_buf 4011000000000000 81 DEFINE H2_OFF_other_buf 4021000000000000 82 DEFINE H2_OFF_pat_buf 4031000000000000 83 DEFINE H2_OFF_ev_bytes 4041000000000000 84 DEFINE H2_OFF_df_byte 5041000000000000 85 ## input_buf: 0x00004200 + 16 MiB 86 ## output_buf: 0x01004200 + 128 MiB 87 ## text_buf: 0x09004200 + 8 MiB 88 ## labels: 0x09804200 + 32 MiB 89 ## fixups: 0x0B804200 + 96 MiB 90 ## scope_history: 0x11804200 + 32 MiB (end at ~313 MiB; ELF p_memsz is 512 MiB). 91 DEFINE H2_OFF_input_buf 0042000000000000 92 DEFINE H2_OFF_output_buf 0042000100000000 93 DEFINE H2_OFF_text_buf 0042000900000000 94 DEFINE H2_OFF_labels 0042800900000000 95 DEFINE H2_OFF_fixups 0042800B00000000 96 DEFINE H2_OFF_scope_history 0042801100000000 97 98 ## --- p1_main: argv parse -> load input -> two passes -> write -> exit ------ 99 100 :p1_main 101 enter_0 102 103 # Save argc / argv before anything clobbers them. 104 la_a2 &saved_argc 105 st_a0,a2,0 106 la_a2 &saved_argv 107 st_a1,a2,0 108 109 # Init BSS pointer slots from ELF_end via table walk. 110 la_t0 &ELF_end 111 la_t1 &bss_init_tbl 112 la_t2 &bss_init_tbl_end 113 :bss_init_loop 114 la_br &bss_init_done 115 beq_t1,t2 116 ld_a2,t1,0 117 ld_a3,t1,8 118 add_a3,a3,t0 119 st_a3,a2,0 120 addi_t1,t1,16 121 la_br &bss_init_loop 122 b 123 :bss_init_done 124 125 # Default ptrsize = 4. 126 li_t0 %4 %0 127 la_a2 &ptrsize 128 st_t0,a2,0 129 130 # ---- Argv loop -------------------------------------------------------- 131 # i = 1 132 li_t0 %1 %0 133 la_a2 &arg_idx 134 st_t0,a2,0 135 :arg_loop 136 la_a0 &arg_idx 137 ld_t0,a0,0 138 la_a1 &saved_argc 139 ld_t1,a1,0 140 la_br &arg_done 141 beq_t0,t1 142 la_br &arg_done 143 blt_t1,t0 144 145 # arg_ptr = argv[i] 146 la_a0 &saved_argv 147 ld_a1,a0,0 148 shli_t2,t0,3 149 add_a1,a1,t2 150 ld_a0,a1,0 151 la_a2 &arg_ptr 152 st_a0,a2,0 153 154 # Match against known short flags. 155 la_a1 &opt_B 156 li_a2 %2 %0 157 la_br &str_eq 158 call 159 la_br &arg_is_B 160 bnez_a0 161 162 la_a0 &arg_ptr 163 ld_a0,a0,0 164 la_a1 &opt_E 165 li_a2 %2 %0 166 la_br &str_eq 167 call 168 la_br &arg_is_big 169 bnez_a0 170 171 la_a0 &arg_ptr 172 ld_a0,a0,0 173 la_a1 &opt_e 174 li_a2 %2 %0 175 la_br &str_eq 176 call 177 la_br &arg_is_little 178 bnez_a0 179 180 la_a0 &arg_ptr 181 ld_a0,a0,0 182 la_a1 &opt_b 183 li_a2 %2 %0 184 la_br &str_eq 185 call 186 la_br &arg_is_binary 187 bnez_a0 188 189 la_a0 &arg_ptr 190 ld_a0,a0,0 191 la_a1 &opt_N 192 li_a2 %2 %0 193 la_br &str_eq 194 call 195 la_br &arg_is_nonexec 196 bnez_a0 197 198 # Unrecognised. If first byte is '-' (and string len > 1), error. 199 la_a0 &arg_ptr 200 ld_a0,a0,0 201 lb_t0,a0,0 202 li_t1 %45 %0 203 la_br &arg_is_positional 204 bne_t0,t1 205 lb_t0,a0,1 206 la_br &arg_is_positional 207 beqz_t0 208 la_br &err_unknown_arg 209 b 210 211 :arg_is_positional 212 # First positional = input path; second = output path; third = error. 213 la_a0 &input_path 214 ld_t0,a0,0 215 la_br &arg_pos_set_out 216 bnez_t0 217 la_a1 &arg_ptr 218 ld_t0,a1,0 219 st_t0,a0,0 220 la_br &arg_loop_next 221 b 222 :arg_pos_set_out 223 la_a0 &output_path 224 ld_t0,a0,0 225 la_br &err_extra_positional 226 bnez_t0 227 la_a1 &arg_ptr 228 ld_t0,a1,0 229 st_t0,a0,0 230 la_br &arg_loop_next 231 b 232 233 :arg_is_B 234 # -B requires a value in the next argv slot. 235 la_a0 &arg_idx 236 ld_t0,a0,0 237 addi_t0,t0,1 238 st_t0,a0,0 239 la_a1 &saved_argc 240 ld_t1,a1,0 241 la_br &err_missing_value 242 beq_t0,t1 243 la_br &err_missing_value 244 blt_t1,t0 245 la_a0 &saved_argv 246 ld_a1,a0,0 247 shli_t2,t0,3 248 add_a1,a1,t2 249 ld_a0,a1,0 250 la_br &parse_long 251 call 252 la_a1 &base_address 253 st_a0,a1,0 254 la_br &arg_loop_next 255 b 256 257 :arg_is_big 258 li_t0 %1 %0 259 la_a1 &big_endian 260 st_t0,a1,0 261 la_br &arg_loop_next 262 b 263 264 :arg_is_little 265 li_t0 %0 %0 266 la_a1 &big_endian 267 st_t0,a1,0 268 la_br &arg_loop_next 269 b 270 271 :arg_is_binary 272 li_t0 %1 %0 273 la_a1 &byte_mode 274 st_t0,a1,0 275 la_br &arg_loop_next 276 b 277 278 :arg_is_nonexec 279 li_t0 %1 %0 280 la_a1 &non_executable 281 st_t0,a1,0 282 la_br &arg_loop_next 283 b 284 285 :arg_loop_next 286 la_a0 &arg_idx 287 ld_t0,a0,0 288 addi_t0,t0,1 289 st_t0,a0,0 290 la_br &arg_loop 291 b 292 293 :arg_done 294 la_a0 &input_path 295 ld_t0,a0,0 296 la_br &err_missing_positional 297 beqz_t0 298 la_a0 &output_path 299 ld_t0,a0,0 300 la_br &err_missing_positional 301 beqz_t0 302 303 # ---- Load input file ------------------------------------------------- 304 la_br &load_input 305 call 306 307 # ---- Single scan: builds labels + fixup list ------------------------- 308 li_t0 %0 %0 309 la_a0 &ip 310 st_t0,a0,0 311 la_a0 &output_used 312 st_t0,a0,0 313 la_a0 &scope_depth 314 st_t0,a0,0 315 la_a0 &scope_seq 316 st_t0,a0,0 317 la_a0 &ptrsize_used 318 st_t0,a0,0 319 li_t0 %4 %0 320 la_a0 &ptrsize 321 st_t0,a0,0 322 la_br &process_input 323 call 324 la_a0 &scope_depth 325 ld_t0,a0,0 326 la_br &err_scope_unclosed 327 bnez_t0 328 329 # ---- Resolve fixups -------------------------------------------------- 330 la_br &patch_fixups 331 call 332 333 # Clear cur_path so any post-fixup error reports without file:line. 334 li_t0 %0 %0 335 la_a0 &cur_path 336 st_t0,a0,0 337 338 la_br &write_output 339 call 340 341 li_a0 %0 %0 342 eret 343 344 ## --- Input loader ---------------------------------------------------------- 345 ## load_input(): openat(input_path), read into input_buf until EOF. 346 :load_input 347 enter_0 348 # fd = openat(AT_FDCWD, input_path, O_RDONLY, 0) 349 li_a0 sys_openat 350 li_a1 H2_AT_FDCWD 351 la_a2 &input_path 352 ld_a2,a2,0 353 li_a3 H2_O_RDONLY 354 li_t0 %0 %0 355 syscall 356 la_br &err_open_input 357 bltz_a0 358 la_a1 &input_fd 359 st_a0,a1,0 360 361 :li_read_loop 362 la_a0 &input_len 363 ld_t0,a0,0 364 li_t1 H2_INPUT_CAP 365 la_br &err_input_too_big 366 beq_t0,t1 367 la_br &err_input_too_big 368 blt_t1,t0 369 370 # n = read(fd, input_buf + input_len, INPUT_CAP - input_len) 371 la_a0 &input_fd 372 ld_a1,a0,0 373 la_a2 &input_buf_ptr 374 ld_a2,a2,0 375 add_a2,a2,t0 376 sub_a3,t1,t0 377 li_a0 sys_read 378 syscall 379 la_br &li_eof 380 beqz_a0 381 la_br &err_read 382 bltz_a0 383 384 la_a1 &input_len 385 ld_t0,a1,0 386 add_t0,t0,a0 387 st_t0,a1,0 388 la_br &li_read_loop 389 b 390 391 :li_eof 392 eret 393 394 ## --- Process input: scan one pass over input_buf --------------------------- 395 :process_input 396 enter_0 397 # cur_path = input_path; cur_line = 1 398 la_a0 &input_path 399 ld_t0,a0,0 400 la_a1 &cur_path 401 st_t0,a1,0 402 li_t0 %1 %0 403 la_a1 &cur_line 404 st_t0,a1,0 405 406 # scan_pos = input_buf; scan_end = input_buf + input_len 407 la_a0 &input_buf_ptr 408 ld_t0,a0,0 409 la_a1 &scan_pos 410 st_t0,a1,0 411 la_a0 &input_len 412 ld_t1,a0,0 413 add_t0,t0,t1 414 la_a1 &scan_end 415 st_t0,a1,0 416 417 :scan_loop 418 la_br &skip_ws_and_comments 419 call 420 la_a0 &scan_pos 421 ld_t0,a0,0 422 la_a1 &scan_end 423 ld_t1,a1,0 424 la_br &scan_done 425 beq_t0,t1 426 la_br &scan_done 427 blt_t1,t0 428 lb_a0,t0,0 429 430 li_t1 %58 %0 431 la_br &handle_label_def 432 beq_a0,t1 433 li_t1 %46 %0 434 la_br &handle_directive 435 beq_a0,t1 436 li_t1 %33 %0 437 la_br &handle_ref 438 beq_a0,t1 439 li_t1 %64 %0 440 la_br &handle_ref 441 beq_a0,t1 442 li_t1 %36 %0 443 la_br &handle_ref 444 beq_a0,t1 445 li_t1 %126 %0 446 la_br &handle_ref 447 beq_a0,t1 448 li_t1 %37 %0 449 la_br &handle_ref 450 beq_a0,t1 451 li_t1 %38 %0 452 la_br &handle_ref 453 beq_a0,t1 454 la_br &is_byte_digit 455 call 456 la_br &handle_byte_stream 457 bnez_a0 458 la_br &err_unexpected_char 459 b 460 461 :handle_label_def 462 # consume ':' 463 la_a0 &scan_pos 464 ld_t0,a0,0 465 addi_t0,t0,1 466 st_t0,a0,0 467 # scan_name -> length in a0, pointer in sn_start (no copy). 468 la_br &scan_name 469 call 470 la_a1 &name_len 471 st_a0,a1,0 472 # dotted = (name[0] == '.') AND scope_depth > 0 473 la_a0 &sn_start 474 ld_a0,a0,0 475 lb_t0,a0,0 476 li_t1 %46 %0 477 la_br &handle_label_global 478 bne_t0,t1 479 la_a0 &scope_depth 480 ld_t0,a0,0 481 la_br &handle_label_global 482 beqz_t0 483 # scope_id = scope_stack[scope_depth-1] 484 addi_t0,t0,neg1 485 la_a1 &scope_stack_ptr 486 ld_a1,a1,0 487 shli_t2,t0,3 488 add_a1,a1,t2 489 ld_t0,a1,0 490 la_a2 &name_scope 491 st_t0,a2,0 492 la_br &handle_label_dispatch 493 b 494 :handle_label_global 495 li_t0 %0 %0 496 la_a2 &name_scope 497 st_t0,a2,0 498 :handle_label_dispatch 499 la_a0 &sn_start 500 ld_a0,a0,0 501 la_a1 &name_len 502 ld_a1,a1,0 503 la_a2 &name_scope 504 ld_a2,a2,0 505 la_br &define_label 506 call 507 la_br &scan_loop 508 b 509 510 :handle_directive 511 # consume '.' 512 la_a0 &scan_pos 513 ld_t0,a0,0 514 addi_t0,t0,1 515 st_t0,a0,0 516 la_a0 &name_buf_ptr 517 ld_a0,a0,0 518 li_a1 H2_TOKEN_CAP 519 la_br &read_directive_name 520 call 521 la_a1 &name_len 522 st_a0,a1,0 523 524 # Dispatch by length, then memcmp. 525 la_a0 &name_len 526 ld_t0,a0,0 527 li_t1 %5 %0 528 la_br &dir_check_4 529 bne_t0,t1 530 # Could be "align" or "scope". 531 la_a0 &name_buf_ptr 532 ld_a0,a0,0 533 la_a1 &kw_align 534 li_a2 %5 %0 535 la_br &mem_eq 536 call 537 la_br &dir_call_align 538 bnez_a0 539 la_a0 &name_buf_ptr 540 ld_a0,a0,0 541 la_a1 &kw_scope 542 li_a2 %5 %0 543 la_br &mem_eq 544 call 545 la_br &dir_call_scope 546 bnez_a0 547 la_br &err_unknown_directive 548 b 549 :dir_check_4 550 li_t1 %4 %0 551 la_br &dir_check_8 552 bne_t0,t1 553 la_a0 &name_buf_ptr 554 ld_a0,a0,0 555 la_a1 &kw_fill 556 li_a2 %4 %0 557 la_br &mem_eq 558 call 559 la_br &dir_call_fill 560 bnez_a0 561 la_br &err_unknown_directive 562 b 563 :dir_check_8 564 li_t1 %8 %0 565 la_br &dir_check_7 566 bne_t0,t1 567 la_a0 &name_buf_ptr 568 ld_a0,a0,0 569 la_a1 &kw_endscope 570 li_a2 %8 %0 571 la_br &mem_eq 572 call 573 la_br &dir_call_endscope 574 bnez_a0 575 la_br &err_unknown_directive 576 b 577 :dir_check_7 578 li_t1 %7 %0 579 la_br &err_unknown_directive 580 bne_t0,t1 581 la_a0 &name_buf_ptr 582 ld_a0,a0,0 583 la_a1 &kw_ptrsize 584 li_a2 %7 %0 585 la_br &mem_eq 586 call 587 la_br &dir_call_ptrsize 588 bnez_a0 589 la_br &err_unknown_directive 590 b 591 592 :dir_call_align 593 la_br &do_align 594 call 595 la_br &scan_loop 596 b 597 :dir_call_fill 598 la_br &do_fill 599 call 600 la_br &scan_loop 601 b 602 :dir_call_scope 603 la_br &do_scope_open 604 call 605 la_br &scan_loop 606 b 607 :dir_call_endscope 608 la_br &do_scope_close 609 call 610 la_br &scan_loop 611 b 612 :dir_call_ptrsize 613 la_br &do_ptrsize 614 call 615 la_br &scan_loop 616 b 617 618 :handle_ref 619 # a0 holds the sigil byte; advance past it then process_reference. 620 la_a1 &cur_sigil 621 st_a0,a1,0 622 la_a0 &scan_pos 623 ld_t0,a0,0 624 addi_t0,t0,1 625 st_t0,a0,0 626 la_br &process_reference 627 call 628 la_br &scan_loop 629 b 630 631 :handle_byte_stream 632 la_br &parse_byte_stream 633 call 634 la_br &scan_loop 635 b 636 637 :scan_done 638 eret 639 640 ## --- Lex helpers ----------------------------------------------------------- 641 642 ## skip_ws_and_comments(): advance scan_pos past whitespace and #/; comments. 643 ## Updates cur_line on '\n'. 644 :skip_ws_and_comments 645 enter_0 646 :swc_loop 647 la_a0 &scan_pos 648 ld_t0,a0,0 649 la_a1 &scan_end 650 ld_t1,a1,0 651 la_br &swc_done 652 beq_t0,t1 653 la_br &swc_done 654 blt_t1,t0 655 lb_a0,t0,0 656 la_br &is_space_any 657 call 658 la_br &swc_after_ws_check 659 beqz_a0 660 # whitespace: bump cur_line on '\n', advance scan_pos. 661 la_a0 &scan_pos 662 ld_t0,a0,0 663 lb_a0,t0,0 664 li_t1 %10 %0 665 la_br &swc_advance 666 bne_a0,t1 667 la_a1 &cur_line 668 ld_t2,a1,0 669 addi_t2,t2,1 670 st_t2,a1,0 671 :swc_advance 672 la_a0 &scan_pos 673 ld_t0,a0,0 674 addi_t0,t0,1 675 st_t0,a0,0 676 la_br &swc_loop 677 b 678 :swc_after_ws_check 679 # is_space_any clobbered a0; re-read the byte at scan_pos. 680 la_a0 &scan_pos 681 ld_t0,a0,0 682 lb_a0,t0,0 683 li_t1 %35 %0 684 la_br &swc_consume_comment 685 beq_a0,t1 686 li_t1 %59 %0 687 la_br &swc_consume_comment 688 beq_a0,t1 689 la_br &swc_done 690 b 691 :swc_consume_comment 692 :swc_cc_loop 693 la_a0 &scan_pos 694 ld_t0,a0,0 695 la_a1 &scan_end 696 ld_t1,a1,0 697 la_br &swc_loop 698 beq_t0,t1 699 la_br &swc_loop 700 blt_t1,t0 701 lb_a0,t0,0 702 li_t1 %10 %0 703 la_br &swc_loop 704 beq_a0,t1 705 addi_t0,t0,1 706 la_a1 &scan_pos 707 st_t0,a1,0 708 la_br &swc_cc_loop 709 b 710 :swc_done 711 eret 712 713 ## skip_inline_ws(): like skip_ws_and_comments but does NOT cross '\n'. 714 :skip_inline_ws 715 enter_0 716 :siw_loop 717 la_a0 &scan_pos 718 ld_t0,a0,0 719 la_a1 &scan_end 720 ld_t1,a1,0 721 la_br &siw_done 722 beq_t0,t1 723 la_br &siw_done 724 blt_t1,t0 725 lb_a0,t0,0 726 li_t1 %32 %0 727 la_br &siw_advance 728 beq_a0,t1 729 li_t1 %9 %0 730 la_br &siw_advance 731 beq_a0,t1 732 li_t1 %13 %0 733 la_br &siw_advance 734 beq_a0,t1 735 li_t1 %12 %0 736 la_br &siw_advance 737 beq_a0,t1 738 li_t1 %11 %0 739 la_br &siw_advance 740 beq_a0,t1 741 li_t1 %35 %0 742 la_br &siw_consume_comment 743 beq_a0,t1 744 li_t1 %59 %0 745 la_br &siw_consume_comment 746 beq_a0,t1 747 la_br &siw_done 748 b 749 :siw_advance 750 la_a0 &scan_pos 751 ld_t0,a0,0 752 addi_t0,t0,1 753 st_t0,a0,0 754 la_br &siw_loop 755 b 756 :siw_consume_comment 757 :siw_cc_loop 758 la_a0 &scan_pos 759 ld_t0,a0,0 760 la_a1 &scan_end 761 ld_t1,a1,0 762 la_br &siw_done 763 beq_t0,t1 764 la_br &siw_done 765 blt_t1,t0 766 lb_a0,t0,0 767 li_t1 %10 %0 768 la_br &siw_done 769 beq_a0,t1 770 addi_t0,t0,1 771 la_a1 &scan_pos 772 st_t0,a1,0 773 la_br &siw_cc_loop 774 b 775 :siw_done 776 eret 777 778 ## is_space_any(a0=c) -> a0=0/1. Whitespace = ' ' \t \n \r \f \v. 779 :is_space_any 780 li_t0 %32 %0 781 la_br &isa_yes 782 beq_a0,t0 783 li_t0 %9 %0 784 la_br &isa_yes 785 beq_a0,t0 786 li_t0 %10 %0 787 la_br &isa_yes 788 beq_a0,t0 789 li_t0 %13 %0 790 la_br &isa_yes 791 beq_a0,t0 792 li_t0 %12 %0 793 la_br &isa_yes 794 beq_a0,t0 795 li_t0 %11 %0 796 la_br &isa_yes 797 beq_a0,t0 798 li_a0 %0 %0 799 ret 800 :isa_yes 801 li_a0 %1 %0 802 ret 803 804 ## is_name_terminator(a0=c) -> a0=0/1. Terminators: ws, '-', '>', '#', ';'. 805 ## Spills c into a BSS slot since is_space_any clobbers a0. 806 :is_name_terminator 807 enter_0 808 la_a1 &nt_c 809 st_a0,a1,0 810 la_br &is_space_any 811 call 812 la_br &nt_yes 813 bnez_a0 814 la_a0 &nt_c 815 ld_a0,a0,0 816 li_t0 %45 %0 817 la_br &nt_yes 818 beq_a0,t0 819 li_t0 %62 %0 820 la_br &nt_yes 821 beq_a0,t0 822 li_t0 %35 %0 823 la_br &nt_yes 824 beq_a0,t0 825 li_t0 %59 %0 826 la_br &nt_yes 827 beq_a0,t0 828 li_a0 %0 %0 829 eret 830 :nt_yes 831 li_a0 %1 %0 832 eret 833 834 ## is_byte_digit(a0=c) -> a0=0/1. Mode-aware (HEX vs BINARY). 835 :is_byte_digit 836 la_a1 &byte_mode 837 ld_t0,a1,0 838 la_br &ibd_bin 839 bnez_t0 840 # HEX: 0-9, a-f, A-F 841 li_t1 %48 %0 842 la_br &ibd_no 843 blt_a0,t1 844 li_t1 %57 %0 845 la_br &ibd_yes 846 blt_a0,t1 847 la_br &ibd_yes 848 beq_a0,t1 849 li_t1 %65 %0 850 la_br &ibd_no 851 blt_a0,t1 852 li_t1 %70 %0 853 la_br &ibd_yes 854 blt_a0,t1 855 la_br &ibd_yes 856 beq_a0,t1 857 li_t1 %97 %0 858 la_br &ibd_no 859 blt_a0,t1 860 li_t1 %102 %0 861 la_br &ibd_yes 862 blt_a0,t1 863 la_br &ibd_yes 864 beq_a0,t1 865 la_br &ibd_no 866 b 867 :ibd_bin 868 li_t1 %48 %0 869 la_br &ibd_yes 870 beq_a0,t1 871 li_t1 %49 %0 872 la_br &ibd_yes 873 beq_a0,t1 874 la_br &ibd_no 875 b 876 :ibd_yes 877 li_a0 %1 %0 878 ret 879 :ibd_no 880 li_a0 %0 %0 881 ret 882 883 ## byte_digit_value(a0=c) -> a0=value (0..15). Caller guarantees c is a 884 ## valid digit for the current byte mode. 885 :byte_digit_value 886 li_t0 %57 %0 887 la_br &bdv_alpha 888 blt_t0,a0 889 li_t1 %48 %0 890 sub_a0,a0,t1 891 ret 892 :bdv_alpha 893 li_t0 %96 %0 894 la_br &bdv_lower 895 blt_t0,a0 896 li_t1 %55 %0 897 sub_a0,a0,t1 898 ret 899 :bdv_lower 900 li_t1 %87 %0 901 sub_a0,a0,t1 902 ret 903 904 ## byte_digit_count() -> a0. 2 for HEX, 8 for BINARY. 905 :byte_digit_count 906 la_a0 &byte_mode 907 ld_t0,a0,0 908 la_br &bdc_bin 909 bnez_t0 910 li_a0 %2 %0 911 ret 912 :bdc_bin 913 li_a0 %8 %0 914 ret 915 916 ## scan_name() -> a0=length, sn_start=pointer into input buffer at name start. 917 ## Advances scan_pos past the name. Fatal on empty. 918 :scan_name 919 enter_0 920 la_a0 &scan_pos 921 ld_t0,a0,0 922 la_a1 &sn_start 923 st_t0,a1,0 924 :sn_loop 925 la_a0 &scan_pos 926 ld_t0,a0,0 927 la_a1 &scan_end 928 ld_t1,a1,0 929 la_br &sn_done 930 beq_t0,t1 931 la_br &sn_done 932 blt_t1,t0 933 lb_a0,t0,0 934 la_br &is_name_terminator 935 call 936 la_br &sn_done 937 bnez_a0 938 la_a0 &scan_pos 939 ld_t0,a0,0 940 addi_t0,t0,1 941 st_t0,a0,0 942 la_br &sn_loop 943 b 944 :sn_done 945 la_a0 &scan_pos 946 ld_t0,a0,0 947 la_a1 &sn_start 948 ld_t1,a1,0 949 sub_a0,t0,t1 950 la_br &err_empty_name 951 beqz_a0 952 eret 953 954 ## read_name(a0=out_buf, a1=max) -> a0=length. Reads scan_pos into out_buf 955 ## until is_name_terminator or scan_end. Fatal on overflow / empty. 956 ## (Kept for reference; superseded by scan_name in single-pass refactor.) 957 :read_name 958 enter_0 959 la_a2 &rn_out 960 st_a0,a2,0 961 la_a2 &rn_max 962 st_a1,a2,0 963 li_t0 %0 %0 964 la_a2 &rn_n 965 st_t0,a2,0 966 :rn_loop 967 la_a0 &scan_pos 968 ld_t0,a0,0 969 la_a1 &scan_end 970 ld_t1,a1,0 971 la_br &rn_done 972 beq_t0,t1 973 la_br &rn_done 974 blt_t1,t0 975 lb_a0,t0,0 976 la_br &is_name_terminator 977 call 978 la_br &rn_done 979 bnez_a0 980 la_a1 &rn_n 981 ld_t0,a1,0 982 la_a0 &rn_max 983 ld_t1,a0,0 984 la_br &err_name_too_long 985 beq_t0,t1 986 # store char 987 la_a0 &scan_pos 988 ld_a0,a0,0 989 lb_a3,a0,0 990 la_a1 &rn_out 991 ld_a1,a1,0 992 add_a1,a1,t0 993 sb_a3,a1,0 994 addi_t0,t0,1 995 la_a1 &rn_n 996 st_t0,a1,0 997 la_a0 &scan_pos 998 ld_t0,a0,0 999 addi_t0,t0,1 1000 st_t0,a0,0 1001 la_br &rn_loop 1002 b 1003 :rn_done 1004 la_a1 &rn_n 1005 ld_a0,a1,0 1006 la_br &err_empty_name 1007 beqz_a0 1008 eret 1009 1010 ## read_directive_name(a0=out_buf, a1=max) -> a0=length. Like read_name but 1011 ## terminates on first non-alpha byte. 1012 :read_directive_name 1013 enter_0 1014 la_a2 &rn_out 1015 st_a0,a2,0 1016 la_a2 &rn_max 1017 st_a1,a2,0 1018 li_t0 %0 %0 1019 la_a2 &rn_n 1020 st_t0,a2,0 1021 :rdn_loop 1022 la_a0 &scan_pos 1023 ld_t0,a0,0 1024 la_a1 &scan_end 1025 ld_t1,a1,0 1026 la_br &rdn_done 1027 beq_t0,t1 1028 la_br &rdn_done 1029 blt_t1,t0 1030 lb_a0,t0,0 1031 # accept [A-Za-z] 1032 li_t1 %65 %0 1033 la_br &rdn_check_lower 1034 blt_a0,t1 1035 li_t1 %90 %0 1036 la_br &rdn_consume 1037 blt_a0,t1 1038 la_br &rdn_consume 1039 beq_a0,t1 1040 :rdn_check_lower 1041 li_t1 %97 %0 1042 la_br &rdn_done 1043 blt_a0,t1 1044 li_t1 %122 %0 1045 la_br &rdn_consume 1046 blt_a0,t1 1047 la_br &rdn_consume 1048 beq_a0,t1 1049 la_br &rdn_done 1050 b 1051 :rdn_consume 1052 la_a1 &rn_n 1053 ld_t0,a1,0 1054 la_a2 &rn_max 1055 ld_t1,a2,0 1056 la_br &err_name_too_long 1057 beq_t0,t1 1058 la_a2 &rn_out 1059 ld_a2,a2,0 1060 add_a2,a2,t0 1061 sb_a0,a2,0 1062 addi_t0,t0,1 1063 la_a1 &rn_n 1064 st_t0,a1,0 1065 la_a0 &scan_pos 1066 ld_t0,a0,0 1067 addi_t0,t0,1 1068 st_t0,a0,0 1069 la_br &rdn_loop 1070 b 1071 :rdn_done 1072 la_a1 &rn_n 1073 ld_a0,a1,0 1074 la_br &err_empty_directive 1075 beqz_a0 1076 eret 1077 1078 ## read_decimal() -> a0=value. Fatal on no digits. 1079 :read_decimal 1080 enter_0 1081 li_t0 %0 %0 1082 la_a0 &rd_val 1083 st_t0,a0,0 1084 la_a0 &rd_saw 1085 st_t0,a0,0 1086 :rd_loop 1087 la_a0 &scan_pos 1088 ld_t0,a0,0 1089 la_a1 &scan_end 1090 ld_t1,a1,0 1091 la_br &rd_done 1092 beq_t0,t1 1093 la_br &rd_done 1094 blt_t1,t0 1095 lb_a0,t0,0 1096 li_t1 %48 %0 1097 la_br &rd_done 1098 blt_a0,t1 1099 li_t1 %57 %0 1100 la_br &rd_done 1101 blt_t1,a0 1102 # acc = acc * 10 + (c - '0') 1103 la_a1 &rd_val 1104 ld_a2,a1,0 1105 li_t1 %10 %0 1106 mul_a2,a2,t1 1107 li_t1 %48 %0 1108 sub_a0,a0,t1 1109 add_a2,a2,a0 1110 st_a2,a1,0 1111 li_t0 %1 %0 1112 la_a1 &rd_saw 1113 st_t0,a1,0 1114 la_a0 &scan_pos 1115 ld_t0,a0,0 1116 addi_t0,t0,1 1117 st_t0,a0,0 1118 la_br &rd_loop 1119 b 1120 :rd_done 1121 la_a1 &rd_saw 1122 ld_t0,a1,0 1123 la_br &err_expected_decimal 1124 beqz_t0 1125 la_a1 &rd_val 1126 ld_a0,a1,0 1127 eret 1128 1129 ## --- Byte stream / single byte literal ------------------------------------- 1130 1131 ## parse_byte_stream(): consume free-flowing digits (intermixed with ws and 1132 ## #/; comments) and emit_byte them. Stops at first non-digit non-ws 1133 ## non-comment byte. 1134 :parse_byte_stream 1135 enter_0 1136 li_t0 %0 %0 1137 la_a0 &pbs_acc 1138 st_t0,a0,0 1139 la_a0 &pbs_have 1140 st_t0,a0,0 1141 :pbs_loop 1142 la_a0 &scan_pos 1143 ld_t0,a0,0 1144 la_a1 &scan_end 1145 ld_t1,a1,0 1146 la_br &pbs_done 1147 beq_t0,t1 1148 la_br &pbs_done 1149 blt_t1,t0 1150 lb_a0,t0,0 1151 la_br &is_space_any 1152 call 1153 la_br &pbs_consume_ws 1154 bnez_a0 1155 la_a0 &scan_pos 1156 ld_t0,a0,0 1157 lb_a0,t0,0 1158 li_t1 %35 %0 1159 la_br &pbs_consume_comment 1160 beq_a0,t1 1161 li_t1 %59 %0 1162 la_br &pbs_consume_comment 1163 beq_a0,t1 1164 la_br &is_byte_digit 1165 call 1166 la_br &pbs_done 1167 beqz_a0 1168 # consume one digit 1169 la_a0 &scan_pos 1170 ld_t0,a0,0 1171 lb_a0,t0,0 1172 addi_t0,t0,1 1173 la_a1 &scan_pos 1174 st_t0,a1,0 1175 la_a1 &pbs_c 1176 st_a0,a1,0 1177 # acc = (acc << shift) | digit 1178 la_a1 &byte_mode 1179 ld_t1,a1,0 1180 la_br &pbs_bin 1181 bnez_t1 1182 # HEX: shift 4 + digit_value 1183 la_a1 &pbs_acc 1184 ld_t0,a1,0 1185 shli_a3,t0,4 1186 la_a1 &pbs_c 1187 ld_a0,a1,0 1188 la_br &byte_digit_value 1189 call 1190 add_a3,a3,a0 1191 la_a1 &pbs_acc 1192 st_a3,a1,0 1193 la_br &pbs_bump 1194 b 1195 :pbs_bin 1196 la_a1 &pbs_acc 1197 ld_t0,a1,0 1198 shli_a3,t0,1 1199 la_a1 &pbs_c 1200 ld_a0,a1,0 1201 li_t1 %48 %0 1202 sub_a0,a0,t1 1203 add_a3,a3,a0 1204 la_a1 &pbs_acc 1205 st_a3,a1,0 1206 :pbs_bump 1207 la_a0 &pbs_have 1208 ld_t0,a0,0 1209 addi_t0,t0,1 1210 st_t0,a0,0 1211 la_br &byte_digit_count 1212 call 1213 la_a1 &pbs_have 1214 ld_t0,a1,0 1215 la_br &pbs_loop 1216 bne_t0,a0 1217 # full byte: emit 1218 la_a1 &pbs_acc 1219 ld_a0,a1,0 1220 andi_a0,a0,255 1221 la_br &emit_byte 1222 call 1223 li_t0 %0 %0 1224 la_a0 &pbs_acc 1225 st_t0,a0,0 1226 la_a0 &pbs_have 1227 st_t0,a0,0 1228 la_br &pbs_loop 1229 b 1230 :pbs_consume_ws 1231 la_a0 &scan_pos 1232 ld_t0,a0,0 1233 lb_a0,t0,0 1234 li_t1 %10 %0 1235 la_br &pbs_ws_advance 1236 bne_a0,t1 1237 la_a1 &cur_line 1238 ld_t2,a1,0 1239 addi_t2,t2,1 1240 st_t2,a1,0 1241 :pbs_ws_advance 1242 la_a0 &scan_pos 1243 ld_t0,a0,0 1244 addi_t0,t0,1 1245 st_t0,a0,0 1246 la_br &pbs_loop 1247 b 1248 :pbs_consume_comment 1249 :pbs_cc_loop 1250 la_a0 &scan_pos 1251 ld_t0,a0,0 1252 la_a1 &scan_end 1253 ld_t1,a1,0 1254 la_br &pbs_loop 1255 beq_t0,t1 1256 la_br &pbs_loop 1257 blt_t1,t0 1258 lb_a0,t0,0 1259 li_t1 %10 %0 1260 la_br &pbs_loop 1261 beq_a0,t1 1262 addi_t0,t0,1 1263 la_a1 &scan_pos 1264 st_t0,a1,0 1265 la_br &pbs_cc_loop 1266 b 1267 :pbs_done 1268 la_a0 &pbs_have 1269 ld_t0,a0,0 1270 la_br &err_byte_stream_short 1271 bnez_t0 1272 eret 1273 1274 ## parse_one_byte(a0=out_addr): read a single byte literal (exactly 1275 ## byte_digit_count contiguous digits, no internal whitespace). 1276 :parse_one_byte 1277 enter_0 1278 la_a1 &p1b_out 1279 st_a0,a1,0 1280 li_t0 %0 %0 1281 la_a1 &p1b_acc 1282 st_t0,a1,0 1283 la_a1 &p1b_have 1284 st_t0,a1,0 1285 :p1b_loop 1286 la_a0 &scan_pos 1287 ld_t0,a0,0 1288 la_a1 &scan_end 1289 ld_t1,a1,0 1290 la_br &p1b_done 1291 beq_t0,t1 1292 la_br &p1b_done 1293 blt_t1,t0 1294 lb_a0,t0,0 1295 la_br &is_byte_digit 1296 call 1297 la_br &p1b_done 1298 beqz_a0 1299 la_a0 &scan_pos 1300 ld_t0,a0,0 1301 lb_a0,t0,0 1302 addi_t0,t0,1 1303 la_a1 &scan_pos 1304 st_t0,a1,0 1305 la_a1 &p1b_c 1306 st_a0,a1,0 1307 la_a1 &byte_mode 1308 ld_t1,a1,0 1309 la_br &p1b_bin 1310 bnez_t1 1311 la_a1 &p1b_acc 1312 ld_t0,a1,0 1313 shli_a3,t0,4 1314 la_a1 &p1b_c 1315 ld_a0,a1,0 1316 la_br &byte_digit_value 1317 call 1318 add_a3,a3,a0 1319 la_a1 &p1b_acc 1320 st_a3,a1,0 1321 la_br &p1b_bump 1322 b 1323 :p1b_bin 1324 la_a1 &p1b_acc 1325 ld_t0,a1,0 1326 shli_a3,t0,1 1327 la_a1 &p1b_c 1328 ld_a0,a1,0 1329 li_t1 %48 %0 1330 sub_a0,a0,t1 1331 add_a3,a3,a0 1332 la_a1 &p1b_acc 1333 st_a3,a1,0 1334 :p1b_bump 1335 la_a0 &p1b_have 1336 ld_t0,a0,0 1337 addi_t0,t0,1 1338 st_t0,a0,0 1339 la_br &byte_digit_count 1340 call 1341 la_a1 &p1b_have 1342 ld_t0,a1,0 1343 la_br &p1b_loop 1344 bne_t0,a0 1345 # got full byte: write to *out_addr and return 1346 la_a1 &p1b_acc 1347 ld_a0,a1,0 1348 andi_a0,a0,255 1349 la_a1 &p1b_out 1350 ld_a1,a1,0 1351 sb_a0,a1,0 1352 eret 1353 :p1b_done 1354 la_a0 &p1b_have 1355 ld_t0,a0,0 1356 la_br &err_byte_lit_bad 1357 bnez_t0 1358 la_br &err_byte_lit_bad 1359 b 1360 1361 ## --- Label table ----------------------------------------------------------- 1362 1363 ## intern(a0=src, a1=len) -> a0=offset into text_buf. Copies bytes plus a 1364 ## NUL terminator. 1365 :intern 1366 enter_0 1367 la_a2 &intern_src 1368 st_a0,a2,0 1369 la_a2 &intern_len 1370 st_a1,a2,0 1371 la_a2 &text_used 1372 ld_a3,a2,0 1373 la_a2 &intern_orig 1374 st_a3,a2,0 1375 # if (text_used + len + 1 > TEXT_CAP) fatal 1376 add_a2,a3,a1 1377 addi_a2,a2,1 1378 li_t0 H2_TEXT_CAP 1379 la_br &err_text_overflow 1380 blt_t0,a2 1381 # dst = text_buf + text_used 1382 la_a0 &text_buf_ptr 1383 ld_a0,a0,0 1384 add_a0,a0,a3 1385 la_a2 &intern_dst 1386 st_a0,a2,0 1387 li_t0 %0 %0 1388 la_a1 &intern_i 1389 st_t0,a1,0 1390 :intern_copy_loop 1391 la_a0 &intern_i 1392 ld_t0,a0,0 1393 la_a1 &intern_len 1394 ld_t1,a1,0 1395 la_br &intern_copy_done 1396 beq_t0,t1 1397 la_a0 &intern_src 1398 ld_a0,a0,0 1399 add_a0,a0,t0 1400 lb_a0,a0,0 1401 la_a2 &intern_dst 1402 ld_a2,a2,0 1403 add_a2,a2,t0 1404 sb_a0,a2,0 1405 addi_t0,t0,1 1406 la_a1 &intern_i 1407 st_t0,a1,0 1408 la_br &intern_copy_loop 1409 b 1410 :intern_copy_done 1411 # NUL terminator 1412 la_a2 &intern_dst 1413 ld_a2,a2,0 1414 la_a1 &intern_len 1415 ld_t0,a1,0 1416 add_a2,a2,t0 1417 li_t1 %0 %0 1418 sb_t1,a2,0 1419 # text_used += len + 1 1420 la_a2 &text_used 1421 ld_a3,a2,0 1422 la_a1 &intern_len 1423 ld_a1,a1,0 1424 add_a3,a3,a1 1425 addi_a3,a3,1 1426 st_a3,a2,0 1427 la_a0 &intern_orig 1428 ld_a0,a0,0 1429 eret 1430 1431 ## label_addr(a0=index) -> a0 = &labels[index]. Each label is 32 B. 1432 :label_addr 1433 li_t0 %32 %0 1434 mul_a0,a0,t0 1435 la_a1 &labels_ptr 1436 ld_a1,a1,0 1437 add_a0,a0,a1 1438 ret 1439 1440 ## name_eq(a0=label_ptr, a1=src, a2=len) -> a0=0/1. 1441 :name_eq 1442 enter_0 1443 la_a3 &ne_label 1444 st_a0,a3,0 1445 la_a3 &ne_src 1446 st_a1,a3,0 1447 la_a3 &ne_len 1448 st_a2,a3,0 1449 # if (label->name_len != len) return 0 1450 ld_t0,a0,8 1451 la_br &ne_no 1452 bne_t0,a2 1453 # bytes equal? 1454 la_a0 &ne_label 1455 ld_a0,a0,0 1456 ld_a3,a0,0 1457 la_a0 &text_buf_ptr 1458 ld_a0,a0,0 1459 add_a0,a0,a3 1460 la_a1 &ne_src 1461 ld_a1,a1,0 1462 la_a2 &ne_len 1463 ld_a2,a2,0 1464 la_br &mem_eq 1465 call 1466 eret 1467 :ne_no 1468 li_a0 %0 %0 1469 eret 1470 1471 ## define_label(a0=src, a1=len, a2=scope_id). First definition wins. 1472 :define_label 1473 enter_0 1474 la_a3 &dl_src 1475 st_a0,a3,0 1476 la_a3 &dl_len 1477 st_a1,a3,0 1478 la_a3 &dl_scope 1479 st_a2,a3,0 1480 la_a0 &label_count 1481 ld_t0,a0,0 1482 li_t1 H2_LABEL_CAP 1483 la_br &err_too_many_labels 1484 beq_t0,t1 1485 la_br &err_too_many_labels 1486 blt_t1,t0 1487 # name_off = intern(src, len) 1488 la_a0 &dl_src 1489 ld_a0,a0,0 1490 la_a1 &dl_len 1491 ld_a1,a1,0 1492 la_br &intern 1493 call 1494 la_a3 &dl_name_off 1495 st_a0,a3,0 1496 # &labels[label_count] 1497 la_a0 &label_count 1498 ld_a0,a0,0 1499 la_br &label_addr 1500 call 1501 la_a3 &dl_label 1502 st_a0,a3,0 1503 # name_off 1504 la_a1 &dl_name_off 1505 ld_t0,a1,0 1506 st_t0,a0,0 1507 # name_len 1508 la_a1 &dl_len 1509 ld_t0,a1,0 1510 st_t0,a0,8 1511 # target_ip 1512 la_a1 &ip 1513 ld_t0,a1,0 1514 st_t0,a0,16 1515 # scope_id 1516 la_a1 &dl_scope 1517 ld_t0,a1,0 1518 st_t0,a0,24 1519 # label_count++ 1520 la_a0 &label_count 1521 ld_t0,a0,0 1522 addi_t0,t0,1 1523 st_t0,a0,0 1524 eret 1525 1526 ## lookup_label_in(a0=src, a1=len, a2=stack_ptr, a3=depth) -> a0=target_ip. 1527 :lookup_label_in 1528 enter_0 1529 la_t1 &ll_src 1530 st_a0,t1,0 1531 la_t1 &ll_len 1532 st_a1,t1,0 1533 la_t1 &ll_stack 1534 st_a2,t1,0 1535 la_t1 &ll_depth 1536 st_a3,t1,0 1537 # dotted? (first byte == '.' AND depth > 0) 1538 lb_t0,a0,0 1539 li_t1 %46 %0 1540 la_br &ll_undotted 1541 bne_t0,t1 1542 la_br &ll_undotted 1543 beqz_a3 1544 addi_t0,a3,neg1 1545 la_a1 &ll_d 1546 st_t0,a1,0 1547 :ll_dot_outer 1548 la_a0 &ll_d 1549 ld_t0,a0,0 1550 la_br &err_undefined_local 1551 bltz_t0 1552 la_a1 &ll_stack 1553 ld_a1,a1,0 1554 shli_t2,t0,3 1555 add_a1,a1,t2 1556 ld_t1,a1,0 1557 la_a0 &ll_sid 1558 st_t1,a0,0 1559 li_t0 %0 %0 1560 la_a0 &ll_i 1561 st_t0,a0,0 1562 :ll_dot_inner 1563 la_a0 &ll_i 1564 ld_t0,a0,0 1565 la_a1 &label_count 1566 ld_t1,a1,0 1567 la_br &ll_dot_next_d 1568 beq_t0,t1 1569 mov_a0,t0 1570 la_br &label_addr 1571 call 1572 la_a3 &ll_label 1573 st_a0,a3,0 1574 ld_t0,a0,24 1575 la_a1 &ll_sid 1576 ld_t1,a1,0 1577 la_br &ll_dot_inner_next 1578 bne_t0,t1 1579 la_a0 &ll_label 1580 ld_a0,a0,0 1581 la_a1 &ll_src 1582 ld_a1,a1,0 1583 la_a2 &ll_len 1584 ld_a2,a2,0 1585 la_br &name_eq 1586 call 1587 la_br &ll_dot_inner_next 1588 beqz_a0 1589 la_a0 &ll_label 1590 ld_a0,a0,0 1591 ld_a0,a0,16 1592 eret 1593 :ll_dot_inner_next 1594 la_a0 &ll_i 1595 ld_t0,a0,0 1596 addi_t0,t0,1 1597 st_t0,a0,0 1598 la_br &ll_dot_inner 1599 b 1600 :ll_dot_next_d 1601 la_a0 &ll_d 1602 ld_t0,a0,0 1603 addi_t0,t0,neg1 1604 st_t0,a0,0 1605 la_br &ll_dot_outer 1606 b 1607 1608 :ll_undotted 1609 li_t0 %0 %0 1610 la_a0 &ll_i 1611 st_t0,a0,0 1612 :ll_undotted_loop 1613 la_a0 &ll_i 1614 ld_t0,a0,0 1615 la_a1 &label_count 1616 ld_t1,a1,0 1617 la_br &err_undefined_label 1618 beq_t0,t1 1619 mov_a0,t0 1620 la_br &label_addr 1621 call 1622 la_a3 &ll_label 1623 st_a0,a3,0 1624 ld_t0,a0,24 1625 la_br &ll_undotted_next 1626 bnez_t0 1627 la_a0 &ll_label 1628 ld_a0,a0,0 1629 la_a1 &ll_src 1630 ld_a1,a1,0 1631 la_a2 &ll_len 1632 ld_a2,a2,0 1633 la_br &name_eq 1634 call 1635 la_br &ll_undotted_next 1636 beqz_a0 1637 la_a0 &ll_label 1638 ld_a0,a0,0 1639 ld_a0,a0,16 1640 eret 1641 :ll_undotted_next 1642 la_a0 &ll_i 1643 ld_t0,a0,0 1644 addi_t0,t0,1 1645 st_t0,a0,0 1646 la_br &ll_undotted_loop 1647 b 1648 1649 ## --- Reference processor --------------------------------------------------- 1650 ## process_reference(): cur_sigil already set; scan_pos already past sigil. 1651 ## Captures label name span (and optional -OTHER), reserves placeholder bytes, 1652 ## and appends a Fixup record. Resolution happens later in patch_fixups. 1653 :process_reference 1654 enter_0 1655 la_br &set_sigil_info 1656 call 1657 # require non-terminator (label name follows) 1658 la_a0 &scan_pos 1659 ld_t0,a0,0 1660 la_a1 &scan_end 1661 ld_t1,a1,0 1662 la_br &err_sigil_no_label 1663 beq_t0,t1 1664 la_br &err_sigil_no_label 1665 blt_t1,t0 1666 lb_a0,t0,0 1667 la_br &is_name_terminator 1668 call 1669 la_br &err_sigil_no_label 1670 bnez_a0 1671 # scan_name -> length in a0, pointer in sn_start (no copy). 1672 la_br &scan_name 1673 call 1674 la_a1 &pref_name_len 1675 st_a0,a1,0 1676 la_a0 &sn_start 1677 ld_t0,a0,0 1678 la_a1 &pref_name 1679 st_t0,a1,0 1680 # default: other = NULL, other_len = 0 1681 li_t0 %0 %0 1682 la_a1 &pref_other 1683 st_t0,a1,0 1684 la_a1 &pref_other_len 1685 st_t0,a1,0 1686 # optional '-' or '>' separator (tight, no whitespace) 1687 la_a0 &scan_pos 1688 ld_t0,a0,0 1689 la_a1 &scan_end 1690 ld_t1,a1,0 1691 la_br &pref_after_other 1692 beq_t0,t1 1693 la_br &pref_after_other 1694 blt_t1,t0 1695 lb_a0,t0,0 1696 li_t1 %45 %0 1697 la_br &pref_consume_sep 1698 beq_a0,t1 1699 li_t1 %62 %0 1700 la_br &pref_consume_sep 1701 beq_a0,t1 1702 la_br &pref_after_other 1703 b 1704 :pref_consume_sep 1705 la_a0 &scan_pos 1706 ld_t0,a0,0 1707 addi_t0,t0,1 1708 st_t0,a0,0 1709 la_a1 &scan_end 1710 ld_t1,a1,0 1711 la_br &err_minus_no_label 1712 beq_t0,t1 1713 la_br &err_minus_no_label 1714 blt_t1,t0 1715 lb_a0,t0,0 1716 la_br &is_name_terminator 1717 call 1718 la_br &err_minus_no_label 1719 bnez_a0 1720 la_br &scan_name 1721 call 1722 la_a1 &pref_other_len 1723 st_a0,a1,0 1724 la_a0 &sn_start 1725 ld_t0,a0,0 1726 la_a1 &pref_other 1727 st_t0,a1,0 1728 :pref_after_other 1729 # Reserve placeholder bytes; emit_zeros returns starting offset. 1730 la_a0 &pr_width 1731 ld_a0,a0,0 1732 la_br &emit_zeros 1733 call 1734 la_a1 &rf_out_off 1735 st_a0,a1,0 1736 # ip_after = ip (already advanced by emit_zeros). 1737 la_a0 &ip 1738 ld_t0,a0,0 1739 la_a1 &rf_ip_after 1740 st_t0,a1,0 1741 la_br &record_fixup 1742 call 1743 eret 1744 1745 ## record_fixup(): pref_name/pref_name_len/pref_other/pref_other_len already set 1746 ## by caller. rf_out_off and rf_ip_after also set. Snapshots cur_sigil/cur_path/ 1747 ## cur_line and the current scope stack (if depth > 0). 1748 :record_fixup 1749 enter_0 1750 la_a0 &fixup_count 1751 ld_t0,a0,0 1752 li_t1 H2_FIXUP_CAP 1753 la_br &err_too_many_fixups 1754 beq_t0,t1 1755 la_br &err_too_many_fixups 1756 blt_t1,t0 1757 # fp = fixups_ptr + count * 96 1758 li_t1 %96 %0 1759 mul_a1,t0,t1 1760 la_a2 &fixups_ptr 1761 ld_a2,a2,0 1762 add_a1,a1,a2 1763 la_a3 &rf_fp 1764 st_a1,a3,0 1765 # offset 0: out_off 1766 la_a0 &rf_out_off 1767 ld_t0,a0,0 1768 st_t0,a1,0 1769 # offset 8: ip_at_ref 1770 la_a0 &rf_ip_after 1771 ld_t0,a0,0 1772 st_t0,a1,8 1773 # offset 16: name 1774 la_a0 &pref_name 1775 ld_t0,a0,0 1776 st_t0,a1,16 1777 # offset 24: other (0 if none) 1778 la_a0 &pref_other 1779 ld_t0,a0,0 1780 st_t0,a1,24 1781 # offset 32: src_path = cur_path 1782 la_a0 &cur_path 1783 ld_t0,a0,0 1784 st_t0,a1,32 1785 # offset 40: name_len 1786 la_a0 &pref_name_len 1787 ld_t0,a0,0 1788 st_t0,a1,40 1789 # offset 48: other_len 1790 la_a0 &pref_other_len 1791 ld_t0,a0,0 1792 st_t0,a1,48 1793 # offset 56: scope_hist_off (filled below if depth > 0) 1794 li_t0 %0 %0 1795 st_t0,a1,56 1796 # offset 64: scope_depth (snapshot) 1797 la_a0 &scope_depth 1798 ld_t0,a0,0 1799 st_t0,a1,64 1800 # offset 72: src_line = cur_line (offset > 64: indirect via a3) 1801 la_a0 &cur_line 1802 ld_t0,a0,0 1803 li_t1 %72 %0 1804 add_a3,a1,t1 1805 st_t0,a3,0 1806 # offset 80: sigil 1807 la_a0 &cur_sigil 1808 ld_t0,a0,0 1809 li_t1 %80 %0 1810 add_a3,a1,t1 1811 st_t0,a3,0 1812 # If depth > 0, snapshot scope_stack into scope_history. 1813 la_a0 &scope_depth 1814 ld_t0,a0,0 1815 la_br &rf_no_scope 1816 beqz_t0 1817 la_a1 &scope_history_used 1818 ld_t1,a1,0 1819 add_t2,t1,t0 1820 li_a3 H2_SCOPE_HISTORY_CAP 1821 la_br &err_scope_history_overflow 1822 blt_a3,t2 1823 # Set scope_hist_off (offset 56) on the fixup. 1824 la_a0 &rf_fp 1825 ld_a0,a0,0 1826 st_t1,a0,56 1827 li_t2 %0 %0 1828 la_a0 &rf_i 1829 st_t2,a0,0 1830 :rf_copy_loop 1831 la_a0 &rf_i 1832 ld_t0,a0,0 1833 la_a1 &scope_depth 1834 ld_t1,a1,0 1835 la_br &rf_copy_done 1836 beq_t0,t1 1837 # src = scope_stack_ptr + i*8 1838 la_a1 &scope_stack_ptr 1839 ld_a1,a1,0 1840 shli_t2,t0,3 1841 add_a1,a1,t2 1842 ld_a3,a1,0 1843 # dst = scope_history_ptr + (scope_history_used + i)*8 1844 la_a2 &scope_history_used 1845 ld_a2,a2,0 1846 add_a2,a2,t0 1847 shli_a2,a2,3 1848 la_a1 &scope_history_ptr 1849 ld_a1,a1,0 1850 add_a1,a1,a2 1851 st_a3,a1,0 1852 addi_t0,t0,1 1853 la_a0 &rf_i 1854 st_t0,a0,0 1855 la_br &rf_copy_loop 1856 b 1857 :rf_copy_done 1858 la_a1 &scope_history_used 1859 ld_t0,a1,0 1860 la_a2 &scope_depth 1861 ld_t1,a2,0 1862 add_t0,t0,t1 1863 st_t0,a1,0 1864 :rf_no_scope 1865 la_a0 &fixup_count 1866 ld_t0,a0,0 1867 addi_t0,t0,1 1868 st_t0,a0,0 1869 eret 1870 1871 ## set_sigil_info(): reads cur_sigil; populates pr_width / pr_is_rel / 1872 ## pr_lo / pr_hi / pr_range_check. 1873 :set_sigil_info 1874 enter_0 1875 la_a0 &cur_sigil 1876 ld_a0,a0,0 1877 li_t0 %33 %0 1878 la_br &ssi_bang 1879 beq_a0,t0 1880 li_t0 %64 %0 1881 la_br &ssi_at 1882 beq_a0,t0 1883 li_t0 %36 %0 1884 la_br &ssi_dollar 1885 beq_a0,t0 1886 li_t0 %126 %0 1887 la_br &ssi_tilde 1888 beq_a0,t0 1889 li_t0 %37 %0 1890 la_br &ssi_pct 1891 beq_a0,t0 1892 li_t0 %38 %0 1893 la_br &ssi_amp 1894 beq_a0,t0 1895 la_br &err_bad_sigil 1896 b 1897 :ssi_bang 1898 li_t0 %1 %0 1899 la_a1 &pr_width 1900 st_t0,a1,0 1901 la_a1 &pr_is_rel 1902 st_t0,a1,0 1903 la_a1 &pr_range_check 1904 st_t0,a1,0 1905 li_t0 %128 %0 1906 li_t1 %0 %0 1907 sub_t0,t1,t0 1908 la_a1 &pr_lo 1909 st_t0,a1,0 1910 li_t0 %127 %0 1911 la_a1 &pr_hi 1912 st_t0,a1,0 1913 eret 1914 :ssi_at 1915 li_t0 %2 %0 1916 la_a1 &pr_width 1917 st_t0,a1,0 1918 li_t0 %1 %0 1919 la_a1 &pr_is_rel 1920 st_t0,a1,0 1921 la_a1 &pr_range_check 1922 st_t0,a1,0 1923 # 32768 = 256 * 128 1924 li_t0 %256 %0 1925 li_t1 %128 %0 1926 mul_t0,t0,t1 1927 li_t1 %0 %0 1928 sub_t1,t1,t0 1929 la_a1 &pr_lo 1930 st_t1,a1,0 1931 addi_t0,t0,neg1 1932 la_a1 &pr_hi 1933 st_t0,a1,0 1934 eret 1935 :ssi_dollar 1936 li_t0 %2 %0 1937 la_a1 &pr_width 1938 st_t0,a1,0 1939 li_t0 %0 %0 1940 la_a1 &pr_is_rel 1941 st_t0,a1,0 1942 li_t0 %1 %0 1943 la_a1 &pr_range_check 1944 st_t0,a1,0 1945 li_t0 %0 %0 1946 la_a1 &pr_lo 1947 st_t0,a1,0 1948 # 65536 = 256 * 256 1949 li_t0 %256 %0 1950 mov_t1,t0 1951 mul_t0,t0,t1 1952 addi_t0,t0,neg1 1953 la_a1 &pr_hi 1954 st_t0,a1,0 1955 eret 1956 :ssi_tilde 1957 li_t0 %3 %0 1958 la_a1 &pr_width 1959 st_t0,a1,0 1960 li_t0 %1 %0 1961 la_a1 &pr_is_rel 1962 st_t0,a1,0 1963 la_a1 &pr_range_check 1964 st_t0,a1,0 1965 # 8388608 = 256 * 256 * 128 1966 li_t0 %256 %0 1967 mov_t1,t0 1968 mul_t0,t0,t1 1969 li_t1 %128 %0 1970 mul_t0,t0,t1 1971 li_t1 %0 %0 1972 sub_t1,t1,t0 1973 la_a1 &pr_lo 1974 st_t1,a1,0 1975 addi_t0,t0,neg1 1976 la_a1 &pr_hi 1977 st_t0,a1,0 1978 eret 1979 :ssi_pct 1980 la_a0 &ptrsize 1981 ld_t0,a0,0 1982 la_a1 &pr_width 1983 st_t0,a1,0 1984 li_t0 %1 %0 1985 la_a1 &pr_is_rel 1986 st_t0,a1,0 1987 la_a1 &ptrsize_used 1988 st_t0,a1,0 1989 li_t0 %0 %0 1990 la_a1 &pr_range_check 1991 st_t0,a1,0 1992 la_a1 &pr_lo 1993 st_t0,a1,0 1994 la_a1 &pr_hi 1995 st_t0,a1,0 1996 eret 1997 :ssi_amp 1998 la_a0 &ptrsize 1999 ld_t0,a0,0 2000 la_a1 &pr_width 2001 st_t0,a1,0 2002 li_t0 %1 %0 2003 la_a1 &ptrsize_used 2004 st_t0,a1,0 2005 li_t0 %0 %0 2006 la_a1 &pr_is_rel 2007 st_t0,a1,0 2008 la_a1 &pr_range_check 2009 st_t0,a1,0 2010 la_a1 &pr_lo 2011 st_t0,a1,0 2012 la_a1 &pr_hi 2013 st_t0,a1,0 2014 eret 2015 2016 ## --- Directives ------------------------------------------------------------ 2017 2018 ## do_align(): .align N [PATTERN]. N positive power of two; optional pattern. 2019 :do_align 2020 enter_0 2021 la_br &skip_inline_ws 2022 call 2023 la_br &read_decimal 2024 call 2025 la_a1 &da_n 2026 st_a0,a1,0 2027 la_br &err_align_n 2028 beqz_a0 2029 la_br &err_align_n 2030 bltz_a0 2031 # power-of-two: N & (N-1) == 0 2032 la_a0 &da_n 2033 ld_a3,a0,0 2034 addi_a3,a3,neg1 2035 la_a0 &da_n 2036 ld_a2,a0,0 2037 and_a3,a3,a2 2038 la_br &err_align_n 2039 bnez_a3 2040 li_t0 %0 %0 2041 la_a0 &da_has_pat 2042 st_t0,a0,0 2043 la_a0 &da_patlen 2044 st_t0,a0,0 2045 la_br &skip_inline_ws 2046 call 2047 la_a0 &scan_pos 2048 ld_t0,a0,0 2049 la_a1 &scan_end 2050 ld_t1,a1,0 2051 la_br &da_compute 2052 beq_t0,t1 2053 la_br &da_compute 2054 blt_t1,t0 2055 lb_a0,t0,0 2056 la_br &is_byte_digit 2057 call 2058 la_br &da_compute 2059 beqz_a0 2060 li_t0 %1 %0 2061 la_a1 &da_has_pat 2062 st_t0,a1,0 2063 :da_pat_loop 2064 la_a0 &scan_pos 2065 ld_t0,a0,0 2066 la_a1 &scan_end 2067 ld_t1,a1,0 2068 la_br &da_compute 2069 beq_t0,t1 2070 la_br &da_compute 2071 blt_t1,t0 2072 lb_a0,t0,0 2073 la_br &is_byte_digit 2074 call 2075 la_br &da_compute 2076 beqz_a0 2077 la_a0 &da_patlen 2078 ld_t0,a0,0 2079 li_t1 H2_TOKEN_CAP 2080 la_br &err_pattern_too_large 2081 beq_t0,t1 2082 la_a0 &pat_buf_ptr 2083 ld_a0,a0,0 2084 add_a0,a0,t0 2085 la_br &parse_one_byte 2086 call 2087 la_a0 &da_patlen 2088 ld_t0,a0,0 2089 addi_t0,t0,1 2090 st_t0,a0,0 2091 la_br &da_pat_loop 2092 b 2093 :da_compute 2094 # pad = (N - (ip mod N)) mod N 2095 la_a0 &ip 2096 ld_a0,a0,0 2097 la_a1 &da_n 2098 ld_a1,a1,0 2099 rem_a2,a0,a1 2100 li_t0 %0 %0 2101 la_a3 &da_pad 2102 st_t0,a3,0 2103 la_br &da_emit 2104 beqz_a2 2105 sub_a3,a1,a2 2106 la_a1 &da_pad 2107 st_a3,a1,0 2108 :da_emit 2109 la_a0 &da_pad 2110 ld_t0,a0,0 2111 la_br &da_emit_done 2112 beqz_t0 2113 # No-pattern fast path: emit_zeros(pad). 2114 la_a1 &da_has_pat 2115 ld_t1,a1,0 2116 la_br &da_emit_pattern 2117 bnez_t1 2118 la_a0 &da_pad 2119 ld_a0,a0,0 2120 la_br &emit_zeros 2121 call 2122 la_br &da_emit_done 2123 b 2124 :da_emit_pattern 2125 li_t0 %0 %0 2126 la_a0 &da_i 2127 st_t0,a0,0 2128 :da_pattern_loop 2129 la_a0 &da_i 2130 ld_t0,a0,0 2131 la_a1 &da_pad 2132 ld_t1,a1,0 2133 la_br &da_emit_done 2134 beq_t0,t1 2135 # b = pat[i % patlen] 2136 la_a1 &da_patlen 2137 ld_a1,a1,0 2138 rem_a2,t0,a1 2139 la_a0 &pat_buf_ptr 2140 ld_a0,a0,0 2141 add_a0,a0,a2 2142 lb_a0,a0,0 2143 la_br &emit_byte 2144 call 2145 la_a0 &da_i 2146 ld_t0,a0,0 2147 addi_t0,t0,1 2148 st_t0,a0,0 2149 la_br &da_pattern_loop 2150 b 2151 :da_emit_done 2152 eret 2153 2154 ## do_fill(): .fill N B. 2155 :do_fill 2156 enter_0 2157 la_br &skip_inline_ws 2158 call 2159 la_br &read_decimal 2160 call 2161 la_a1 &df_n 2162 st_a0,a1,0 2163 la_br &err_fill_n 2164 bltz_a0 2165 la_br &skip_inline_ws 2166 call 2167 la_a0 &df_byte_ptr 2168 ld_a0,a0,0 2169 la_br &parse_one_byte 2170 call 2171 la_a0 &df_n 2172 ld_a0,a0,0 2173 la_br &df_done 2174 beqz_a0 2175 la_a1 &df_byte_ptr 2176 ld_a1,a1,0 2177 lb_a1,a1,0 2178 la_br &emit_fill 2179 call 2180 :df_done 2181 eret 2182 2183 ## do_scope_open(): scope_seq++; scope_stack[scope_depth++] = scope_seq. 2184 :do_scope_open 2185 enter_0 2186 la_a0 &scope_depth 2187 ld_t0,a0,0 2188 li_t1 H2_SCOPE_CAP 2189 la_br &err_scope_overflow 2190 beq_t0,t1 2191 la_br &err_scope_overflow 2192 blt_t1,t0 2193 la_a0 &scope_seq 2194 ld_t1,a0,0 2195 addi_t1,t1,1 2196 st_t1,a0,0 2197 la_a1 &scope_stack_ptr 2198 ld_a1,a1,0 2199 shli_t2,t0,3 2200 add_a1,a1,t2 2201 st_t1,a1,0 2202 addi_t0,t0,1 2203 la_a0 &scope_depth 2204 st_t0,a0,0 2205 eret 2206 2207 ## do_scope_close(): scope_depth--. 2208 :do_scope_close 2209 enter_0 2210 la_a0 &scope_depth 2211 ld_t0,a0,0 2212 la_br &err_scope_underflow 2213 beqz_t0 2214 addi_t0,t0,neg1 2215 st_t0,a0,0 2216 eret 2217 2218 ## do_ptrsize(): .ptrsize N -- N must be 4 or 8. 2219 :do_ptrsize 2220 enter_0 2221 la_br &skip_inline_ws 2222 call 2223 la_br &read_decimal 2224 call 2225 la_a1 &dp_n 2226 st_a0,a1,0 2227 li_t0 %4 %0 2228 la_br &dp_ok 2229 beq_a0,t0 2230 li_t0 %8 %0 2231 la_br &dp_ok 2232 beq_a0,t0 2233 la_br &err_ptrsize_bad 2234 b 2235 :dp_ok 2236 la_a0 &ptrsize_used 2237 ld_t0,a0,0 2238 la_br &dp_set 2239 beqz_t0 2240 la_a0 &ptrsize 2241 ld_t0,a0,0 2242 la_a1 &dp_n 2243 ld_t1,a1,0 2244 la_br &err_ptrsize_conflict 2245 bne_t0,t1 2246 eret 2247 :dp_set 2248 la_a0 &dp_n 2249 ld_t0,a0,0 2250 la_a1 &ptrsize 2251 st_t0,a1,0 2252 eret 2253 2254 ## --- Emit ------------------------------------------------------------------ 2255 2256 ## emit_byte(a0=byte): write one byte to output_buf and bump ip. 2257 :emit_byte 2258 la_a1 &output_used 2259 ld_t0,a1,0 2260 li_t1 H2_OUTPUT_CAP 2261 la_br &err_output_overflow 2262 beq_t0,t1 2263 la_br &err_output_overflow 2264 blt_t1,t0 2265 la_a2 &output_buf_ptr 2266 ld_a2,a2,0 2267 add_a2,a2,t0 2268 sb_a0,a2,0 2269 addi_t0,t0,1 2270 st_t0,a1,0 2271 la_a0 &ip 2272 ld_t0,a0,0 2273 addi_t0,t0,1 2274 st_t0,a0,0 2275 ret 2276 2277 ## emit_zeros(a0=n) -> a0 = starting offset (output_used before the call). 2278 ## Writes n zero bytes to output_buf and advances output_used + ip by n. 2279 :emit_zeros 2280 enter_0 2281 la_a3 &emz_n 2282 st_a0,a3,0 2283 # Capacity check: output_used + n must fit. 2284 la_a1 &output_used 2285 ld_t0,a1,0 2286 add_t1,t0,a0 2287 li_t2 H2_OUTPUT_CAP 2288 la_br &err_output_overflow 2289 blt_t2,t1 2290 la_a2 &emz_off 2291 st_t0,a2,0 2292 la_a2 &output_buf_ptr 2293 ld_a2,a2,0 2294 add_a2,a2,t0 2295 li_t1 %0 %0 2296 :emz_loop 2297 la_a3 &emz_n 2298 ld_t2,a3,0 2299 la_br &emz_done 2300 beq_t1,t2 2301 add_a3,a2,t1 2302 li_t0 %0 %0 2303 sb_t0,a3,0 2304 addi_t1,t1,1 2305 la_br &emz_loop 2306 b 2307 :emz_done 2308 la_a3 &emz_n 2309 ld_t0,a3,0 2310 la_a1 &output_used 2311 ld_t1,a1,0 2312 add_t1,t1,t0 2313 st_t1,a1,0 2314 la_a1 &ip 2315 ld_t1,a1,0 2316 add_t1,t1,t0 2317 st_t1,a1,0 2318 la_a0 &emz_off 2319 ld_a0,a0,0 2320 eret 2321 2322 ## emit_fill(a0=n, a1=byte): write n copies of byte; advances output_used + ip. 2323 :emit_fill 2324 enter_0 2325 la_a3 &emf_n 2326 st_a0,a3,0 2327 la_a3 &emf_b 2328 st_a1,a3,0 2329 la_a2 &output_used 2330 ld_t0,a2,0 2331 add_t1,t0,a0 2332 li_t2 H2_OUTPUT_CAP 2333 la_br &err_output_overflow 2334 blt_t2,t1 2335 la_a2 &output_buf_ptr 2336 ld_a2,a2,0 2337 add_a2,a2,t0 2338 li_t1 %0 %0 2339 :emf_loop 2340 la_a3 &emf_n 2341 ld_t2,a3,0 2342 la_br &emf_done 2343 beq_t1,t2 2344 la_a3 &emf_b 2345 ld_t0,a3,0 2346 add_a3,a2,t1 2347 sb_t0,a3,0 2348 addi_t1,t1,1 2349 la_br &emf_loop 2350 b 2351 :emf_done 2352 la_a3 &emf_n 2353 ld_t0,a3,0 2354 la_a1 &output_used 2355 ld_t1,a1,0 2356 add_t1,t1,t0 2357 st_t1,a1,0 2358 la_a1 &ip 2359 ld_t1,a1,0 2360 add_t1,t1,t0 2361 st_t1,a1,0 2362 eret 2363 2364 ## write_value(a0=out_off): patch a value into output_buf at out_off. 2365 ## Caller pre-populates ev_value/ev_width/ev_lo/ev_hi/ev_range_check. 2366 :write_value 2367 enter_0 2368 la_t1 &ev_out_off 2369 st_a0,t1,0 2370 2371 la_a0 &ev_range_check 2372 ld_t0,a0,0 2373 la_br &wv_no_range 2374 beqz_t0 2375 la_a0 &ev_value 2376 ld_a0,a0,0 2377 la_a1 &ev_lo 2378 ld_a1,a1,0 2379 la_br &err_ref_out_of_range 2380 blt_a0,a1 2381 la_a0 &ev_value 2382 ld_a0,a0,0 2383 la_a1 &ev_hi 2384 ld_a1,a1,0 2385 la_br &err_ref_out_of_range 2386 blt_a1,a0 2387 :wv_no_range 2388 la_a0 &ev_value 2389 ld_a0,a0,0 2390 la_a1 &ev_pack_v 2391 st_a0,a1,0 2392 li_t0 %0 %0 2393 la_a0 &ev_i 2394 st_t0,a0,0 2395 :wv_pack_loop 2396 la_a0 &ev_i 2397 ld_t0,a0,0 2398 la_a1 &ev_width 2399 ld_t1,a1,0 2400 la_br &wv_emit_dispatch 2401 beq_t0,t1 2402 la_a1 &ev_pack_v 2403 ld_a3,a1,0 2404 andi_a3,a3,255 2405 la_a2 &ev_bytes_ptr 2406 ld_a2,a2,0 2407 add_a2,a2,t0 2408 sb_a3,a2,0 2409 la_a1 &ev_pack_v 2410 ld_t2,a1,0 2411 shri_t2,t2,8 2412 st_t2,a1,0 2413 addi_t0,t0,1 2414 la_a0 &ev_i 2415 st_t0,a0,0 2416 la_br &wv_pack_loop 2417 b 2418 :wv_emit_dispatch 2419 la_a0 &big_endian 2420 ld_t0,a0,0 2421 la_br &wv_emit_be 2422 bnez_t0 2423 li_t0 %0 %0 2424 la_a0 &ev_i 2425 st_t0,a0,0 2426 :wv_emit_le_loop 2427 la_a0 &ev_i 2428 ld_t0,a0,0 2429 la_a1 &ev_width 2430 ld_t1,a1,0 2431 la_br &wv_done 2432 beq_t0,t1 2433 la_a2 &ev_bytes_ptr 2434 ld_a2,a2,0 2435 add_a2,a2,t0 2436 lb_a0,a2,0 2437 la_a3 &output_buf_ptr 2438 ld_a3,a3,0 2439 la_a2 &ev_out_off 2440 ld_a2,a2,0 2441 add_a3,a3,a2 2442 add_a3,a3,t0 2443 sb_a0,a3,0 2444 addi_t0,t0,1 2445 la_a0 &ev_i 2446 st_t0,a0,0 2447 la_br &wv_emit_le_loop 2448 b 2449 :wv_emit_be 2450 li_t0 %0 %0 2451 la_a0 &ev_i 2452 st_t0,a0,0 2453 :wv_emit_be_loop 2454 la_a0 &ev_i 2455 ld_t0,a0,0 2456 la_a1 &ev_width 2457 ld_t1,a1,0 2458 la_br &wv_done 2459 beq_t0,t1 2460 # src_idx = (width - 1) - i 2461 addi_t1,t1,neg1 2462 sub_t2,t1,t0 2463 la_a2 &ev_bytes_ptr 2464 ld_a2,a2,0 2465 add_a2,a2,t2 2466 lb_a0,a2,0 2467 la_a3 &output_buf_ptr 2468 ld_a3,a3,0 2469 la_a2 &ev_out_off 2470 ld_a2,a2,0 2471 add_a3,a3,a2 2472 add_a3,a3,t0 2473 sb_a0,a3,0 2474 addi_t0,t0,1 2475 la_a0 &ev_i 2476 st_t0,a0,0 2477 la_br &wv_emit_be_loop 2478 b 2479 :wv_done 2480 eret 2481 2482 ## --- Fixup resolution ------------------------------------------------------ 2483 ## patch_fixups(): walk fixups[0..fixup_count), resolve labels, write values 2484 ## into output_buf. Per-fixup error reports use the snapshotted src_path / 2485 ## src_line via the cur_path / cur_line globals. 2486 :patch_fixups 2487 enter_0 2488 li_t0 %0 %0 2489 la_a0 &pf_i 2490 st_t0,a0,0 2491 :pf_loop 2492 la_a0 &pf_i 2493 ld_t0,a0,0 2494 la_a1 &fixup_count 2495 ld_t1,a1,0 2496 la_br &pf_done 2497 beq_t0,t1 2498 # fp = fixups + i*96 2499 li_t1 %96 %0 2500 mul_a1,t0,t1 2501 la_a2 &fixups_ptr 2502 ld_a2,a2,0 2503 add_a1,a1,a2 2504 la_a3 &pf_fp 2505 st_a1,a3,0 2506 # cur_path = fp[32]; cur_line = fp[72]; cur_sigil = fp[80] 2507 ld_t0,a1,32 2508 la_a2 &cur_path 2509 st_t0,a2,0 2510 li_t1 %72 %0 2511 add_a3,a1,t1 2512 ld_t0,a3,0 2513 la_a2 &cur_line 2514 st_t0,a2,0 2515 li_t1 %80 %0 2516 add_a3,a1,t1 2517 ld_t0,a3,0 2518 la_a2 &cur_sigil 2519 st_t0,a2,0 2520 # pr_width / pr_is_rel / pr_lo / pr_hi / pr_range_check 2521 la_br &set_sigil_info 2522 call 2523 # Determine stack pointer for the lookup (NULL if depth == 0). 2524 la_a0 &pf_fp 2525 ld_a1,a0,0 2526 ld_t0,a1,64 2527 la_a2 &pf_depth 2528 st_t0,a2,0 2529 li_t1 %0 %0 2530 la_a2 &pf_stack 2531 st_t1,a2,0 2532 la_br &pf_lookup_label 2533 beqz_t0 2534 # stack = scope_history_ptr + scope_hist_off * 8 2535 ld_t1,a1,56 2536 shli_t1,t1,3 2537 la_a2 &scope_history_ptr 2538 ld_a2,a2,0 2539 add_a2,a2,t1 2540 la_a3 &pf_stack 2541 st_a2,a3,0 2542 :pf_lookup_label 2543 la_a0 &pf_fp 2544 ld_a1,a0,0 2545 ld_a0,a1,16 2546 ld_t0,a1,40 2547 mov_a1,t0 2548 la_a2 &pf_stack 2549 ld_a2,a2,0 2550 la_a3 &pf_depth 2551 ld_a3,a3,0 2552 la_br &lookup_label_in 2553 call 2554 la_a1 &pf_t_label 2555 st_a0,a1,0 2556 # If other != 0: value = t_label - t_other; emit. 2557 la_a0 &pf_fp 2558 ld_a1,a0,0 2559 ld_t0,a1,24 2560 la_br &pf_no_other 2561 beqz_t0 2562 mov_a0,t0 2563 ld_t0,a1,48 2564 mov_a1,t0 2565 la_a2 &pf_stack 2566 ld_a2,a2,0 2567 la_a3 &pf_depth 2568 ld_a3,a3,0 2569 la_br &lookup_label_in 2570 call 2571 la_a1 &pf_t_label 2572 ld_a1,a1,0 2573 sub_a0,a1,a0 2574 la_a1 &pf_value 2575 st_a0,a1,0 2576 la_br &pf_emit 2577 b 2578 :pf_no_other 2579 la_a0 &pr_is_rel 2580 ld_t0,a0,0 2581 la_br &pf_abs 2582 beqz_t0 2583 # rel: value = t_label - ip_at_ref 2584 la_a0 &pf_fp 2585 ld_a1,a0,0 2586 ld_t1,a1,8 2587 la_a0 &pf_t_label 2588 ld_a0,a0,0 2589 sub_a0,a0,t1 2590 la_a1 &pf_value 2591 st_a0,a1,0 2592 la_br &pf_emit 2593 b 2594 :pf_abs 2595 la_a0 &pf_t_label 2596 ld_a1,a0,0 2597 la_a0 &base_address 2598 ld_a0,a0,0 2599 add_a1,a1,a0 2600 la_a3 &pf_value 2601 st_a1,a3,0 2602 :pf_emit 2603 # Populate ev_* state, then write_value(out_off). 2604 la_a0 &pf_value 2605 ld_t0,a0,0 2606 la_a1 &ev_value 2607 st_t0,a1,0 2608 la_a0 &pr_width 2609 ld_t0,a0,0 2610 la_a1 &ev_width 2611 st_t0,a1,0 2612 la_a0 &pr_lo 2613 ld_t0,a0,0 2614 la_a1 &ev_lo 2615 st_t0,a1,0 2616 la_a0 &pr_hi 2617 ld_t0,a0,0 2618 la_a1 &ev_hi 2619 st_t0,a1,0 2620 la_a0 &pr_range_check 2621 ld_t0,a0,0 2622 la_a1 &ev_range_check 2623 st_t0,a1,0 2624 la_a0 &pf_fp 2625 ld_a1,a0,0 2626 ld_a0,a1,0 2627 la_br &write_value 2628 call 2629 # i++ 2630 la_a0 &pf_i 2631 ld_t0,a0,0 2632 addi_t0,t0,1 2633 st_t0,a0,0 2634 la_br &pf_loop 2635 b 2636 :pf_done 2637 eret 2638 2639 ## --- Output writer --------------------------------------------------------- 2640 :write_output 2641 enter_0 2642 la_a0 &output_path 2643 ld_a2,a0,0 2644 li_a0 sys_openat 2645 li_a1 H2_AT_FDCWD 2646 li_a3 H2_O_WRONLY_CREAT_TRUNC 2647 la_t1 &non_executable 2648 ld_t1,t1,0 2649 la_br &wo_mode_nonexec 2650 bnez_t1 2651 li_t0 H2_MODE_0750 2652 la_br &wo_after_mode 2653 b 2654 :wo_mode_nonexec 2655 li_t0 H2_MODE_0640 2656 :wo_after_mode 2657 syscall 2658 la_br &err_open_output 2659 bltz_a0 2660 la_a1 &output_fd 2661 st_a0,a1,0 2662 li_t0 %0 %0 2663 la_a1 &output_written 2664 st_t0,a1,0 2665 :wo_loop 2666 la_a0 &output_written 2667 ld_t0,a0,0 2668 la_a1 &output_used 2669 ld_t1,a1,0 2670 la_br &wo_done 2671 beq_t0,t1 2672 la_a0 &output_fd 2673 ld_a1,a0,0 2674 la_a2 &output_buf_ptr 2675 ld_a2,a2,0 2676 add_a2,a2,t0 2677 sub_a3,t1,t0 2678 li_a0 sys_write 2679 syscall 2680 la_br &err_write 2681 bltz_a0 2682 la_br &err_write 2683 beqz_a0 2684 la_a1 &output_written 2685 ld_t0,a1,0 2686 add_t0,t0,a0 2687 st_t0,a1,0 2688 la_br &wo_loop 2689 b 2690 :wo_done 2691 eret 2692 2693 ## --- Misc helpers ---------------------------------------------------------- 2694 2695 ## str_eq(a0=p, a1=q, a2=len) -> a0=0/1. len bytes equal AND p[len]==NUL. 2696 :str_eq 2697 enter_0 2698 la_t0 &se_p 2699 st_a0,t0,0 2700 la_t0 &se_q 2701 st_a1,t0,0 2702 la_t0 &se_len 2703 st_a2,t0,0 2704 li_t1 %0 %0 2705 :se_loop 2706 la_a0 &se_len 2707 ld_a1,a0,0 2708 la_br &se_check_terminal 2709 beq_t1,a1 2710 la_a0 &se_p 2711 ld_a0,a0,0 2712 add_a0,a0,t1 2713 lb_t0,a0,0 2714 la_a2 &se_q 2715 ld_a2,a2,0 2716 add_a2,a2,t1 2717 lb_t2,a2,0 2718 la_br &se_no 2719 bne_t0,t2 2720 addi_t1,t1,1 2721 la_br &se_loop 2722 b 2723 :se_check_terminal 2724 la_a0 &se_p 2725 ld_a0,a0,0 2726 add_a0,a0,t1 2727 lb_t0,a0,0 2728 la_br &se_no 2729 bnez_t0 2730 li_a0 %1 %0 2731 eret 2732 :se_no 2733 li_a0 %0 %0 2734 eret 2735 2736 ## mem_eq(a0=p, a1=q, a2=len) -> a0=0/1. 2737 :mem_eq 2738 enter_0 2739 la_t0 &me_p 2740 st_a0,t0,0 2741 la_t0 &me_q 2742 st_a1,t0,0 2743 la_t0 &me_len 2744 st_a2,t0,0 2745 li_t1 %0 %0 2746 :me_loop 2747 la_a0 &me_len 2748 ld_a1,a0,0 2749 la_br &me_yes 2750 beq_t1,a1 2751 la_a0 &me_p 2752 ld_a0,a0,0 2753 add_a0,a0,t1 2754 lb_t0,a0,0 2755 la_a2 &me_q 2756 ld_a2,a2,0 2757 add_a2,a2,t1 2758 lb_t2,a2,0 2759 la_br &me_no 2760 bne_t0,t2 2761 addi_t1,t1,1 2762 la_br &me_loop 2763 b 2764 :me_yes 2765 li_a0 %1 %0 2766 eret 2767 :me_no 2768 li_a0 %0 %0 2769 eret 2770 2771 ## parse_long(a0=cstr) -> a0=value. Decimal or 0x-prefixed hex i64. 2772 :parse_long 2773 enter_0 2774 la_t0 &pl_p 2775 st_a0,t0,0 2776 li_t0 %0 %0 2777 la_a1 &pl_val 2778 st_t0,a1,0 2779 la_a1 &pl_neg 2780 st_t0,a1,0 2781 # 0x / 0X prefix? 2782 la_a0 &pl_p 2783 ld_a0,a0,0 2784 lb_t0,a0,0 2785 li_t1 %48 %0 2786 la_br &pl_dec_init 2787 bne_t0,t1 2788 lb_t0,a0,1 2789 li_t1 %120 %0 2790 la_br &pl_hex_init 2791 beq_t0,t1 2792 li_t1 %88 %0 2793 la_br &pl_hex_init 2794 beq_t0,t1 2795 la_br &pl_dec_init 2796 b 2797 :pl_hex_init 2798 la_a0 &pl_p 2799 ld_t0,a0,0 2800 addi_t0,t0,2 2801 st_t0,a0,0 2802 :pl_hex_loop 2803 la_a0 &pl_p 2804 ld_t0,a0,0 2805 lb_t0,t0,0 2806 la_br &pl_finish 2807 beqz_t0 2808 # accept '0'..'9' / 'A'..'F' / 'a'..'f'; reject anything else 2809 li_t1 %48 %0 2810 la_br &err_bad_long 2811 blt_t0,t1 2812 li_t1 %57 %0 2813 la_br &pl_hex_acc 2814 blt_t0,t1 2815 la_br &pl_hex_acc 2816 beq_t0,t1 2817 li_t1 %65 %0 2818 la_br &err_bad_long 2819 blt_t0,t1 2820 li_t1 %70 %0 2821 la_br &pl_hex_acc 2822 blt_t0,t1 2823 la_br &pl_hex_acc 2824 beq_t0,t1 2825 li_t1 %97 %0 2826 la_br &err_bad_long 2827 blt_t0,t1 2828 li_t1 %102 %0 2829 la_br &pl_hex_acc 2830 blt_t0,t1 2831 la_br &pl_hex_acc 2832 beq_t0,t1 2833 la_br &err_bad_long 2834 b 2835 :pl_hex_acc 2836 mov_a0,t0 2837 la_br &byte_digit_value 2838 call 2839 la_a1 &pl_val 2840 ld_t0,a1,0 2841 shli_t0,t0,4 2842 add_t0,t0,a0 2843 st_t0,a1,0 2844 la_a0 &pl_p 2845 ld_t0,a0,0 2846 addi_t0,t0,1 2847 st_t0,a0,0 2848 la_br &pl_hex_loop 2849 b 2850 :pl_dec_init 2851 la_a0 &pl_p 2852 ld_a0,a0,0 2853 lb_t0,a0,0 2854 li_t1 %45 %0 2855 la_br &pl_dec_loop 2856 bne_t0,t1 2857 li_t0 %1 %0 2858 la_a1 &pl_neg 2859 st_t0,a1,0 2860 la_a0 &pl_p 2861 ld_t0,a0,0 2862 addi_t0,t0,1 2863 st_t0,a0,0 2864 :pl_dec_loop 2865 la_a0 &pl_p 2866 ld_t0,a0,0 2867 lb_t0,t0,0 2868 la_br &pl_finish 2869 beqz_t0 2870 li_t1 %48 %0 2871 la_br &err_bad_long 2872 blt_t0,t1 2873 li_t1 %57 %0 2874 la_br &err_bad_long 2875 blt_t1,t0 2876 li_t1 %48 %0 2877 sub_t0,t0,t1 2878 la_a1 &pl_val 2879 ld_a2,a1,0 2880 li_t1 %10 %0 2881 mul_a2,a2,t1 2882 add_a2,a2,t0 2883 st_a2,a1,0 2884 la_a0 &pl_p 2885 ld_t0,a0,0 2886 addi_t0,t0,1 2887 st_t0,a0,0 2888 la_br &pl_dec_loop 2889 b 2890 :pl_finish 2891 la_a1 &pl_neg 2892 ld_t0,a1,0 2893 la_br &pl_done 2894 beqz_t0 2895 la_a1 &pl_val 2896 ld_a3,a1,0 2897 li_t0 %0 %0 2898 sub_a3,t0,a3 2899 st_a3,a1,0 2900 :pl_done 2901 la_a1 &pl_val 2902 ld_a0,a1,0 2903 eret 2904 2905 ## --- Errors ---------------------------------------------------------------- 2906 2907 ## fatal(a0=msg_ptr): writes "<path>:<line>: hex2pp: <msg>\n" to stderr if 2908 ## cur_path is set, else "hex2pp: <msg>\n", then exits 1. 2909 :fatal 2910 la_a1 &fm_msg 2911 st_a0,a1,0 2912 la_a0 &cur_path 2913 ld_t0,a0,0 2914 la_br &fm_no_path 2915 beqz_t0 2916 # write path 2917 mov_a0,t0 2918 la_br &cstrlen 2919 call 2920 la_a3 &fm_tmp 2921 st_a0,a3,0 2922 la_a2 &cur_path 2923 ld_a2,a2,0 2924 la_a3 &fm_tmp 2925 ld_a3,a3,0 2926 li_a0 sys_write 2927 li_a1 %2 %0 2928 syscall 2929 # ":" 2930 li_a0 sys_write 2931 li_a1 %2 %0 2932 la_a2 &str_colon 2933 li_a3 %1 %0 2934 syscall 2935 # decimal cur_line 2936 la_a0 &cur_line 2937 ld_a0,a0,0 2938 la_br &write_decimal_stderr 2939 call 2940 # ": hex2pp: " 2941 li_a0 sys_write 2942 li_a1 %2 %0 2943 la_a2 &str_colon_prog 2944 li_a3 %10 %0 2945 syscall 2946 la_br &fm_emit_msg 2947 b 2948 :fm_no_path 2949 li_a0 sys_write 2950 li_a1 %2 %0 2951 la_a2 &str_prog 2952 li_a3 %8 %0 2953 syscall 2954 :fm_emit_msg 2955 la_a0 &fm_msg 2956 ld_a0,a0,0 2957 la_br &cstrlen 2958 call 2959 la_a3 &fm_tmp 2960 st_a0,a3,0 2961 la_a2 &fm_msg 2962 ld_a2,a2,0 2963 la_a3 &fm_tmp 2964 ld_a3,a3,0 2965 li_a0 sys_write 2966 li_a1 %2 %0 2967 syscall 2968 li_a0 sys_write 2969 li_a1 %2 %0 2970 la_a2 &str_newline 2971 li_a3 %1 %0 2972 syscall 2973 li_a0 sys_exit 2974 li_a1 %1 %0 2975 syscall 2976 2977 ## cstrlen(a0=p) -> a0=length. Walks until NUL. 2978 :cstrlen 2979 li_t0 %0 %0 2980 :cs_loop 2981 add_t1,a0,t0 2982 lb_t1,t1,0 2983 la_br &cs_done 2984 beqz_t1 2985 addi_t0,t0,1 2986 la_br &cs_loop 2987 b 2988 :cs_done 2989 mov_a0,t0 2990 ret 2991 2992 ## write_decimal_stderr(a0=value): write decimal of unsigned i64 to stderr. 2993 :write_decimal_stderr 2994 enter_0 2995 la_a1 &wd_v 2996 st_a0,a1,0 2997 la_br &wd_nonzero 2998 bnez_a0 2999 li_a0 sys_write 3000 li_a1 %2 %0 3001 la_a2 &str_zero 3002 li_a3 %1 %0 3003 syscall 3004 eret 3005 :wd_nonzero 3006 li_t0 %63 %0 3007 la_a1 &wd_pos 3008 st_t0,a1,0 3009 :wd_loop 3010 la_a0 &wd_v 3011 ld_a0,a0,0 3012 la_br &wd_emit 3013 beqz_a0 3014 li_t1 %10 %0 3015 rem_a2,a0,t1 3016 div_a0,a0,t1 3017 la_a3 &wd_v 3018 st_a0,a3,0 3019 li_t1 %48 %0 3020 add_a3,t1,a2 3021 la_a0 &wd_pos 3022 ld_t0,a0,0 3023 la_a1 &line_scratch_ptr 3024 ld_a1,a1,0 3025 add_a1,a1,t0 3026 sb_a3,a1,0 3027 addi_t0,t0,neg1 3028 la_a0 &wd_pos 3029 st_t0,a0,0 3030 la_br &wd_loop 3031 b 3032 :wd_emit 3033 la_a0 &wd_pos 3034 ld_t0,a0,0 3035 addi_t0,t0,1 3036 la_a1 &line_scratch_ptr 3037 ld_a1,a1,0 3038 add_a1,a1,t0 3039 mov_a2,a1 3040 li_t1 %64 %0 3041 sub_a3,t1,t0 3042 li_a0 sys_write 3043 li_a1 %2 %0 3044 syscall 3045 eret 3046 3047 ## --- Error stubs ----------------------------------------------------------- 3048 :err_unknown_arg 3049 la_a0 &msg_unknown_arg 3050 la_br &fatal 3051 b 3052 :err_extra_positional 3053 la_a0 &msg_extra_positional 3054 la_br &fatal 3055 b 3056 :err_missing_positional 3057 la_a0 &msg_missing_positional 3058 la_br &fatal 3059 b 3060 :err_missing_value 3061 la_a0 &msg_missing_value 3062 la_br &fatal 3063 b 3064 :err_open_input 3065 la_a0 &msg_open_input 3066 la_br &fatal 3067 b 3068 :err_read 3069 la_a0 &msg_read 3070 la_br &fatal 3071 b 3072 :err_input_too_big 3073 la_a0 &msg_input_too_big 3074 la_br &fatal 3075 b 3076 :err_open_output 3077 la_a0 &msg_open_output 3078 la_br &fatal 3079 b 3080 :err_write 3081 la_a0 &msg_write 3082 la_br &fatal 3083 b 3084 :err_text_overflow 3085 la_a0 &msg_text_overflow 3086 la_br &fatal 3087 b 3088 :err_too_many_labels 3089 la_a0 &msg_too_many_labels 3090 la_br &fatal 3091 b 3092 :err_duplicate_label 3093 la_a0 &msg_duplicate_label 3094 la_br &fatal 3095 b 3096 :err_undefined_label 3097 la_a0 &msg_undefined_label 3098 la_br &fatal 3099 b 3100 :err_undefined_local 3101 la_a0 &msg_undefined_local 3102 la_br &fatal 3103 b 3104 :err_unexpected_char 3105 la_a0 &msg_unexpected_char 3106 la_br &fatal 3107 b 3108 :err_unknown_directive 3109 la_a0 &msg_unknown_directive 3110 la_br &fatal 3111 b 3112 :err_scope_overflow 3113 la_a0 &msg_scope_overflow 3114 la_br &fatal 3115 b 3116 :err_scope_underflow 3117 la_a0 &msg_scope_underflow 3118 la_br &fatal 3119 b 3120 :err_scope_unclosed 3121 la_a0 &msg_scope_unclosed 3122 la_br &fatal 3123 b 3124 :err_align_n 3125 la_a0 &msg_align_n 3126 la_br &fatal 3127 b 3128 :err_fill_n 3129 la_a0 &msg_fill_n 3130 la_br &fatal 3131 b 3132 :err_pattern_too_large 3133 la_a0 &msg_pattern_too_large 3134 la_br &fatal 3135 b 3136 :err_byte_lit_bad 3137 la_a0 &msg_byte_lit_bad 3138 la_br &fatal 3139 b 3140 :err_byte_stream_short 3141 la_a0 &msg_byte_stream_short 3142 la_br &fatal 3143 b 3144 :err_sigil_no_label 3145 la_a0 &msg_sigil_no_label 3146 la_br &fatal 3147 b 3148 :err_minus_no_label 3149 la_a0 &msg_minus_no_label 3150 la_br &fatal 3151 b 3152 :err_bad_sigil 3153 la_a0 &msg_bad_sigil 3154 la_br &fatal 3155 b 3156 :err_ref_out_of_range 3157 la_a0 &msg_ref_out_of_range 3158 la_br &fatal 3159 b 3160 :err_name_too_long 3161 la_a0 &msg_name_too_long 3162 la_br &fatal 3163 b 3164 :err_empty_name 3165 la_a0 &msg_empty_name 3166 la_br &fatal 3167 b 3168 :err_empty_directive 3169 la_a0 &msg_empty_directive 3170 la_br &fatal 3171 b 3172 :err_expected_decimal 3173 la_a0 &msg_expected_decimal 3174 la_br &fatal 3175 b 3176 :err_output_overflow 3177 la_a0 &msg_output_overflow 3178 la_br &fatal 3179 b 3180 :err_bad_long 3181 la_a0 &msg_bad_long 3182 la_br &fatal 3183 b 3184 :err_too_many_fixups 3185 la_a0 &msg_too_many_fixups 3186 la_br &fatal 3187 b 3188 :err_scope_history_overflow 3189 la_a0 &msg_scope_history_overflow 3190 la_br &fatal 3191 b 3192 :err_ptrsize_bad 3193 la_a0 &msg_ptrsize_bad 3194 la_br &fatal 3195 b 3196 :err_ptrsize_conflict 3197 la_a0 &msg_ptrsize_conflict 3198 la_br &fatal 3199 b 3200 3201 ## Sentinel: end of executable text. 3202 :_text_end 3203 3204 ## --- Rodata ---------------------------------------------------------------- 3205 3206 :opt_B "-B" '00' 3207 :opt_E "-E" '00' 3208 :opt_e "-e" '00' 3209 :opt_b "-b" '00' 3210 :opt_N "-N" '00' 3211 3212 :kw_align "align" 3213 :kw_fill "fill" 3214 :kw_scope "scope" 3215 :kw_endscope "endscope" 3216 :kw_ptrsize "ptrsize" 3217 3218 :str_colon ":" 3219 :str_colon_prog ": hex2pp: " 3220 :str_prog "hex2pp: " 3221 :str_newline " 3222 " 3223 :str_zero "0" 3224 3225 :msg_unknown_arg "unknown argument" '00' 3226 :msg_extra_positional "extra positional argument" '00' 3227 :msg_missing_positional "missing IN or OUT positional argument" '00' 3228 :msg_missing_value "missing value for option" '00' 3229 :msg_open_input "failed to open input file" '00' 3230 :msg_read "failed to read input" '00' 3231 :msg_input_too_big "input too large" '00' 3232 :msg_open_output "failed to open output file" '00' 3233 :msg_write "failed to write output" '00' 3234 :msg_text_overflow "text pool overflow" '00' 3235 :msg_too_many_labels "too many labels" '00' 3236 :msg_duplicate_label "duplicate label" '00' 3237 :msg_undefined_label "undefined label" '00' 3238 :msg_undefined_local "undefined local label" '00' 3239 :msg_unexpected_char "unexpected character" '00' 3240 :msg_unknown_directive "unknown directive" '00' 3241 :msg_scope_overflow ".scope: depth overflow" '00' 3242 :msg_scope_underflow ".endscope: not in a scope" '00' 3243 :msg_scope_unclosed ".scope not closed at end of input" '00' 3244 :msg_align_n ".align: N must be a positive power of two" '00' 3245 :msg_fill_n ".fill: N must be non-negative" '00' 3246 :msg_pattern_too_large "pattern too large" '00' 3247 :msg_byte_lit_bad "byte literal: bad digit count" '00' 3248 :msg_byte_stream_short "byte stream: incomplete digits at end of run" '00' 3249 :msg_sigil_no_label "sigil not followed by label name" '00' 3250 :msg_minus_no_label "'-' must be followed by label name" '00' 3251 :msg_bad_sigil "internal: bad sigil" '00' 3252 :msg_ref_out_of_range "reference out of range" '00' 3253 :msg_name_too_long "name too long" '00' 3254 :msg_empty_name "expected label name" '00' 3255 :msg_empty_directive "expected directive name after '.'" '00' 3256 :msg_expected_decimal "expected decimal integer" '00' 3257 :msg_output_overflow "output overflow" '00' 3258 :msg_bad_long "invalid integer argument" '00' 3259 :msg_ptrsize_bad ".ptrsize: N must be 4 or 8" '00' 3260 :msg_ptrsize_conflict ".ptrsize conflicts with already-used width" '00' 3261 :msg_too_many_fixups "too many references" '00000000' 3262 :msg_scope_history_overflow "scope history overflow" '00' 3263 3264 ## BSS pointer-slot init table. 3265 :bss_init_tbl 3266 &scope_stack_ptr ZERO4 H2_OFF_scope_stack 3267 &name_buf_ptr ZERO4 H2_OFF_name_buf 3268 &label_buf_ptr ZERO4 H2_OFF_label_buf 3269 &other_buf_ptr ZERO4 H2_OFF_other_buf 3270 &pat_buf_ptr ZERO4 H2_OFF_pat_buf 3271 &line_scratch_ptr ZERO4 H2_OFF_line_scratch 3272 &ev_bytes_ptr ZERO4 H2_OFF_ev_bytes 3273 &df_byte_ptr ZERO4 H2_OFF_df_byte 3274 &input_buf_ptr ZERO4 H2_OFF_input_buf 3275 &output_buf_ptr ZERO4 H2_OFF_output_buf 3276 &text_buf_ptr ZERO4 H2_OFF_text_buf 3277 &labels_ptr ZERO4 H2_OFF_labels 3278 &fixups_ptr ZERO4 H2_OFF_fixups 3279 &scope_history_ptr ZERO4 H2_OFF_scope_history 3280 :bss_init_tbl_end 3281 3282 ## --- BSS scalars ---------------------------------------------------------- 3283 3284 :saved_argc 3285 ZERO8 3286 :saved_argv 3287 ZERO8 3288 :arg_idx 3289 ZERO8 3290 :arg_ptr 3291 ZERO8 3292 :input_path 3293 ZERO8 3294 :input_fd 3295 ZERO8 3296 :input_len 3297 ZERO8 3298 :output_path 3299 ZERO8 3300 :output_fd 3301 ZERO8 3302 :output_used 3303 ZERO8 3304 :output_written 3305 ZERO8 3306 :base_address 3307 ZERO8 3308 :byte_mode 3309 ZERO8 3310 :big_endian 3311 ZERO8 3312 :non_executable 3313 ZERO8 3314 :ptrsize 3315 ZERO8 3316 :ptrsize_used 3317 ZERO8 3318 3319 :pass 3320 ZERO8 3321 :ip 3322 ZERO8 3323 :cur_path 3324 ZERO8 3325 :cur_line 3326 ZERO8 3327 :scan_pos 3328 ZERO8 3329 :scan_end 3330 ZERO8 3331 :text_used 3332 ZERO8 3333 :label_count 3334 ZERO8 3335 :fixup_count 3336 ZERO8 3337 :scope_history_used 3338 ZERO8 3339 :scope_depth 3340 ZERO8 3341 :scope_seq 3342 ZERO8 3343 3344 ## name read 3345 :name_len 3346 ZERO8 3347 :name_scope 3348 ZERO8 3349 :nt_c 3350 ZERO8 3351 :rn_out 3352 ZERO8 3353 :rn_max 3354 ZERO8 3355 :rn_n 3356 ZERO8 3357 3358 ## scan_name (returns ptr+len; pointer goes here, length in a0). 3359 :sn_start 3360 ZERO8 3361 3362 ## record_fixup scratch 3363 :rf_name 3364 ZERO8 3365 :rf_name_len 3366 ZERO8 3367 :rf_other 3368 ZERO8 3369 :rf_other_len 3370 ZERO8 3371 :rf_out_off 3372 ZERO8 3373 :rf_ip_after 3374 ZERO8 3375 :rf_idx 3376 ZERO8 3377 :rf_fp 3378 ZERO8 3379 :rf_i 3380 ZERO8 3381 3382 ## patch_fixups scratch 3383 :pf_i 3384 ZERO8 3385 :pf_fp 3386 ZERO8 3387 :pf_t_label 3388 ZERO8 3389 :pf_value 3390 ZERO8 3391 :pf_stack 3392 ZERO8 3393 :pf_depth 3394 ZERO8 3395 3396 ## process_reference scratch (single-pass record path) 3397 :pref_name 3398 ZERO8 3399 :pref_name_len 3400 ZERO8 3401 :pref_other 3402 ZERO8 3403 :pref_other_len 3404 ZERO8 3405 3406 ## decimal read 3407 :rd_val 3408 ZERO8 3409 :rd_saw 3410 ZERO8 3411 3412 ## byte stream 3413 :pbs_acc 3414 ZERO8 3415 :pbs_have 3416 ZERO8 3417 :pbs_c 3418 ZERO8 3419 3420 ## one byte literal 3421 :p1b_out 3422 ZERO8 3423 :p1b_acc 3424 ZERO8 3425 :p1b_have 3426 ZERO8 3427 :p1b_c 3428 ZERO8 3429 3430 ## intern 3431 :intern_src 3432 ZERO8 3433 :intern_len 3434 ZERO8 3435 :intern_dst 3436 ZERO8 3437 :intern_orig 3438 ZERO8 3439 :intern_i 3440 ZERO8 3441 3442 ## name_eq 3443 :ne_label 3444 ZERO8 3445 :ne_src 3446 ZERO8 3447 :ne_len 3448 ZERO8 3449 3450 ## define_label 3451 :dl_src 3452 ZERO8 3453 :dl_len 3454 ZERO8 3455 :dl_scope 3456 ZERO8 3457 :dl_i 3458 ZERO8 3459 :dl_label 3460 ZERO8 3461 :dl_name_off 3462 ZERO8 3463 3464 ## lookup_label_in 3465 :ll_src 3466 ZERO8 3467 :ll_len 3468 ZERO8 3469 :ll_stack 3470 ZERO8 3471 :ll_depth 3472 ZERO8 3473 :ll_d 3474 ZERO8 3475 :ll_sid 3476 ZERO8 3477 :ll_i 3478 ZERO8 3479 :ll_label 3480 ZERO8 3481 3482 ## process_reference / set_sigil_info 3483 :cur_sigil 3484 ZERO8 3485 :pr_width 3486 ZERO8 3487 :pr_is_rel 3488 ZERO8 3489 :pr_lo 3490 ZERO8 3491 :pr_hi 3492 ZERO8 3493 :pr_range_check 3494 ZERO8 3495 :pr_llen 3496 ZERO8 3497 :pr_olen 3498 ZERO8 3499 :pr_has_other 3500 ZERO8 3501 :pr_t_label 3502 ZERO8 3503 :pr_value 3504 ZERO8 3505 3506 ## emit_value / write_value 3507 :ev_value 3508 ZERO8 3509 :ev_width 3510 ZERO8 3511 :ev_lo 3512 ZERO8 3513 :ev_hi 3514 ZERO8 3515 :ev_range_check 3516 ZERO8 3517 :ev_pack_v 3518 ZERO8 3519 :ev_i 3520 ZERO8 3521 :ev_out_off 3522 ZERO8 3523 3524 ## emit_zeros / emit_fill scratch 3525 :emz_n 3526 ZERO8 3527 :emz_off 3528 ZERO8 3529 :emf_n 3530 ZERO8 3531 :emf_b 3532 ZERO8 3533 3534 ## directive scratch 3535 :da_n 3536 ZERO8 3537 :da_has_pat 3538 ZERO8 3539 :da_patlen 3540 ZERO8 3541 :da_pad 3542 ZERO8 3543 :da_i 3544 ZERO8 3545 :df_n 3546 ZERO8 3547 :df_i 3548 ZERO8 3549 :dp_n 3550 ZERO8 3551 3552 ## str/mem 3553 :se_p 3554 ZERO8 3555 :se_q 3556 ZERO8 3557 :se_len 3558 ZERO8 3559 :me_p 3560 ZERO8 3561 :me_q 3562 ZERO8 3563 :me_len 3564 ZERO8 3565 3566 ## parse_long 3567 :pl_p 3568 ZERO8 3569 :pl_val 3570 ZERO8 3571 :pl_neg 3572 ZERO8 3573 3574 ## fatal 3575 :fm_msg 3576 ZERO8 3577 :fm_tmp 3578 ZERO8 3579 3580 ## write_decimal 3581 :wd_v 3582 ZERO8 3583 :wd_pos 3584 ZERO8 3585 3586 ## --- BSS pointer slots ---------------------------------------------------- 3587 :scope_stack_ptr 3588 ZERO8 3589 :name_buf_ptr 3590 ZERO8 3591 :label_buf_ptr 3592 ZERO8 3593 :other_buf_ptr 3594 ZERO8 3595 :pat_buf_ptr 3596 ZERO8 3597 :line_scratch_ptr 3598 ZERO8 3599 :ev_bytes_ptr 3600 ZERO8 3601 :df_byte_ptr 3602 ZERO8 3603 :input_buf_ptr 3604 ZERO8 3605 :output_buf_ptr 3606 ZERO8 3607 :text_buf_ptr 3608 ZERO8 3609 :labels_ptr 3610 ZERO8 3611 :fixups_ptr 3612 ZERO8 3613 :scope_history_ptr 3614 ZERO8 3615 3616 :ELF_end