https://github.com/akkartik/mu/blob/master/subx/examples/ex8.subx

     1 # Example reading commandline arguments: compute length of first arg.
     2 #
     3 # To run (from the subx directory):
     4 #   $ ./subx translate examples/ex8.subx -o examples/ex8
     5 #   $ ./subx run examples/ex8 abc de fghi
     6 # Expected result:
     7 #   $ echo $?
     8 #   3  # length of 'abc'
     9 #
    10 # At the start of a SubX program:
    11 #   argc: *ESP
    12 #   argv[0]: *(ESP+4)
    13 #   argv[1]: *(ESP+8)
    14 #   ...
    15 # Locals start from ESP-4 downwards.
    16
    17 == code
    18 #   instruction                     effective address                                                   register    displacement    immediate
    19 # . op          subop               mod             rm32          base        index         scale       r32
    20 # . 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
    21
    22     # . prolog
    23     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    24     # EAX = ascii-length(argv[1])
    25     # . . push args
    26     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
    27     # . . call
    28     e8/call  ascii-length/disp32
    29     # . . discard args
    30     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    31
    32     # exit(EAX)
    33     89/copy                         3/mod/direct    3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # copy EAX to EBX
    34     b8/copy-to-EAX  1/imm32/exit
    35     cd/syscall  0x80/imm8
    36
    37 ascii-length:  # s : (address array byte) -> n/EAX
    38     # EDX = s
    39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
    40     # var result/EAX = 0
    41     b8/copy-to-EAX  0/imm32
    42 $ascii-length-loop:
    43     # var c/ECX = *s
    44     8a/copy-byte                    0/mod/*         2/rm32/EDX    .           .             .           1/r32/CL    .               .                 # copy byte at *EDX to CL
    45     # if (c == '\0') break
    46     81          7/subop/compare     3/mod/direct    1/rm32/ECX    .           .             .           .           .               0/imm32           # compare ECX
    47     74/jump-if-equal  $ascii-length-ret/disp8
    48     # ++s
    49     42/increment-EDX
    50     # ++result
    51     40/inc-EAX
    52     # loop
    53     eb/jump  $ascii-length-loop/disp8
    54 $ascii-length-ret:
    55     # return EAX
    56     c3/return
    57
    58 # . . vim:nowrap:textwidth=0