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