https://github.com/akkartik/mu/blob/main/linux/102test.subx
  1 # Rudimentary test harness
  2 
  3 == code
  4 #   instruction                     effective address                                                   register    displacement    immediate
  5 # . op          subop               mod             rm32          base        index         scale       r32
  6 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
  7 
  8 #? Entry:  # manual test
  9 #?     # check-ints-equal(34, 34)
 10 #?     # . . push args
 11 #?     68/push  "error in check-ints-equal"/imm32
 12 #?     68/push  34/imm32
 13 #?     68/push  34/imm32
 14 #?     # . . call
 15 #?     e8/call  check-ints-equal/disp32
 16 #?     # . . discard args
 17 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 18 #?     # syscall_exit(0)
 19 #?     bb/copy-to-ebx  0/imm32
 20 #?     e8/call  syscall_exit/disp32
 21 
 22 # print msg to stderr if a != b, otherwise print "."
 23 check-ints-equal:  # a: int, b: int, msg: (addr array byte)
 24     # . prologue
 25     55/push-ebp
 26     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 27     # . save registers
 28     50/push-eax
 29     51/push-ecx
 30     53/push-ebx
 31     # load first 2 args into eax and ebx
 32     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
 33     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
 34     # if (eax == ebx) success
 35     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
 36     75/jump-if-unequal  $check-ints-equal:else/disp8
 37     # . _write(2/stderr, '.')
 38     # . . push args
 39     68/push  "."/imm32
 40     68/push  2/imm32/stderr
 41     # . . call
 42     e8/call  _write/disp32
 43     # . . discard args
 44     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 45     # . return
 46     eb/jump  $check-ints-equal:end/disp8
 47     # otherwise print error message
 48 $check-ints-equal:else:
 49     # . _write(2/stderr, msg)
 50     # . . push args
 51     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # copy *(ebp+16) to ecx
 52     51/push-ecx
 53     68/push  2/imm32/stderr
 54     # . . call
 55     e8/call  _write/disp32
 56     # . . discard args
 57     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 58     # . _write(2/stderr, Newline)
 59     # . . push args
 60     68/push  Newline/imm32
 61     68/push  2/imm32/stderr
 62     # . . call
 63     e8/call  _write/disp32
 64     # . . discard args
 65     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 66     # increment Num-test-failures
 67     ff          0/subop/increment   0/mod/indirect  5/rm32/.disp32            .             .           .           Num-test-failures/disp32          # increment *Num-test-failures
 68 $check-ints-equal:end:
 69     # . restore registers
 70     5b/pop-to-ebx
 71     59/pop-to-ecx
 72     58/pop-to-eax
 73     # . epilogue
 74     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 75     5d/pop-to-ebp
 76     c3/return
 77 
 78 == data
 79 
 80 # length-prefixed string containing just a single newline
 81 # convenient to have when printing messages and so on
 82 Newline:  # (array byte)
 83     # size: int
 84     1/imm32
 85     # data
 86     0a/newline
 87 
 88 # every test failure increments this counter
 89 Num-test-failures:  # int
 90     0/imm32
 91 
 92 # length-prefixed string containing just a single space
 93 Space:  # (array byte)
 94     # size: int
 95     1/imm32
 96     # data
 97     20/space
 98 
 99 # length-prefixed string containing just a single slash
100 Slash:  # (array byte)
101     # size: int
102     1/imm32
103     # data
104     2f/slash
105 
106 # . . vim:nowrap:textwidth=0