boot2

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

M0.hex2 (43551B)


      1 # SPDX-FileCopyrightText: 2019 Jeremiah Orians <jeremiah@pdp10.guru>
      2 # SPDX-FileCopyrightText: 2023 Andrius Štikonas <andrius@stikonas.eu>
      3 #
      4 # SPDX-License-Identifier: GPL-3.0-or-later
      5 
      6     # Register usage:
      7     # RAX, RSI, RDI => Temps
      8     # R12 => MALLOC
      9     # R13 => HEAD
     10     # R14 => Output_file
     11     # R15 => Input_file
     12 
     13     # Struct format: (size 32)
     14     # NEXT => 0
     15     # TYPE => 8
     16     # TEXT => 16
     17     # EXPRESSION => 24
     18 
     19     # Types
     20     # None => 0
     21     # MACRO => 1
     22     # STRING => 2
     23 
     24 # Where the ELF Header is going to hit
     25 # Simply jump to _start
     26 # Our main function
     27 :_start
     28     58                      ; pop_rax                     # Get the number of arguments
     29     5F                      ; pop_rdi                     # Get the program name
     30     5F                      ; pop_rdi                     # Get the actual input name
     31     48C7C6 00000000         ; mov_rsi, %0                 # prepare read_only
     32     48C7C0 02000000         ; mov_rax, %2                 # the syscall number for open()
     33     0F05                    ; syscall                     # Now open that damn file
     34     4989C7                  ; mov_r15,rax                 # Preserve the file pointer we were given
     35 
     36     5F                      ; pop_rdi                     # Get the actual output name
     37     48C7C6 41020000         ; mov_rsi, %577               # Prepare file as O_WRONLY|O_CREAT|O_TRUNC
     38     48C7C2 80010000         ; mov_rdx, %384               # Prepare file as RW for owner only (600 in octal)
     39     48C7C0 02000000         ; mov_rax, %2                 # the syscall number for open()
     40     0F05                    ; syscall                     # Now open that damn file
     41     483D 00000000           ; cmp_rax, %0                 # Check for missing output
     42     7F !_start_out          ; jg8 !_start_out             # Have real input
     43     48C7C0 01000000         ; mov_rax, %1                 # Use stdout
     44 
     45 :_start_out
     46     4989C6                  ; mov_r14,rax                 # Preserve the file pointer we were given
     47 
     48     48C7C0 0C000000         ; mov_rax, %12                # the Syscall # for SYS_BRK
     49     48C7C7 00000000         ; mov_rdi, %0                 # Get current brk
     50     0F05                    ; syscall                     # Let the kernel do the work
     51     4989C4                  ; mov_r12,rax                 # Set our malloc pointer
     52 
     53     4D31ED                  ; xor_r13,r13                 # Set HEAD = NULL
     54     E8 %Tokenize_Line       ; call %Tokenize_Line         # Get all lines
     55     4C89E8                  ; mov_rax,r13                 # prepare for Reverse_List
     56     E8 %Reverse_List        ; call %Reverse_List          # Correct order
     57     4989C5                  ; mov_r13,rax                 # Update HEAD
     58     E8 %Identify_Macros     ; call %Identify_Macros       # Find the DEFINEs
     59     E8 %Line_Macro          ; call %Line_Macro            # Apply the DEFINEs
     60     E8 %Process_String      ; call %Process_String        # Handle strings
     61     E8 %Eval_Immediates     ; call %Eval_Immediates       # Handle Numbers
     62     E8 %Preserve_Other      ; call %Preserve_Other        # Collect the remaining
     63     E8 %Print_Hex           ; call %Print_Hex             # Output our results
     64 
     65 :Done
     66     # program completed Successfully
     67     48C7C7 00000000         ; mov_rdi, %0                 # All is well
     68     48C7C0 3C000000         ; mov_rax, %0x3c              # put the exit syscall number in eax
     69     0F05                    ; syscall                     # Call it a good day
     70 
     71 
     72 # Tokenize_Line Function
     73 # Using input file R15 and Head R13
     74 # Creates a linked list of structs
     75 # Uses RBX for in_set strings, RCX for Int C and RDX for Struct Token* p
     76 :Tokenize_Line
     77     53                      ; push_rbx                    # Protect RBX
     78     51                      ; push_rcx                    # Protect RCX
     79     52                      ; push_rdx                    # Protect RDX
     80 
     81 :restart
     82     E8 %fgetc               ; call %fgetc                 # Read a char
     83     483D FCFFFFFF           ; cmp_rax, %-4                # Check for EOF
     84     74 !done                ; je8 !done                   # File is collected
     85 
     86     480FB6C0                ; movzx_rax,al                # We have to zero extend it to use it
     87     4889C1                  ; mov_rcx,rax                 # Protect C
     88 
     89     488D1D %comments        ; lea_rbx,[rip+DWORD] %comments # Get pointer to "#;"
     90     E8 %In_Set              ; call %In_Set                # Check for comments
     91     483D 01000000           ; cmp_rax, %1                 # If comments
     92     0F84 %Purge_LineComment ; je %Purge_LineComment       # try again
     93 
     94     4889C8                  ; mov_rax,rcx                 # put C in place for check
     95     488D1D %terminators     ; lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t "
     96     E8 %In_Set              ; call %In_Set                # Check for terminators
     97     483D 01000000           ; cmp_rax, %1                 # If terminator
     98     74 !restart             ; je8 !restart                # try again
     99 
    100     48C7C0 20000000         ; mov_rax, %32                # Malloc the struct P
    101     E8 %malloc              ; call %malloc                # Get pointer to P
    102     4889C2                  ; mov_rdx,rax                 # Protect P
    103     4C892A                  ; mov_[rdx],r13               # P->NEXT = HEAD
    104     4989D5                  ; mov_r13,rdx                 # HEAD = P
    105 
    106     4889C8                  ; mov_rax,rcx                 # put C in place for check
    107     488D1D %string_char     ; lea_rbx,[rip+DWORD] %string_char # Get pointer to "\"'"
    108     E8 %In_Set              ; call %In_Set                # Check for string chars
    109     483D 01000000           ; cmp_rax, %1                 # If string char
    110     0F84 %Store_String      ; je %Store_String            # Get string
    111 
    112     E8 %Store_Atom          ; call %Store_Atom            # Get whole token
    113     EB !restart             ; jmp8 !restart
    114 
    115 :done
    116     5A                      ; pop_rdx                     # Restore RDX
    117     59                      ; pop_rcx                     # Restore RCX
    118     5B                      ; pop_rbx                     # Restore RBX
    119     C3                      ; ret
    120 
    121 
    122 # fgetc function
    123 # Receives FILE* in R15
    124 # Returns -4 (EOF) or char in RAX
    125 :fgetc
    126     48C7C0 FCFFFFFF         ; mov_rax, %-4                # Put EOF in rax
    127     50                      ; push_rax                    # Assume bad (If nothing read, value will remain EOF)ill remain EOF)
    128     488D3424                ; lea_rsi,[rsp]               # Get stack address
    129     4C89FF                  ; mov_rdi,r15                 # Where are we reading from
    130     48C7C0 00000000         ; mov_rax, %0                 # the syscall number for read
    131     52                      ; push_rdx                    # Protect RDX
    132     48C7C2 01000000         ; mov_rdx, %1                 # set the size of chars we want
    133     4153                    ; push_r11                    # Protect r11
    134     0F05                    ; syscall                     # call the Kernel
    135     415B                    ; pop_r11                     # Restore r11
    136     5A                      ; pop_rdx                     # Restore RDX
    137     58                      ; pop_rax                     # Get either char or EOF
    138     C3                      ; ret
    139 
    140 
    141 # Malloc isn't actually required if the program being built fits in the initial memory
    142 # However, it doesn't take much to add it.
    143 # Requires R12 to be initialized and RAX to have the number of desired bytes
    144 :malloc
    145     4C89E7                  ; mov_rdi,r12                 # Using the current pointer
    146     4801C7                  ; add_rdi,rax                 # Request the number of desired bytes
    147     48C7C0 0C000000         ; mov_rax, %12                # the Syscall # for SYS_BRK
    148     51                      ; push_rcx                    # Protect rcx
    149     4153                    ; push_r11                    # Protect r11
    150     0F05                    ; syscall                     # call the Kernel
    151     415B                    ; pop_r11                     # Restore r11
    152     59                      ; pop_rcx                     # Restore rcx
    153     4C89E0                  ; mov_rax,r12                 # Return pointer
    154     4989FC                  ; mov_r12,rdi                 # Update pointer
    155     C3                      ; ret
    156 
    157 
    158 # Purge_LineComment function
    159 # Reads chars until LF and jumps to restart
    160 :Purge_LineComment
    161     E8 %fgetc               ; call %fgetc                 # Get a char
    162     480FB6C0                ; movzx_rax,al                # Zero extend
    163     4883F8 0A               ; cmp_rax, %10                # While not LF
    164     75 !Purge_LineComment   ; jne8 !Purge_LineComment     # Keep reading
    165     E9 %restart             ; jmp %restart
    166 
    167 
    168 # Store_String Function
    169 # Receives C in RCX, HEAD in RDX and Input file in R14
    170 # Uses RBX for terminator, RCX for C and RDX for string
    171 :Store_String
    172     53                      ; push_rbx                    # Protect RBX
    173     51                      ; push_rcx                    # Protect RCX
    174     52                      ; push_rdx                    # Protect RDX
    175 
    176     48C7C0 02000000         ; mov_rax, %2                 # Using TYPE STRING
    177     488942 08               ; mov_[rdx+BYTE],rax !8       # HEAD->TYPE = STRINGE = STRING
    178     48C7C0 00010000         ; mov_rax, %256               # Malloc the string
    179     E8 %malloc              ; call %malloc                # Get pointer to P
    180     488942 10               ; mov_[rdx+BYTE],rax !16      # HEAD->TEXT = STRINGXT = STRING
    181     4889CB                  ; mov_rbx,rcx                 # Protect terminator
    182     4889C2                  ; mov_rdx,rax                 # Protect string pointer
    183 :Store_String_Loop
    184     880A                    ; mov_[rdx],cl                # write byte
    185     E8 %fgetc               ; call %fgetc                 # read next char
    186     480FB6C0                ; movzx_rax,al                # Zero extend it
    187     4889C1                  ; mov_rcx,rax                 # Update C
    188     4883C2 01               ; add_rdx, %1                 # STRING = STRING + 1
    189     4839D9                  ; cmp_rcx,rbx                 # See if we hit terminator
    190     75 !Store_String_Loop   ; jne8 !Store_String_Loop     # Otherwise keep looping
    191 
    192     5A                      ; pop_rdx                     # Restore RDX
    193     59                      ; pop_rcx                     # Restore RCX
    194     5B                      ; pop_rbx                     # Restore RBX
    195     4889D0                  ; mov_rax,rdx                 # return HEAD
    196     E9 %restart             ; jmp %restart
    197 
    198 
    199 # Store_Atom Function
    200 # Receives C in RCX, HEAD in RDX and Input file in R15
    201 # Uses RBX for in_set strings, RCX for C and RDX for string
    202 :Store_Atom
    203     53                      ; push_rbx                    # Protect RBX
    204     51                      ; push_rcx                    # Protect RCX
    205     52                      ; push_rdx                    # Protect RDX
    206 
    207     48C7C0 00010000         ; mov_rax, %256               # Malloc the string
    208     E8 %malloc              ; call %malloc                # Get pointer to P
    209     488942 10               ; mov_[rdx+BYTE],rax !16      # HEAD->TEXT = STRING
    210     488D1D %terminators     ; lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t "
    211     4889C2                  ; mov_rdx,rax                 # Protect string pointer
    212 :Store_Atom_loop
    213     880A                    ; mov_[rdx],cl                # write byte
    214     E8 %fgetc               ; call %fgetc                 # read next char
    215     480FB6C0                ; movzx_rax,al                # Zero extend it
    216     4889C1                  ; mov_rcx,rax                 # Update C
    217     4883C2 01               ; add_rdx, %1                 # STRING = STRING + 1
    218     E8 %In_Set              ; call %In_Set                # Check for terminators
    219     4883F8 00               ; cmp_rax, %0                 # Check for "\n\t "
    220     74 !Store_Atom_loop     ; je8 !Store_Atom_loop        # Loop otherwise
    221 
    222     5A                      ; pop_rdx                     # Restore RDX
    223     59                      ; pop_rcx                     # Restore RCX
    224     5B                      ; pop_rbx                     # Restore RBX
    225     4889D0                  ; mov_rax,rdx                 # return HEAD
    226     C3                      ; ret
    227 
    228 
    229 # In_Set function
    230 # Receives Char C in RAX and CHAR* in RBX
    231 # Returns 1 if true, zero if false in RAX
    232 :In_Set
    233     53                      ; push_rbx                    # Protect RBX
    234     51                      ; push_rcx                    # Protect RCX
    235 :In_Set_loop
    236     8A0B                    ; mov_cl,[rbx]                # Read char
    237     480FB6C9                ; movzx_rcx,cl                # Zero extend it
    238 
    239     4839C8                  ; cmp_rax,rcx                 # See if they match
    240     74 !In_Set_True         ; je8 !In_Set_True            # return true
    241 
    242     4881F9 00000000         ; cmp_rcx, %0                 # Check for NULL
    243     74 !In_Set_False        ; je8 !In_Set_False           # return false
    244 
    245     4881C3 01000000         ; add_rbx, %1                 # s = s + 1
    246     EB !In_Set_loop         ; jmp8 !In_Set_loop           # Keep looping
    247 
    248 :In_Set_True
    249     48C7C0 01000000         ; mov_rax, %1                 # Set True
    250     59                      ; pop_rcx                     # Restore RCX
    251     5B                      ; pop_rbx                     # Restore RBX
    252     C3                      ; ret
    253 
    254 :In_Set_False
    255     48C7C0 00000000         ; mov_rax, %0                 # Set FALSE
    256     59                      ; pop_rcx                     # Restore RCX
    257     5B                      ; pop_rbx                     # Restore RBX
    258     C3                      ; ret
    259 
    260 # Char sets
    261 :terminators
    262     0A 09 20 00             # "\n\t \0"
    263 
    264 :comments
    265     23 3B 00                # "#;\0"
    266 
    267 :string_char
    268     22 27 00                # "\"'\0"
    269 
    270 
    271 # Reverse_List function
    272 # Receives List in RAX
    273 # Returns the list reversed in RAX
    274 :Reverse_List
    275     53                      ; push_rbx                    # Protect RBX
    276     51                      ; push_rcx                    # Protect RCX
    277     4889C3                  ; mov_rbx,rax                 # Set HEAD
    278     48C7C0 00000000         ; mov_rax, %0                 # ROOT = NULL
    279 :Reverse_List_Loop
    280     4883FB 00               ; cmp_rbx, %0                 # WHILE HEAD != NULL
    281     74 !Reverse_List_Done   ; je8 !Reverse_List_Done      # Stop otherwise
    282 
    283     488B0B                  ; mov_rcx,[rbx]               # NEXT = HEAD->NEXT
    284     488903                  ; mov_[rbx],rax               # HEAD->NEXT = ROOT
    285     4889D8                  ; mov_rax,rbx                 # ROOT = HEAD
    286     4889CB                  ; mov_rbx,rcx                 # HEAD = NEXT
    287     EB !Reverse_List_Loop   ; jmp8 !Reverse_List_Loop     # Keep Going
    288 
    289 :Reverse_List_Done
    290     59                      ; pop_rcx                     # Restore RCX
    291     5B                      ; pop_rbx                     # Restore RBX
    292     C3                      ; ret
    293 
    294 
    295 # Identify_Macros function
    296 # Receives List in RAX
    297 # Updates the list in place; does not modify registers
    298 # Uses RBX for DEFINE, RCX for I
    299 :Identify_Macros
    300     50                      ; push_rax                    # Protect RAX
    301     53                      ; push_rbx                    # Protect RBX
    302     51                      ; push_rcx                    # Protect RCX
    303     52                      ; push_rdx                    # Protect RDX
    304     488D1D %DEFINE_str      ; lea_rbx,[rip+DWORD] %DEFINE_str # Setup define string
    305     4889C1                  ; mov_rcx,rax                 # I = HEAD
    306 :Identify_Macros_Loop
    307     488B41 10               ; mov_rax,[rcx+BYTE] !16      # I->TEXT
    308     E8 %match               ; call %match                 # IF "DEFINE" == I->TEXT
    309     4883F8 00               ; cmp_rax, %0                 # Check if match
    310     75 !Identify_Macros_Next ; jne8 !Identify_Macros_Next # Skip the work
    311 
    312     # Deal with MACRO
    313     48C7C0 01000000         ; mov_rax, %1                 # Using MACRO
    314     488941 08               ; mov_[rcx+BYTE],rax !8       # I->TYPE = MACRO
    315 
    316     488B01                  ; mov_rax,[rcx]               # I->NEXT
    317     488B40 10               ; mov_rax,[rax+BYTE] !16      # I->NEXT->TEXT
    318     488941 10               ; mov_[rcx+BYTE],rax !16      # I->TEXT = I->NEXT->TEXT
    319 
    320     488B01                  ; mov_rax,[rcx]               # I->NEXT
    321     488B00                  ; mov_rax,[rax]               # I->NEXT->NEXT
    322     488B40 10               ; mov_rax,[rax+BYTE] !16      # I->NEXT->NEXT->TEXT
    323     488941 18               ; mov_[rcx+BYTE],rax !24      # I->EXPRESSION = I->NEXT->NEXT->TEXT
    324 
    325     488B01                  ; mov_rax,[rcx]               # I->NEXT
    326     488B00                  ; mov_rax,[rax]               # I->NEXT->NEXT
    327     488B00                  ; mov_rax,[rax]               # I->NEXT->NEXT->NEXT
    328     488901                  ; mov_[rcx],rax               # I->NEXT = I->NEXT->NEXT->NEXT
    329 
    330 :Identify_Macros_Next
    331     488B09                  ; mov_rcx,[rcx]               # I = I->NEXT
    332     4883F9 00               ; cmp_rcx, %0                 # Check for NULL
    333     75 !Identify_Macros_Loop ; jne8 !Identify_Macros_Loop # Keep looping otherwise
    334 
    335     5A                      ; pop_rdx                     # Restore RDX
    336     59                      ; pop_rcx                     # Restore RCX
    337     5B                      ; pop_rbx                     # Restore RBX
    338     58                      ; pop_rax                     # Restore RAX
    339     C3                      ; ret
    340 
    341 :DEFINE_str
    342     44 45 46 49 4E 45 00    # "DEFINE"
    343 
    344 
    345 # match function
    346 # Receives CHAR* in RAX and CHAR* in RBX
    347 # Returns 0 (TRUE) or 1 (FALSE) in RAX
    348 :match
    349     53                      ; push_rbx                    # Protect RBX
    350     51                      ; push_rcx                    # Protect RCX
    351     52                      ; push_rdx                    # Protect RDX
    352     4889C1                  ; mov_rcx,rax                 # S1 in place
    353     4889DA                  ; mov_rdx,rbx                 # S2 in place
    354 :match_Loop
    355     8A01                    ; mov_al,[rcx]                # S1[0]
    356     480FB6C0                ; movzx_rax,al                # Make it useful
    357     8A1A                    ; mov_bl,[rdx]                # S2[0]
    358     480FB6DB                ; movzx_rbx,bl                # Make it useful
    359     4839D8                  ; cmp_rax,rbx                 # See if they match
    360     75 !match_False         ; jne8 !match_False           # If not
    361 
    362     4883C1 01               ; add_rcx, %1                 # S1 = S1 + 1
    363     4883C2 01               ; add_rdx, %1                 # S2 = S2 + 1
    364     4883F8 00               ; cmp_rax, %0                 # If reached end of string
    365     74 !match_Done          ; je8 !match_Done             # Perfect match
    366     EB !match_Loop          ; jmp8 !match_Loop            # Otherwise keep looping
    367 
    368 :match_False
    369     48C7C0 01000000         ; mov_rax, %1                 # Return false
    370 :match_Done
    371     5A                      ; pop_rdx                     # Restore RDX
    372     59                      ; pop_rcx                     # Restore RCX
    373     5B                      ; pop_rbx                     # Restore RBX
    374     C3                      ; ret
    375 
    376 
    377 # Line_Macro function
    378 # Receives List in RAX
    379 # Updates the list in place; does not modify registers
    380 # Uses RAX for I, RBX for I->TEXT, RCX for I->EXPRESSION
    381 :Line_Macro
    382     50                      ; push_rax                    # Protect RAX
    383     53                      ; push_rbx                    # Protect RBX
    384     51                      ; push_rcx                    # Protect RCX
    385     52                      ; push_rdx                    # Protect RDX
    386 :Line_Macro_Loop
    387     488B58 08               ; mov_rbx,[rax+BYTE] !8       # I->TYPE
    388     4883FB 01               ; cmp_rbx, %1                 # IF MACRO == I->TYPE
    389     75 !Line_Macro_Next     ; jne8 !Line_Macro_Next       # Otherwise move on
    390 
    391     # Is a macro apply
    392     488B58 10               ; mov_rbx,[rax+BYTE] !16      # I->TEXT
    393     488B48 18               ; mov_rcx,[rax+BYTE] !24      # I->EXPRESSION
    394     488B00                  ; mov_rax,[rax]               # I->NEXT
    395     E8 %Set_Expression      ; call %Set_Expression        # Apply it
    396     EB !Line_Macro_Loop     ; jmp8 !Line_Macro_Loop       # Move on to next
    397 
    398 :Line_Macro_Next
    399     488B00                  ; mov_rax,[rax]               # I->NEXT
    400     4883F8 00               ; cmp_rax, %0                 # Check for NULL
    401     75 !Line_Macro_Loop     ; jne8 !Line_Macro_Loop       # Keep going
    402 
    403     5A                      ; pop_rdx                     # Restore RDX
    404     59                      ; pop_rcx                     # Restore RCX
    405     5B                      ; pop_rbx                     # Restore RBX
    406     58                      ; pop_rax                     # Restore RAX
    407     C3                      ; ret
    408 
    409 
    410 # Set_Expression function
    411 # Receives List in RAX, CHAR* in RBX and CHAR* in RCX
    412 # Updates the list in place; does not modify registers
    413 # Uses RBX for C, RCX for EXP and RDX for I
    414 :Set_Expression
    415     50                      ; push_rax                    # Protect RAX
    416     53                      ; push_rbx                    # Protect RBX
    417     51                      ; push_rcx                    # Protect RCX
    418     52                      ; push_rdx                    # Protect RDX
    419     4889C2                  ; mov_rdx,rax                 # Set I
    420 :Set_Expression_Loop
    421     488B42 08               ; mov_rax,[rdx+BYTE] !8       # I->TYPE
    422     4883F8 01               ; cmp_rax, %1                 # IF MACRO == I->TYPE
    423     74 !Set_Expression_Next ; je8 !Set_Expression_Next    # Ignore and move on
    424 
    425     488B42 10               ; mov_rax,[rdx+BYTE] !16      # I->TEXT
    426     E8 %match               ; call %match                 # Check for match
    427     4883F8 00               ; cmp_rax, %0                 # If match
    428     75 !Set_Expression_Next ; jne8 !Set_Expression_Next   # Otherwise next
    429 
    430     # We have a non-macro match
    431     48894A 18               ; mov_[rdx+BYTE],rcx !24      # I->EXPRESSION = EXP
    432 
    433 :Set_Expression_Next
    434     488B12                  ; mov_rdx,[rdx]               # I = I->NEXT
    435     4883FA 00               ; cmp_rdx, %0                 # IF NULL == I
    436     75 !Set_Expression_Loop ; jne8 !Set_Expression_Loop   # Otherwise keep looping
    437 
    438     5A                      ; pop_rdx                     # Restore RDX
    439     59                      ; pop_rcx                     # Restore RCX
    440     5B                      ; pop_rbx                     # Restore RBX
    441     58                      ; pop_rax                     # Restore RAX
    442     C3                      ; ret
    443 
    444 
    445 # Process_String function
    446 # Receives List in RAX
    447 # Update the list in place; does not modify registers
    448 # Uses RBX for I->TEXT, RCX for I and RDX for S
    449 :Process_String
    450     50                      ; push_rax                    # Protect RAX
    451     53                      ; push_rbx                    # Protect RBX
    452     51                      ; push_rcx                    # Protect RCX
    453     52                      ; push_rdx                    # Protect RDX
    454     4889C1                  ; mov_rcx,rax                 # I = HEAD
    455 :Process_String_loop
    456     488B41 08               ; mov_rax,[rcx+BYTE] !8       # I->TYPE
    457     4883F8 02               ; cmp_rax, %2                 # IF STRING == I->TYPE
    458     75 !Process_String_Next ; jne8 !Process_String_Next   # Skip to next
    459 
    460     488B59 10               ; mov_rbx,[rcx+BYTE] !16      # I->TEXT
    461     8A03                    ; mov_al,[rbx]                # I->TEXT[0]
    462     480FB6C0                ; movzx_rax,al                # make it useful
    463     4883F8 27               ; cmp_rax, %39                # IF '\'' == I->TEXT[0]
    464     75 !Process_String_Raw  ; jne8 !Process_String_Raw    # Deal with '"'
    465 
    466     # Deal with '\''
    467     4883C3 01               ; add_rbx, %1                 # I->TEXT + 1
    468     488959 18               ; mov_[rcx+BYTE],rbx !24      # I->EXPRESSION = I->TEXT + 1
    469     EB !Process_String_Next ; jmp8 !Process_String_Next   # Move on to next
    470 
    471 :Process_String_Raw
    472     4889D8                  ; mov_rax,rbx                 # Get length of I->TEXT
    473     E8 %string_length       ; call %string_length         # Do it
    474     48C1E8 02               ; shr_rax, !2                 # LENGTH = LENGTH >> 2
    475     4883C0 01               ; add_rax, %1                 # LENGTH = LENGTH + 1
    476     48C1E0 03               ; shl_rax, !3                 # LENGTH = LENGTH << 3
    477     E8 %malloc              ; call %malloc                # Get string
    478     4889DA                  ; mov_rdx,rbx                 # S = I->TEXT
    479     4883C2 01               ; add_rdx, %1                 # S = S + 1
    480     488941 18               ; mov_[rcx+BYTE],rax !24      # I->EXPRESSION = hexify
    481     4889C3                  ; mov_rbx,rax                 # Put hexify buffer in rbx
    482 
    483 :Process_String_Raw_Loop
    484     8A02                    ; mov_al,[rdx]                # Read 1 chars
    485     480FB6C0                ; movzx_rax,al                # Make it useful
    486     4883C2 01               ; add_rdx, %1                 # S = S + 1
    487     3C 00                   ; cmp_al, !0                  # Check for NULL
    488     9C                      ; pushf                       # Protect condition
    489     E8 %hex8                ; call %hex8                  # write them all
    490     9D                      ; popf                        # restore condition
    491     75 !Process_String_Raw_Loop ; jne8 !Process_String_Raw_Loop # Keep looping
    492 
    493 :Process_String_Next
    494     488B09                  ; mov_rcx,[rcx]               # I = I->NEXT
    495     4883F9 00               ; cmp_rcx, %0                 # IF NULL == I
    496     75 !Process_String_loop ; jne8 !Process_String_loop   # Otherwise keep looping
    497 
    498     5A                      ; pop_rdx                     # Restore RDX
    499     59                      ; pop_rcx                     # Restore RCX
    500     5B                      ; pop_rbx                     # Restore RBX
    501     58                      ; pop_rax                     # Restore RAX
    502     C3                      ; ret
    503 
    504 
    505 # string_length function
    506 # Receives CHAR* in RAX
    507 # Returns INT in RAX
    508 # Uses RAX for CH, RBX for S and RCX for INDEX
    509 :string_length
    510     53                      ; push_rbx                    # Protect RBX
    511     51                      ; push_rcx                    # Protect RCX
    512     4889C3                  ; mov_rbx,rax                 # Set S
    513     B9 00000000             ; mov_rcx, %0                 # INDEX = 0
    514 :string_length_loop
    515     8A040B                  ; mov_al,[rbx+rcx]            # S[0]
    516     480FB6C0                ; movzx_rax,al                # make it useful
    517     4883F8 00               ; cmp_rax, %0                 # IF NULL == S[0]
    518     74 !string_length_done  ; je8 !string_length_done     # Stop
    519 
    520     4883C1 01               ; add_rcx, %1                 # INDEX = INDEX + 1
    521     EB !string_length_loop  ; jmp8 !string_length_loop    # Keep going
    522 
    523 :string_length_done
    524     4889C8                  ; mov_rax,rcx                 # RETURN INDEX
    525     59                      ; pop_rcx                     # Restore RCX
    526     5B                      ; pop_rbx                     # Restore RBX
    527     C3                      ; ret
    528 
    529 
    530 # Eval_Immediates function
    531 # Receives List in RAX
    532 # Updates the list in place; does not modify registers
    533 # Uses RBX for I->TEXT[0], RCX for I->TEXT[1] and RDX for I
    534 :Eval_Immediates
    535     50                      ; push_rax                    # Protect RAX
    536     53                      ; push_rbx                    # Protect RBX
    537     51                      ; push_rcx                    # Protect RCX
    538     52                      ; push_rdx                    # Protect RDX
    539     4889C2                  ; mov_rdx,rax                 # I = HEAD
    540 :Eval_Immediates_Loop
    541     # Check for MACRO
    542     488B42 08               ; mov_rax,[rdx+BYTE] !8       # I->TYPE
    543     4883F8 01               ; cmp_rax, %1                 # IF MACRO == I->TYPE
    544     74 !Eval_Immediates_Next ; je8 !Eval_Immediates_Next  # Skip to next
    545 
    546     # Check for NULL EXPRESSION
    547     488B42 18               ; mov_rax,[rdx+BYTE] !24      # I->EXPRESSION
    548     4883F8 00               ; cmp_rax, %0                 # IF NULL == I->EXPRESSION
    549     75 !Eval_Immediates_Next ; jne8 !Eval_Immediates_Next # Skip to next
    550 
    551     # Check if number
    552     488B42 10               ; mov_rax,[rdx+BYTE] !16      # I->TEXT
    553     8A18                    ; mov_bl,[rax]                # I->TEXT[0]
    554     480FB6DB                ; movzx_rbx,bl                # Extend to use
    555     4883C0 01               ; add_rax, %1                 # I->TEXT + 1
    556     8A08                    ; mov_cl,[rax]                # I->TEXT[1]
    557     480FB6C9                ; movzx_rcx,cl                # Extend to use
    558     E8 %numerate_string     ; call %numerate_string       # Convert string to INT
    559     4883F8 00               ; cmp_rax, %0                 # IF 0 == numerate_string(I->TEXT + 1)
    560     75 !Eval_Immediates_value ; jne8 !Eval_Immediates_value # Has a value
    561 
    562     # Last chance for Immediate
    563     4883F9 30               ; cmp_rcx, %48                # If '0' == I->TEXT[1]
    564     75 !Eval_Immediates_Next ; jne8 !Eval_Immediates_Next # Skip to next
    565 
    566 :Eval_Immediates_value
    567     E8 %express_number      ; call %express_number        # Convert value to hex string
    568     488942 18               ; mov_[rdx+BYTE],rax !24      # I->EXPRESSION = express_number(value, I-TEXT[0])
    569 
    570 :Eval_Immediates_Next
    571     488B12                  ; mov_rdx,[rdx]               # I = I->NEXT
    572     4883FA 00               ; cmp_rdx, %0                 # IF NULL == I
    573     75 !Eval_Immediates_Loop ; jne8 !Eval_Immediates_Loop # Otherwise keep looping
    574 
    575     5A                      ; pop_rdx                     # Restore RDX
    576     59                      ; pop_rcx                     # Restore RCX
    577     5B                      ; pop_rbx                     # Restore RBX
    578     58                      ; pop_rax                     # Restore RAX
    579     C3                      ; ret
    580 
    581 
    582 # numerate_string function
    583 # Receives CHAR* in RAX
    584 # Returns value of CHAR* in RAX
    585 # Only supports negative decimals and Uppercase Hex (eg 5, -3 and 0xCC)
    586 # Uses RAX for VALUE, RBX for S, RCX for CH and RSI for NEGATIVE?
    587 :numerate_string
    588     53                      ; push_rbx                    # Protect RBX
    589     51                      ; push_rcx                    # Protect RCX
    590     52                      ; push_rdx                    # Protect RDX
    591     56                      ; push_rsi                    # Protect RSI
    592     4889C3                  ; mov_rbx,rax                 # put S in correct place
    593     48C7C0 00000000         ; mov_rax, %0                 # Initialize to Zero
    594 :numerate_string_loop
    595     8A4B 01                 ; mov_cl,[rbx+BYTE] !1        # S[1]
    596     480FB6C9                ; movzx_rcx,cl                # make it useful
    597     4883F9 78               ; cmp_rcx, %120               # IF 'x' == S[1]
    598     74 !numerate_hex        ; je8 !numerate_hex           # Deal with hex input
    599 
    600     # Assume decimal input
    601     48C7C6 00000000         ; mov_rsi, %0                 # Assume no negation
    602     8A0B                    ; mov_cl,[rbx]                # S[0]
    603     480FB6C9                ; movzx_rcx,cl                # make it useful
    604     4883F9 2D               ; cmp_rcx, %45                # IF '-' == S[0]
    605     75 !numerate_decimal    ; jne8 !numerate_decimal      # Skip negation
    606 
    607     48C7C6 01000000         ; mov_rsi, %1                 # Set FLAG
    608     4883C3 01               ; add_rbx, %1                 # S = S + 1
    609 
    610 :numerate_decimal
    611     8A0B                    ; mov_cl,[rbx]                # S[0]
    612     480FB6C9                ; movzx_rcx,cl                # make it useful
    613     4883F9 00               ; cmp_rcx, %0                 # IF NULL == S[0]
    614     74 !numerate_decimal_done ; je8 !numerate_decimal_done # We are done
    615 
    616     486BC0 0A               ; imul_rax, !10               # VALUE = VALUE * 10
    617     4883E9 30               ; sub_rcx, !48                # CH = CH - '0'
    618     4883F9 09               ; cmp_rcx, %9                 # Check for illegal
    619     7F !numerate_string_fail ; jg8 !numerate_string_fail  # If CH > '9'
    620     4883F9 00               ; cmp_rcx, %0                 # Check for illegal
    621     7C !numerate_string_fail ; jl8 !numerate_string_fail  # IF CH < 0
    622     4801C8                  ; add_rax,rcx                 # VALUE = VALUE + CH
    623     4883C3 01               ; add_rbx, %1                 # S = S + 1
    624     EB !numerate_decimal    ; jmp8 !numerate_decimal      # Keep looping
    625 
    626 :numerate_decimal_done
    627     4883FE 01               ; cmp_rsi, %1                 # Check if need to negate
    628     75 !numerate_string_done ; jne8 !numerate_string_done # Nope
    629 
    630     486BC0 FF               ; imul_rax, !-1               # VALUE = VALUE * -1
    631     EB !numerate_string_done ; jmp8 !numerate_string_done # Done
    632 
    633 :numerate_hex
    634     4883C3 02               ; add_rbx, %2                 # S = S + 2
    635 :numerate_hex_loop
    636     8A0B                    ; mov_cl,[rbx]                # S[0]
    637     480FB6C9                ; movzx_rcx,cl                # make it useful
    638     4883F9 00               ; cmp_rcx, %0                 # IF NULL == S[0]
    639     0F84 %numerate_string_done ; je8 !numerate_string_done # We are done
    640 
    641     48C1E0 04               ; shl_rax, !4                 # VALUE = VALUE << 4
    642     4883E9 30               ; sub_rcx, !48                # CH = CH - '0'
    643     4883F9 0A               ; cmp_rcx, %10                # IF 10 >= CH
    644     7C !numerate_hex_digit  ; jl8 !numerate_hex_digit     # NO
    645     4883E9 07               ; sub_rcx, !7                 # Push A-F into range
    646 :numerate_hex_digit
    647     4883F9 0F               ; cmp_rcx, %15                # Check for illegal
    648     7F !numerate_string_fail ; jg8 !numerate_string_fail  # If CH > 'F'
    649     4883F9 00               ; cmp_rcx, %0                 # Check for illegal
    650     7C !numerate_string_fail ; jl8 !numerate_string_fail  # IF CH < 0
    651     4801C8                  ; add_rax,rcx                 # VALUE = VALUE + CH
    652     4883C3 01               ; add_rbx, %1                 # S = S + 1
    653     EB !numerate_hex_loop   ; jmp8 !numerate_hex_loop     # Keep looping
    654 
    655 :numerate_string_fail
    656     48C7C0 00000000         ; mov_rax, %0                 # return ZERO
    657 
    658 :numerate_string_done
    659     5E                      ; pop_rsi                     # Restore RSI
    660     5A                      ; pop_rdx                     # Restore RDX
    661     59                      ; pop_rcx                     # Restore RCX
    662     5B                      ; pop_rbx                     # Restore RBX
    663     C3                      ; ret
    664 
    665 
    666 # express_number function
    667 # Receives INT in RAX and CHAR in RBX
    668 # Allocates a string and expresses the value in hex
    669 # Returns string in RAX
    670 # Uses RAX for VALUE, RBX for S and RCX for CH
    671 :express_number
    672     53                      ; push_rbx                    # Protect RBX
    673     51                      ; push_rcx                    # Protect RCX
    674     52                      ; push_rdx                    # Protect RDX
    675     4889D9                  ; mov_rcx,rbx                 # Put CH in right place
    676     4889C3                  ; mov_rbx,rax                 # Protect VALUE
    677     4883F9 25               ; cmp_rcx, %37                # IF '%' == CH
    678     75 !express_number2     ; jne8 !express_number2       # Otherwise try @
    679 
    680     48C7C0 09000000         ; mov_rax, %9                 # We need 9 bytes
    681     E8 %malloc              ; call %malloc                # Get S pointer
    682     4893                    ; xchg_rax,rbx                # Put S and VALUE in place
    683     53                      ; push_rbx                    # Protect S
    684     E8 %hex32l              ; call %hex32l                # Store 32bits
    685     EB !express_number_done ; jmp8 !express_number_done   # done
    686 
    687 :express_number2
    688     4883F9 40               ; cmp_rcx, %64                # IF '@' == CH
    689     75 !express_number1     ; jne8 !express_number1       # Othrewise try !
    690 
    691     48C7C0 05000000         ; mov_rax, %5                 # We need 5 bytes
    692     E8 %malloc              ; call %malloc                # Get S pointer
    693     4893                    ; xchg_rax,rbx                # Put S and VALUE in place
    694     53                      ; push_rbx                    # Protect S
    695     E8 %hex16l              ; call %hex16l                # Store 16bits
    696     EB !express_number_done ; jmp8 !express_number_done   # done
    697 
    698 :express_number1
    699     48C7C0 03000000         ; mov_rax, %3                 # We need 3 bytes
    700     E8 %malloc              ; call %malloc                # Get S pointer
    701     4893                    ; xchg_rax,rbx                # Put S and VALUE in place
    702     53                      ; push_rbx                    # Protect S
    703     E8 %hex8                ; call %hex8                  # Store 8bit
    704 
    705 :express_number_done
    706     58                      ; pop_rax                     # Restore S
    707     5A                      ; pop_rdx                     # Restore RDX
    708     59                      ; pop_rcx                     # Restore RCX
    709     5B                      ; pop_rbx                     # Restore RBX
    710     C3                      ; ret
    711 
    712 
    713 # HEX to ascii routine
    714 # Receives INT in RAX and CHAR* in RBX
    715 # Stores ascii of INT in CHAR*
    716 # Returns only modifying RAX
    717 :hex64l
    718     50                      ; push_rax                    # Protect top 32
    719     E8 %hex32l              ; call %hex32l                # Store it
    720     58                      ; pop_rax                     # do top 32
    721     48C1E8 20               ; shr_rax, !32                # do bottom 32 first
    722 :hex32l
    723     50                      ; push_rax                    # Protect top 16
    724     E8 %hex16l              ; call %hex16l                # Store it
    725     58                      ; pop_rax                     # do top 16
    726     48C1E8 10               ; shr_rax, !16                # do bottom 16 first
    727 :hex16l
    728     50                      ; push_rax                    # Protect top byte
    729     E8 %hex8                ; call %hex8                  # Store it
    730     58                      ; pop_rax                     # do high byte
    731     48C1E8 08               ; shr_rax, !8                 # do bottom byte first
    732 :hex8
    733     50                      ; push_rax                    # Protect bottom nibble
    734     48C1E8 04               ; shr_rax, !4                 # do high nibble first
    735     E8 %hex4                ; call %hex4                  # Store it
    736     58                      ; pop_rax                     # do low nibble
    737 :hex4
    738     4883E0 0F               ; and_rax, !0xF               # isolate nibble
    739     04 30                   ; add_al, !0x30               # convert to ascii (add '0')
    740     3C 39                   ; cmp_al, !0x39               # valid digit? (compare to '9')
    741     76 !hex1                ; jbe8 !hex1                  # yes
    742     04 07                   ; add_al, !7                  # use alpha range
    743 :hex1
    744     8803                    ; mov_[ebx],al                # store result
    745     4883C3 01               ; add_ebx, !1                 # next position
    746     C3                      ; ret
    747 
    748 
    749 # Preserve_Other function
    750 # Receives List in RAX
    751 # Updates the list in place; does not modify registers
    752 # Uses RAX for I, RBX for I->TEXT
    753 :Preserve_Other
    754     50                      ; push_rax                    # Protect RAX
    755     53                      ; push_rbx                    # Protect RBX
    756     51                      ; push_rcx                    # Protect RCX
    757     52                      ; push_rdx                    # Protect RDX
    758 :Preserve_Other_Loop
    759     488B58 18               ; mov_rbx,[rax+BYTE] !24      # I->EXPRESSION
    760     4883FB 00               ; cmp_rbx, %0                 # IF NULL == I->EXPRESSION
    761     75 !Preserve_Other_Next ; jne8 !Preserve_Other_Next   # Otherwise next
    762 
    763     # Needs preserving
    764     488B58 10               ; mov_rbx,[rax+BYTE] !16      # I->TEXT
    765     488958 18               ; mov_[rax+BYTE],rbx !24      # I->EXPRESSION = I->TEXT
    766 
    767 :Preserve_Other_Next
    768     488B00                  ; mov_rax,[rax]               # I = I->NEXT
    769     4883F8 00               ; cmp_rax, %0                 # IF NULL == I
    770     75 !Preserve_Other_Loop ; jne8 !Preserve_Other_Loop   # Otherwise keep looping
    771 
    772     5A                      ; pop_rdx                     # Restore RDX
    773     59                      ; pop_rcx                     # Restore RCX
    774     5B                      ; pop_rbx                     # Restore RBX
    775     58                      ; pop_rax                     # Restore RAX
    776     C3                      ; ret
    777 
    778 
    779 # Print_Hex function
    780 # Receives list in RAX
    781 # walks the list and prints the I->EXPRESSION for all nodes followed by newline
    782 # Uses RBX for I
    783 :Print_Hex
    784     53                      ; push_rbx                    # Protect RBX
    785     4C89EB                  ; mov_rbx,r13                 # I = Head
    786 :Print_Hex_Loop
    787     488B43 08               ; mov_rax,[rbx+BYTE] !8       # I->TYPE
    788     4883F8 01               ; cmp_rax, %1                 # IF MACRO == I->TYPE
    789     74 !Print_Hex_Next      ; je8 !Print_Hex_Next         # Skip
    790 
    791     488B43 18               ; mov_rax,[rbx+BYTE] !24      # Using EXPRESSION
    792     E8 %File_Print          ; call %File_Print            # Print it
    793     48C7C0 0A000000         ; mov_rax, %10                # NEWLINE
    794     E8 %fputc               ; call %fputc                 # Append it
    795 
    796 :Print_Hex_Next
    797     488B1B                  ; mov_rbx,[rbx]               # Iterate to next Token
    798     4883FB 00               ; cmp_rbx, %0                 # Check for NULL
    799     75 !Print_Hex_Loop      ; jne8 !Print_Hex_Loop        # Otherwise keep looping
    800 
    801     5B                      ; pop_rbx                     # Restore RBX
    802     C3                      ; ret
    803 
    804 
    805 # File_Print function
    806 # Receives CHAR* in RAX
    807 # calls fputc for every non-null char
    808 :File_Print
    809     53                      ; push_rbx                    # Protect RBX
    810     4889C3                  ; mov_rbx,rax                 # Protect S
    811     4883F8 00               ; cmp_rax, %0                 # Protect against nulls
    812     74 !File_Print_Done     ; je8 !File_Print_Done        # Simply don't try to print them
    813 :File_Print_Loop
    814     8A03                    ; mov_al,[rbx]                # Read byte
    815     480FB6C0                ; movzx_rax,al                # zero extend
    816     4883F8 00               ; cmp_rax, %0                 # Check for NULL
    817     74 !File_Print_Done     ; je8 !File_Print_Done        # Stop at NULL
    818 
    819     E8 %fputc               ; call %fputc                 # write it
    820     4883C3 01               ; add_rbx, %1                 # S = S + 1
    821     EB !File_Print_Loop     ; jmp8 !File_Print_Loop       # Keep going
    822 
    823 :File_Print_Done
    824     5B                      ; pop_rbx                     # Restore RBX
    825     C3                      ; ret
    826 
    827 
    828 # fputc function
    829 # receives CHAR in RAX and FILE* in R14
    830 # writes char and returns
    831 :fputc
    832     50                      ; push_rax                    # We are writing rax
    833     488D3424                ; lea_rsi,[rsp]               # Get stack address
    834     4C89F7                  ; mov_rdi,r14                 # Write to target file
    835     48C7C0 01000000         ; mov_rax, %1                 # the syscall number for write
    836     52                      ; push_rdx                    # Protect RDX
    837     48C7C2 01000000         ; mov_rdx, %1                 # set the size of chars we want
    838     4153                    ; push_r11                    # Protect HEAD
    839     0F05                    ; syscall                     # call the Kernel
    840     415B                    ; pop_r11                     # Restore HEAD
    841     5A                      ; pop_rdx                     # Restore RDX
    842     58                      ; pop_rax                     # Restore stack
    843     C3                      ; ret
    844 
    845 :ELF_end