boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

P1-aarch64.M1pp (14392B)


      1 # aarch64.M1M -- P1 aarch64 backend expressed in m1macro.
      2 
      3 # Width hooks consumed by the portable P1pp support library.
      4 %macro p1_word_bytes()
      5 8
      6 %endm
      7 %macro p1_word_bits()
      8 64
      9 %endm
     10 %macro p1_word_shift()
     11 3
     12 %endm
     13 %macro p1_scheme_heap_bytes()
     14 0x10000000
     15 %endm
     16 %macro p1_waitid_status_off()
     17 24
     18 %endm
     19 #
     20 # This mirrors p1/aarch64.py using the m1macro integer builtins:
     21 #   %(sexpr), $(sexpr), and %select(cond, then, else).
     22 
     23 # ---- Native register numbers --------------------------------------------
     24 
     25 %macro aa64_reg_a0()
     26 0
     27 %endm
     28 %macro aa64_reg_a1()
     29 1
     30 %endm
     31 %macro aa64_reg_a2()
     32 2
     33 %endm
     34 %macro aa64_reg_a3()
     35 3
     36 %endm
     37 %macro aa64_reg_x4()
     38 4
     39 %endm
     40 %macro aa64_reg_x5()
     41 5
     42 %endm
     43 %macro aa64_reg_t0()
     44 9
     45 %endm
     46 %macro aa64_reg_t1()
     47 10
     48 %endm
     49 %macro aa64_reg_t2()
     50 11
     51 %endm
     52 %macro aa64_reg_s0()
     53 19
     54 %endm
     55 %macro aa64_reg_s1()
     56 20
     57 %endm
     58 %macro aa64_reg_s2()
     59 21
     60 %endm
     61 %macro aa64_reg_s3()
     62 22
     63 %endm
     64 %macro aa64_reg_sp()
     65 31
     66 %endm
     67 %macro aa64_reg_xzr()
     68 31
     69 %endm
     70 %macro aa64_reg_lr()
     71 30
     72 %endm
     73 %macro aa64_reg_br()
     74 17
     75 %endm
     76 %macro aa64_reg_scratch()
     77 16
     78 %endm
     79 %macro aa64_reg_x8()
     80 8
     81 %endm
     82 %macro aa64_reg_save0()
     83 23
     84 %endm
     85 %macro aa64_reg_save1()
     86 24
     87 %endm
     88 %macro aa64_reg_save2()
     89 25
     90 %endm
     91 
     92 %macro aa64_reg(r)
     93 %aa64_reg_##r
     94 %endm
     95 
     96 %macro aa64_is_sp_a0()
     97 0
     98 %endm
     99 %macro aa64_is_sp_a1()
    100 0
    101 %endm
    102 %macro aa64_is_sp_a2()
    103 0
    104 %endm
    105 %macro aa64_is_sp_a3()
    106 0
    107 %endm
    108 %macro aa64_is_sp_x4()
    109 0
    110 %endm
    111 %macro aa64_is_sp_x5()
    112 0
    113 %endm
    114 %macro aa64_is_sp_t0()
    115 0
    116 %endm
    117 %macro aa64_is_sp_t1()
    118 0
    119 %endm
    120 %macro aa64_is_sp_t2()
    121 0
    122 %endm
    123 %macro aa64_is_sp_s0()
    124 0
    125 %endm
    126 %macro aa64_is_sp_s1()
    127 0
    128 %endm
    129 %macro aa64_is_sp_s2()
    130 0
    131 %endm
    132 %macro aa64_is_sp_s3()
    133 0
    134 %endm
    135 %macro aa64_is_sp_sp()
    136 1
    137 %endm
    138 %macro aa64_is_sp_xzr()
    139 0
    140 %endm
    141 %macro aa64_is_sp_lr()
    142 0
    143 %endm
    144 %macro aa64_is_sp_br()
    145 0
    146 %endm
    147 %macro aa64_is_sp_scratch()
    148 0
    149 %endm
    150 %macro aa64_is_sp_x8()
    151 0
    152 %endm
    153 %macro aa64_is_sp_save0()
    154 0
    155 %endm
    156 %macro aa64_is_sp_save1()
    157 0
    158 %endm
    159 %macro aa64_is_sp_save2()
    160 0
    161 %endm
    162 
    163 %macro aa64_is_sp(r)
    164 %aa64_is_sp_##r
    165 %endm
    166 
    167 # ---- Low-level instruction encoders --------------------------------------
    168 
    169 %macro aa64_rrr(base, rd, ra, rb)
    170 %((| base (<< %aa64_reg(rb) 16) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    171 %endm
    172 
    173 %macro aa64_add_imm(rd, ra, imm12)
    174 %((| 0x91000000 (<< (& imm12 0xFFF) 10) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    175 %endm
    176 
    177 %macro aa64_sub_imm(rd, ra, imm12)
    178 %((| 0xD1000000 (<< (& imm12 0xFFF) 10) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    179 %endm
    180 
    181 %macro aa64_add_imm_lsl12(rd, ra, imm12)
    182 %((| 0x91400000 (<< (& imm12 0xFFF) 10) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    183 %endm
    184 
    185 %macro aa64_sub_imm_lsl12(rd, ra, imm12)
    186 %((| 0xD1400000 (<< (& imm12 0xFFF) 10) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    187 %endm
    188 
    189 # ADD/SUB immediate with arbitrary unsigned magnitude. The native imm12
    190 # form covers [0, 4095]; the imm12<<12 form (optionally combined with a
    191 # second imm12 for the low bits) covers [4096, 0xFFFFFF]. Past 24 bits,
    192 # materialize the constant in scratch and emit the R-type ADD/SUB.
    193 # Callers must not pass `scratch` as `ra` (the materialize would
    194 # clobber it before the R-type read).
    195 %macro aa64_add_imm_any(rd, ra, imm)
    196 %select((<= imm 4095),
    197     %aa64_add_imm(rd, ra, imm),
    198     %select((<= imm 0xFFFFFF),
    199         %select((= (& imm 0xFFF) 0),
    200             %aa64_add_imm_lsl12(rd, ra, (>> imm 12)),
    201             %aa64_add_imm_lsl12(rd, ra, (>> imm 12))
    202             %aa64_add_imm(rd, rd, (& imm 0xFFF))),
    203         %p1_li(scratch, imm)
    204         %aa64_rrr(0x8B000000, rd, ra, scratch)))
    205 %endm
    206 
    207 %macro aa64_sub_imm_any(rd, ra, imm)
    208 %select((<= imm 4095),
    209     %aa64_sub_imm(rd, ra, imm),
    210     %select((<= imm 0xFFFFFF),
    211         %select((= (& imm 0xFFF) 0),
    212             %aa64_sub_imm_lsl12(rd, ra, (>> imm 12)),
    213             %aa64_sub_imm_lsl12(rd, ra, (>> imm 12))
    214             %aa64_sub_imm(rd, rd, (& imm 0xFFF))),
    215         %p1_li(scratch, imm)
    216         %aa64_rrr(0xCB000000, rd, ra, scratch)))
    217 %endm
    218 
    219 %macro aa64_mov_rr(dst, src)
    220 %select((= %aa64_is_sp(dst) 1),
    221     %aa64_add_imm(sp, src, 0),
    222     %select((= %aa64_is_sp(src) 1),
    223         %aa64_add_imm(dst, sp, 16),
    224         %((| 0xAA000000 (<< %aa64_reg(src) 16) (<< 31 5) %aa64_reg(dst)))))
    225 %endm
    226 
    227 %macro aa64_ubfm(rd, ra, immr, imms)
    228 %((| 0xD3400000 (<< immr 16) (<< imms 10) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    229 %endm
    230 
    231 %macro aa64_sbfm(rd, ra, immr, imms)
    232 %((| 0x93400000 (<< immr 16) (<< imms 10) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    233 %endm
    234 
    235 %macro aa64_movz(rd, imm16)
    236 %((| 0xD2800000 (<< (& imm16 0xFFFF) 5) %aa64_reg(rd)))
    237 %endm
    238 
    239 %macro aa64_movn(rd, imm16)
    240 %((| 0x92800000 (<< (& imm16 0xFFFF) 5) %aa64_reg(rd)))
    241 %endm
    242 
    243 %macro aa64_materialize_small_imm(rd, imm)
    244 %select((>= imm 0),
    245     %aa64_movz(rd, imm),
    246     %aa64_movn(rd, (& (~ imm) 0xFFFF)))
    247 %endm
    248 
    249 # Materialize an arbitrary 64-bit signed immediate into `rd`. Picks the
    250 # 1-insn MOVZ / MOVN form when the value (or its complement, for
    251 # negatives) fits 16 bits; otherwise emits the 4-insn MOVZ + 3*MOVK
    252 # chain used by %p1_li. Used by ANDI/ORI/ADDI fallbacks below to avoid
    253 # silently truncating to the small-imm window.
    254 %macro aa64_materialize_imm_any(rd, imm)
    255 %select((>= imm 0),
    256     %select((<= imm 0xFFFF),
    257         %aa64_movz(rd, imm),
    258         %p1_li(rd, imm)),
    259     %select((>= imm -65536),
    260         %aa64_movn(rd, (& (~ imm) 0xFFFF)),
    261         %p1_li(rd, imm)))
    262 %endm
    263 
    264 %macro aa64_ldst_uimm12(base, rt, rn, off_bytes, size_log2)
    265 %((| base (<< (>> off_bytes size_log2) 10) (<< %aa64_reg(rn) 5) %aa64_reg(rt)))
    266 %endm
    267 
    268 %macro aa64_ldst_unscaled(base, rt, rn, off)
    269 %((| base (<< (& off 0x1FF) 12) (<< %aa64_reg(rn) 5) %aa64_reg(rt)))
    270 %endm
    271 
    272 %macro aa64_mem_uimm_base_LD()
    273 0xF9400000
    274 %endm
    275 %macro aa64_mem_uimm_base_ST()
    276 0xF9000000
    277 %endm
    278 %macro aa64_mem_uimm_base_LB()
    279 0x39400000
    280 %endm
    281 %macro aa64_mem_uimm_base_SB()
    282 0x39000000
    283 %endm
    284 
    285 %macro aa64_mem_unscaled_base_LD()
    286 0xF8400000
    287 %endm
    288 %macro aa64_mem_unscaled_base_ST()
    289 0xF8000000
    290 %endm
    291 %macro aa64_mem_unscaled_base_LB()
    292 0x38400000
    293 %endm
    294 %macro aa64_mem_unscaled_base_SB()
    295 0x38000000
    296 %endm
    297 
    298 %macro aa64_mem_size_LD()
    299 3
    300 %endm
    301 %macro aa64_mem_size_ST()
    302 3
    303 %endm
    304 %macro aa64_mem_size_LB()
    305 0
    306 %endm
    307 %macro aa64_mem_size_SB()
    308 0
    309 %endm
    310 
    311 %macro aa64_mem_uimm_base(op)
    312 %aa64_mem_uimm_base_##op
    313 %endm
    314 
    315 %macro aa64_mem_unscaled_base(op)
    316 %aa64_mem_unscaled_base_##op
    317 %endm
    318 
    319 %macro aa64_mem_size(op)
    320 %aa64_mem_size_##op
    321 %endm
    322 
    323 %macro aa64_mem_fallback(op, rt, rn, off)
    324 %select((>= off 0),
    325     %aa64_add_imm_any(scratch, rn, off)
    326     %aa64_ldst_uimm12(%aa64_mem_uimm_base(op), rt, scratch, 0, %aa64_mem_size(op)),
    327     %aa64_sub_imm_any(scratch, rn, (- 0 off))
    328     %aa64_ldst_uimm12(%aa64_mem_uimm_base(op), rt, scratch, 0, %aa64_mem_size(op)))
    329 %endm
    330 
    331 %macro aa64_mem_after_uimm(op, rt, rn, off)
    332 %select((>= off -256),
    333     %select((<= off 255),
    334         %aa64_ldst_unscaled(%aa64_mem_unscaled_base(op), rt, rn, off),
    335         %aa64_mem_fallback(op, rt, rn, off)),
    336     %aa64_mem_fallback(op, rt, rn, off))
    337 %endm
    338 
    339 %macro aa64_mem_after_nonneg(op, rt, rn, off)
    340 %select((= (& off (- (<< 1 %aa64_mem_size(op)) 1)) 0),
    341     %select((< off (<< 4096 %aa64_mem_size(op))),
    342         %aa64_ldst_uimm12(%aa64_mem_uimm_base(op), rt, rn, off, %aa64_mem_size(op)),
    343         %aa64_mem_after_uimm(op, rt, rn, off)),
    344     %aa64_mem_after_uimm(op, rt, rn, off))
    345 %endm
    346 
    347 %macro aa64_mem(op, rt, rn, off)
    348 %select((>= off 0),
    349     %aa64_mem_after_nonneg(op, rt, rn, off),
    350     %aa64_mem_after_uimm(op, rt, rn, off))
    351 %endm
    352 
    353 %macro aa64_cmp_skip(cond, ra, rb)
    354 %((| 0xEB000000 (<< %aa64_reg(rb) 16) (<< %aa64_reg(ra) 5) 31))
    355 %((| 0x54000040 cond))
    356 %endm
    357 
    358 %macro aa64_br(reg)
    359 %((| 0xD61F0000 (<< %aa64_reg(reg) 5)))
    360 %endm
    361 
    362 %macro aa64_blr(reg)
    363 %((| 0xD63F0000 (<< %aa64_reg(reg) 5)))
    364 %endm
    365 
    366 %macro aa64_ret()
    367 %(0xD65F03C0)
    368 %endm
    369 
    370 %macro aa64_lit64_prefix(rd)
    371 # 64-bit literal-pool prefix for LI: ldr xN, [pc,#8]; b PC+12.
    372 # The 8 bytes that follow in source become the literal; b skips them.
    373 %((| 0x58000040 %aa64_reg(rd)))
    374 %(0x14000003)
    375 %endm
    376 
    377 %macro aa64_lit32_prefix(rd)
    378 # 32-bit literal-pool prefix for LA / LA_BR: ldr wN, [pc,#8]; b PC+8.
    379 # ldr w zero-extends into the full 64-bit register, so a 4-byte literal
    380 # is enough for any address in the stage0 layout. Lets source use
    381 # `&label` directly without padding to 8 bytes.
    382 %((| 0x18000040 %aa64_reg(rd)))
    383 %(0x14000002)
    384 %endm
    385 
    386 # ---- P1 register-register op lowering -----------------------------------
    387 
    388 %macro aa64_rrr_ADD(rd, ra, rb)
    389 %aa64_rrr(0x8B000000, rd, ra, rb)
    390 %endm
    391 %macro aa64_rrr_SUB(rd, ra, rb)
    392 %aa64_rrr(0xCB000000, rd, ra, rb)
    393 %endm
    394 %macro aa64_rrr_AND(rd, ra, rb)
    395 %aa64_rrr(0x8A000000, rd, ra, rb)
    396 %endm
    397 %macro aa64_rrr_OR(rd, ra, rb)
    398 %aa64_rrr(0xAA000000, rd, ra, rb)
    399 %endm
    400 %macro aa64_rrr_XOR(rd, ra, rb)
    401 %aa64_rrr(0xCA000000, rd, ra, rb)
    402 %endm
    403 %macro aa64_rrr_SHL(rd, ra, rb)
    404 %aa64_rrr(0x9AC02000, rd, ra, rb)
    405 %endm
    406 %macro aa64_rrr_SHR(rd, ra, rb)
    407 %aa64_rrr(0x9AC02400, rd, ra, rb)
    408 %endm
    409 %macro aa64_rrr_SAR(rd, ra, rb)
    410 %aa64_rrr(0x9AC02800, rd, ra, rb)
    411 %endm
    412 %macro aa64_rrr_DIV(rd, ra, rb)
    413 %aa64_rrr(0x9AC00C00, rd, ra, rb)
    414 %endm
    415 %macro aa64_rrr_UDIV(rd, ra, rb)
    416 %aa64_rrr(0x9AC00800, rd, ra, rb)
    417 %endm
    418 %macro aa64_rrr_MUL(rd, ra, rb)
    419 %((| 0x9B000000 (<< %aa64_reg(rb) 16) (<< 31 10) (<< %aa64_reg(ra) 5) %aa64_reg(rd)))
    420 %endm
    421 %macro aa64_rrr_REM(rd, ra, rb)
    422 %((| 0x9AC00C00 (<< %aa64_reg(rb) 16) (<< %aa64_reg(ra) 5) %aa64_reg(scratch)))
    423 %((| 0x9B008000 (<< %aa64_reg(rb) 16) (<< %aa64_reg(ra) 10) (<< %aa64_reg(scratch) 5) %aa64_reg(rd)))
    424 %endm
    425 %macro aa64_rrr_UREM(rd, ra, rb)
    426 %((| 0x9AC00800 (<< %aa64_reg(rb) 16) (<< %aa64_reg(ra) 5) %aa64_reg(scratch)))
    427 %((| 0x9B008000 (<< %aa64_reg(rb) 16) (<< %aa64_reg(ra) 10) (<< %aa64_reg(scratch) 5) %aa64_reg(rd)))
    428 %endm
    429 
    430 %macro aa64_rrr_op(op, rd, ra, rb)
    431 %aa64_rrr_##op(rd, ra, rb)
    432 %endm
    433 
    434 # ---- P1 operation lowering -----------------------------------------------
    435 
    436 # MOVZ + 3 MOVK chain for 64-bit immediate. 4 instructions, 16 bytes — same
    437 # size as the prior LDR-literal-pool lowering. Pure instructions, no inline
    438 # data, which is the standard aarch64 codegen for materializing constants.
    439 %macro aa64_movk_lsl16(rd, imm16)
    440 %((| 0xF2A00000 (<< (& imm16 0xFFFF) 5) %aa64_reg(rd)))
    441 %endm
    442 %macro aa64_movk_lsl32(rd, imm16)
    443 %((| 0xF2C00000 (<< (& imm16 0xFFFF) 5) %aa64_reg(rd)))
    444 %endm
    445 %macro aa64_movk_lsl48(rd, imm16)
    446 %((| 0xF2E00000 (<< (& imm16 0xFFFF) 5) %aa64_reg(rd)))
    447 %endm
    448 
    449 %macro p1_li(rd, imm)
    450 %aa64_movz(rd, (& imm 0xFFFF))
    451 %aa64_movk_lsl16(rd, (& (>> imm 16) 0xFFFF))
    452 %aa64_movk_lsl32(rd, (& (>> imm 32) 0xFFFF))
    453 %aa64_movk_lsl48(rd, (& (>> imm 48) 0xFFFF))
    454 %endm
    455 
    456 %macro p1_la(rd)
    457 %aa64_lit32_prefix(rd)
    458 %endm
    459 
    460 %macro p1_labr()
    461 %aa64_lit32_prefix(br)
    462 %endm
    463 
    464 %macro p1_mov(rd, rs)
    465 %aa64_mov_rr(rd, rs)
    466 %endm
    467 
    468 %macro p1_rrr(op, rd, ra, rb)
    469 %aa64_rrr_op(op, rd, ra, rb)
    470 %endm
    471 
    472 %macro p1_addi(rd, ra, imm)
    473 %select((>= imm 0),
    474     %aa64_add_imm_any(rd, ra, imm),
    475     %aa64_sub_imm_any(rd, ra, (- 0 imm)))
    476 %endm
    477 
    478 %macro p1_logi_ANDI(rd, ra, imm)
    479 %aa64_materialize_imm_any(scratch, imm)
    480 %aa64_rrr(0x8A000000, rd, ra, scratch)
    481 %endm
    482 %macro p1_logi_ORI(rd, ra, imm)
    483 %aa64_materialize_imm_any(scratch, imm)
    484 %aa64_rrr(0xAA000000, rd, ra, scratch)
    485 %endm
    486 %macro p1_logi(op, rd, ra, imm)
    487 %p1_logi_##op(rd, ra, imm)
    488 %endm
    489 
    490 %macro p1_shifti_SHLI(rd, ra, imm)
    491 %aa64_ubfm(rd, ra, (& (- 0 imm) 63), (- 63 imm))
    492 %endm
    493 %macro p1_shifti_SHRI(rd, ra, imm)
    494 %aa64_ubfm(rd, ra, imm, 63)
    495 %endm
    496 %macro p1_shifti_SARI(rd, ra, imm)
    497 %aa64_sbfm(rd, ra, imm, 63)
    498 %endm
    499 %macro p1_shifti(op, rd, ra, imm)
    500 %p1_shifti_##op(rd, ra, imm)
    501 %endm
    502 
    503 %macro p1_mem(op, rt, rn, off)
    504 %select((= %aa64_is_sp(rn) 1),
    505     %aa64_mem(op, rt, rn, (+ off 16)),
    506     %aa64_mem(op, rt, rn, off))
    507 %endm
    508 
    509 %macro p1_ldarg(rd, slot)
    510 %aa64_mem(LD, scratch, sp, 8)
    511 %aa64_mem(LD, rd, scratch, (+ 16 (* 8 slot)))
    512 %endm
    513 
    514 %macro p1_b()
    515 %aa64_br(br)
    516 %endm
    517 
    518 %macro p1_br(rs)
    519 %aa64_br(rs)
    520 %endm
    521 
    522 %macro p1_call()
    523 %aa64_blr(br)
    524 %endm
    525 
    526 %macro p1_callr(rs)
    527 %aa64_blr(rs)
    528 %endm
    529 
    530 %macro p1_ret()
    531 %aa64_ret
    532 %endm
    533 
    534 %macro p1_eret()
    535 %aa64_mem(LD, lr, sp, 0)
    536 %aa64_mem(LD, x8, sp, 8)
    537 %aa64_mov_rr(sp, x8)
    538 %aa64_ret
    539 %endm
    540 
    541 %macro p1_tail()
    542 %aa64_mem(LD, lr, sp, 0)
    543 %aa64_mem(LD, x8, sp, 8)
    544 %aa64_mov_rr(sp, x8)
    545 %aa64_br(br)
    546 %endm
    547 
    548 %macro p1_tailr(rs)
    549 %aa64_mem(LD, lr, sp, 0)
    550 %aa64_mem(LD, x8, sp, 8)
    551 %aa64_mov_rr(sp, x8)
    552 %aa64_br(rs)
    553 %endm
    554 
    555 %macro p1_condb_BEQ(ra, rb)
    556 %aa64_cmp_skip(1, ra, rb)
    557 %aa64_br(br)
    558 %endm
    559 %macro p1_condb_BNE(ra, rb)
    560 %aa64_cmp_skip(0, ra, rb)
    561 %aa64_br(br)
    562 %endm
    563 %macro p1_condb_BLT(ra, rb)
    564 %aa64_cmp_skip(10, ra, rb)
    565 %aa64_br(br)
    566 %endm
    567 %macro p1_condb_BLTU(ra, rb)
    568 %aa64_cmp_skip(2, ra, rb)
    569 %aa64_br(br)
    570 %endm
    571 %macro p1_condb(op, ra, rb)
    572 %p1_condb_##op(ra, rb)
    573 %endm
    574 
    575 %macro p1_condbz_BEQZ(ra)
    576 %((| 0xB5000000 (<< 2 5) %aa64_reg(ra)))
    577 %aa64_br(br)
    578 %endm
    579 %macro p1_condbz_BNEZ(ra)
    580 %((| 0xB4000000 (<< 2 5) %aa64_reg(ra)))
    581 %aa64_br(br)
    582 %endm
    583 %macro p1_condbz_BLTZ(ra)
    584 %((| 0xEB1F001F (<< %aa64_reg(ra) 5)))
    585 %((| 0x54000040 10))
    586 %aa64_br(br)
    587 %endm
    588 %macro p1_condbz(op, ra)
    589 %p1_condbz_##op(ra)
    590 %endm
    591 
    592 %macro p1_enter(size)
    593 %aa64_sub_imm_any(sp, sp, (& (+ (+ 16 size) 15) -16))
    594 %aa64_mem(ST, lr, sp, 0)
    595 %aa64_add_imm_any(x8, sp, (& (+ (+ 16 size) 15) -16))
    596 %aa64_mem(ST, x8, sp, 8)
    597 %endm
    598 
    599 %macro p1_entry()
    600 # :_start stub emitted by the aarch64 backend per the P1 program-entry
    601 # model. Captures argc from [sp] into a0, computes argv=sp+8 into a1,
    602 # calls p1_main under the one-word direct-result convention, then issues
    603 # a native Linux sys_exit with p1_main's return value as the exit status.
    604 :_start
    605 %aa64_mem(LD, a0, sp, 0)
    606 %aa64_add_imm(a1, sp, 8)
    607 %aa64_lit32_prefix(br)
    608 &p1_main
    609 %aa64_blr(br)
    610 %aa64_movz(x8, 93)
    611 %(0xD4000001)
    612 %endm
    613 
    614 %macro p1_syscall()
    615 %aa64_mov_rr(x8, a0)
    616 %aa64_mov_rr(save0, a1)
    617 %aa64_mov_rr(save1, a2)
    618 %aa64_mov_rr(save2, a3)
    619 %aa64_mov_rr(a0, save0)
    620 %aa64_mov_rr(a1, save1)
    621 %aa64_mov_rr(a2, save2)
    622 %aa64_mov_rr(a3, t0)
    623 %aa64_mov_rr(x4, s0)
    624 %aa64_mov_rr(x5, s1)
    625 %(0xD4000001)
    626 %aa64_mov_rr(a1, save0)
    627 %aa64_mov_rr(a2, save1)
    628 %aa64_mov_rr(a3, save2)
    629 %endm
    630 
    631 # ---- Linux aarch64 syscall numbers ---------------------------------------
    632 # Each macro returns the syscall number as an integer atom so callers can
    633 # use it inside expressions (e.g. `%li(a0, %sys_write)`).
    634 
    635 %macro p1_sys_read()
    636 63
    637 %endm
    638 %macro p1_sys_write()
    639 64
    640 %endm
    641 %macro p1_sys_close()
    642 57
    643 %endm
    644 %macro p1_sys_openat()
    645 56
    646 %endm
    647 %macro p1_sys_exit()
    648 93
    649 %endm
    650 %macro p1_sys_clone()
    651 220
    652 %endm
    653 %macro p1_sys_execve()
    654 221
    655 %endm
    656 %macro p1_sys_spawn()
    657 1024
    658 %endm
    659 %macro p1_sys_waitid()
    660 95
    661 %endm
    662 %macro p1_sys_lseek()
    663 62
    664 %endm
    665 %macro p1_sys_lseek_wrapper()
    666 %mov(a3, a2)
    667 %mov(a2, a1)
    668 %mov(a1, a0)
    669 %li(a0, %p1_sys_lseek)
    670 %syscall
    671 %ret
    672 %endm
    673 %macro p1_sys_brk()
    674 214
    675 %endm
    676 %macro p1_sys_unlinkat()
    677 35
    678 %endm