1 # Initialize the minimal runtime for Mu programs. 2 # 3 # See translate_mu for how this file is used. 4 # 5 # Mu programs start at a function called 'main' with this signature: 6 # fn main args: (addr array (addr array byte)) -> exit-status/ebx: int 7 # If your program doesn't need commandline arguments you can drop it: 8 # fn main -> exit-status/ebx: int 9 # 10 # Notice that the output must be in ebx, so that the exit() syscall can pick 11 # it up. 12 13 == code 14 15 Entry: 16 # we don't use ebp in Entry; just initialize it 17 bd/copy-to-ebp 0/imm32 18 # - save argc and argv 19 # var argc-and-argv/esi 20 89/<- %esi 4/r32/esp 21 $Entry:initialize-heap: 22 # - initialize the heap 23 (new-segment *Heap-size Heap) 24 $Entry:initialize-args: 25 # - convert argv from null-terminated 'kernel' strings to length-prefixed Mu strings 26 # var argc/edx: int 27 8b/-> *esi 2/r32/edx 28 # argc is in words; convert it to bytes 29 c1/shift 4/subop/left %edx 2/imm8 30 # var tmp/ebx: handle 31 68/push 0/imm32 32 68/push 0/imm32 33 89/<- %ebx 4/r32/esp 34 # var args/edi: (addr array (addr array byte)) 35 (allocate-array Heap %edx %ebx) 36 (lookup *ebx *(ebx+4)) # => eax 37 89/<- %edi 0/r32/eax 38 # var curr/ecx: (addr kernel-string) = argv 39 8d/copy-address *(esi+4) 1/r32/ecx 40 # var max/edx: (addr kernel-string) = argv+4+argc 41 8d/copy-address *(ecx+edx) 2/r32/edx 42 # var dest/esi: (addr (addr array byte)) = args+4 43 8d/copy-address *(edi+4) 6/r32/esi 44 { 45 # if (curr >= max) break 46 39/compare %ecx 2/r32/edx 47 73/jump-if-addr>= break/disp8 48 # *dest = kernel-string-to-string(*curr) 49 (kernel-string-to-string Heap *ecx %ebx) 50 (lookup *ebx *(ebx+4)) # => eax 51 89/<- *esi 0/r32/eax 52 # curr += 4 53 81 0/subop/add %ecx 4/imm32 54 # dest += 4 55 81 0/subop/add %esi 4/imm32 56 # 57 eb/jump loop/disp8 58 } 59 # - run Mu program 60 (main %edi) # => ebx 61 # - exit 62 (syscall_exit)