### Copyright (C) 2019 Jeremiah Orians ### This file is part of stage0. ### ### stage0 is free software: you can redistribute it and/or modify ### it under the terms of the GNU General Public License as published by ### the Free Software Foundation, either version 3 of the License, or ### (at your option) any later version. ### ### stage0 is distributed in the hope that it will be useful, ### but WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ### GNU General Public License for more details. ### ### You should have received a copy of the GNU General Public License ### along with stage0. If not, see . DEFINE ADDI8_to_AL 04 DEFINE ADDI8_to_RAX 4883C0 DEFINE ADDI8_to_RBX 4883C3 DEFINE ADDI8_to_RCX 4883C1 DEFINE ADDI8_to_RDX 4883C2 DEFINE ADD_RAX_to_RDI 4801C7 DEFINE ADD_RCX_to_RAX 4801C8 DEFINE AND_RAX_Immediate8 4883E0 DEFINE CALLI32 E8 DEFINE CMP_AL_Immediate8 3C DEFINE CMP_RAX_Immediate8 4883F8 DEFINE CMP_RBX_Immediate8 4883FB DEFINE CMP_RCX_Immediate8 4883F9 DEFINE CMP_RDX_Immediate8 4883FA DEFINE CMP_RSI_Immediate8 4883FE DEFINE CMP_RBX_to_RAX 4839D8 DEFINE CMP_RBX_to_RCX 4839D9 DEFINE CMP_RCX_to_RAX 4839C8 DEFINE COPY_R12_to_RAX 4C89E0 DEFINE COPY_R12_to_RDI 4C89E7 DEFINE COPY_R13_to_RAX 4C89E8 DEFINE COPY_R13_to_RBX 4C89EB DEFINE COPY_R14_to_RDI 4C89F7 DEFINE COPY_R15_to_RDI 4C89FF DEFINE COPY_RAX_to_R12 4989C4 DEFINE COPY_RAX_to_R13 4989C5 DEFINE COPY_RAX_to_R14 4989C6 DEFINE COPY_RAX_to_R15 4989C7 DEFINE COPY_RAX_to_RBX 4889C3 DEFINE COPY_RAX_to_RCX 4889C1 DEFINE COPY_RAX_to_RDX 4889C2 DEFINE COPY_RBX_to_RAX 4889D8 DEFINE COPY_RBX_to_RCX 4889D9 DEFINE COPY_RBX_to_RDX 4889DA DEFINE COPY_RCX_to_RAX 4889C8 DEFINE COPY_RCX_to_RBX 4889CB DEFINE COPY_RDI_to_R12 4989FC DEFINE COPY_RDX_to_R13 4989D5 DEFINE COPY_RDX_to_RAX 4889D0 DEFINE IMUL_RAX_Immediate8 486BC0 DEFINE JBE8 76 DEFINE JE32 0F84 DEFINE JG32 0F8F DEFINE JL32 0F8C DEFINE JMP32 E9 DEFINE JNE32 0F85 DEFINE LEA_RSI 488D3424 DEFINE LOAD8_AL_from_Address_RBX 8A03 DEFINE LOAD8_AL_from_Address_RBX_Index_RCX 8A040B DEFINE LOAD8_AL_from_Address_RCX 8A01 DEFINE LOAD8_AL_from_Address_RDX 8A02 DEFINE LOAD8_BL_from_Address_RAX 8A18 DEFINE LOAD8_BL_from_Address_RDX 8A1A DEFINE LOAD8_CL_from_Address_RAX 8A08 DEFINE LOAD8_CL_from_Address_RBX 8A0B DEFINE LOAD8_CL_from_Address_RBX_Immediate8 8A4B DEFINE LOAD64_into_RAX_from_Address_RAX 488B00 DEFINE LOAD64_into_RAX_from_Address_RCX 488B01 DEFINE LOAD64_into_RAX_from_Address_RAX_Immediate8 488B40 DEFINE LOAD64_into_RAX_from_Address_RBX_Immediate8 488B43 DEFINE LOAD64_into_RAX_from_Address_RCX_Immediate8 488B41 DEFINE LOAD64_into_RAX_from_Address_RDX_Immediate8 488B42 DEFINE LOAD64_into_RBX_from_Address_RAX_Immediate8 488B58 DEFINE LOAD64_into_RBX_from_Address_RBX 488B1B DEFINE LOAD64_into_RBX_from_Address_RCX_Immediate8 488B59 DEFINE LOAD64_into_RCX_from_Address_RAX_Immediate8 488B48 DEFINE LOAD64_into_RCX_from_Address_RBX 488B0B DEFINE LOAD64_into_RCX_from_Address_RCX 488B09 DEFINE LOAD64_into_RDX_from_Address_RDX 488B12 DEFINE LOADI32_RAX 48C7C0 DEFINE LOADI32_RBX BB DEFINE LOADI32_RCX B9 DEFINE LOADI32_RDI BF DEFINE LOADI32_RDX BA DEFINE LOADI32_RSI BE DEFINE POP_FLAGS 9D DEFINE POP_R11 415B DEFINE POP_RAX 58 DEFINE POP_RBX 5B DEFINE POP_RCX 59 DEFINE POP_RDX 5A DEFINE POP_RDI 5F DEFINE POP_RSI 5E DEFINE PUSH_FLAGS 9C DEFINE PUSH_R11 4153 DEFINE PUSH_RAX 50 DEFINE PUSH_RBX 53 DEFINE PUSH_RCX 51 DEFINE PUSH_RDX 52 DEFINE PUSH_RSI 56 DEFINE RET C3 DEFINE SHIFT_LEFT_RAX_Immediate8 48C1E0 DEFINE SHIFT_RIGHT_RAX_Immediate8 48C1E8 DEFINE STORE64_R13_into_Address_RDX 4C892A DEFINE STORE64_RAX_into_Address_RBX 488903 DEFINE STORE64_RAX_into_Address_RCX 488901 DEFINE STORE64_RAX_into_Address_RCX_Immediate8 488941 DEFINE STORE64_RAX_into_Address_RDX_Immediate8 488942 DEFINE STORE64_RBX_into_Address_RAX_Immediate8 488958 DEFINE STORE64_RBX_into_Address_RCX_Immediate8 488959 DEFINE STORE64_RCX_into_Address_RDX_Immediate8 48894A DEFINE STORE8_AL_into_Address_RBX 8803 DEFINE STORE8_CL_into_Address_RDX 880A DEFINE SUBI8_RCX 4883E9 DEFINE SWAP_RAX_RBX 4893 DEFINE SYSCALL 0F05 DEFINE ZERO_EXTEND_AL 480FB6C0 DEFINE ZERO_EXTEND_BL 480FB6DB DEFINE ZERO_EXTEND_CL 480FB6C9 ;; Register usage: ;; RAX, RSI, RDI => Temps ;; R12 => MALLOC ;; R13 => HEAD ;; R14 => Output_file ;; R15 => Input_file ;; Struct format: (size 32) ;; NEXT => 0 ;; TYPE => 8 ;; TEXT => 16 ;; EXPRESSION => 24 ;; Types ;; None => 0 ;; MACRO => 1 ;; STRING => 2 ; Where the ELF Header is going to hit ; Simply jump to _start ; Our main function :_start POP_RAX ;·Get·the·number·of·arguments POP_RDI ;·Get·the·program·name POP_RDI ;·Get·the·actual·input name LOADI32_RSI %0 ;·prepare·read_only LOADI32_RAX %2 ;·the·syscall·number·for·open() SYSCALL ; Now open that damn file COPY_RAX_to_R15 ; Preserve the file pointer we were given POP_RDI ;·Get·the·actual·output name LOADI32_RSI %577 ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC LOADI32_RDX %384 ; Prepare file as RW for owner only (600 in octal) LOADI32_RAX %2 ;·the·syscall·number·for·open() SYSCALL ; Now open that damn file CMP_RAX_Immediate8 !0 ; Check for missing output JG32 %_start_out ; Have real input LOADI32_RAX %1 ; Use stdout :_start_out COPY_RAX_to_R14 ; Preserve the file pointer we were given LOADI32_RAX %0xC ; the Syscall # for SYS_BRK LOADI32_RDI %0 ; Get current brk SYSCALL ; Let the kernel do the work COPY_RAX_to_R12 ; Set our malloc pointer CALLI32 %Tokenize_Line ; Get all lines COPY_R13_to_RAX ; prepare for Reverse_List CALLI32 %Reverse_List ; Correct order COPY_RAX_to_R13 ; Update HEAD CALLI32 %Identify_Macros ; Find the DEFINEs CALLI32 %Line_Macro ; Apply the DEFINEs CALLI32 %Process_String ; Handle strings CALLI32 %Eval_Immediates ; Handle Numbers CALLI32 %Preserve_Other ; Collect the remaining CALLI32 %Print_Hex ; Output our results :Done ; program completed Successfully LOADI32_RDI %0 ; All is well LOADI32_RAX %0x3C ; put the exit syscall number in eax SYSCALL ; Call it a good day ;; Tokenize_Line Function ;; Using input file R15 and Head R13 ;; Creates a linked list of structs ;; Uses RBX for in_set strings, RCX for Int C and RDX for Struct Token* p :Tokenize_Line PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX :restart CALLI32 %fgetc ; Read a char CMP_RAX_Immediate8 !-4 ; Check for EOF JE32 %done ; File is collected ZERO_EXTEND_AL ; We have to zero extend it to use it COPY_RAX_to_RCX ; Protect C LOADI32_RBX &comments ; Get pointer to "#;" CALLI32 %In_Set ; Check for comments CMP_RAX_Immediate8 !1 ; If comments JE32 %Purge_LineComment ; try again COPY_RCX_to_RAX ; put C in place for check LOADI32_RBX &terminators ; Get pointer to "\n\t " CALLI32 %In_Set ; Check for terminators CMP_RAX_Immediate8 !1 ; If terminator JE32 %restart ; try again LOADI32_RAX %32 ; Malloc the struct P CALLI32 %malloc ; Get pointer to P COPY_RAX_to_RDX ; Protect P STORE64_R13_into_Address_RDX ; P->NEXT = HEAD COPY_RDX_to_R13 ; HEAD = P COPY_RCX_to_RAX ; put C in place for check LOADI32_RBX &string_char ; Get pointer to "\"'" CALLI32 %In_Set ; Check for string chars CMP_RAX_Immediate8 !1 ; If string char JE32 %Store_String ; Get string CALLI32 %Store_Atom ; Get whole token JMP32 %restart :done POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; fgetc function ;; Receives FILE* in R15 ;; Returns -4 (EOF) or char in RAX :fgetc LOADI32_RAX %-4 ; Put EOF in rax PUSH_RAX ; Assume bad (If nothing read, value will remain EOF) LEA_RSI ; Get stack address COPY_R15_to_RDI ; Where are we reading from LOADI32_RAX %0 ; the syscall number for read PUSH_RDX ; Protect RDX LOADI32_RDX %1 ; set the size of chars we want PUSH_R11 ; Protect r11 SYSCALL ; call the Kernel POP_R11 ; Restore r11 POP_RDX ; Restore RDX POP_RAX ; Get either char or EOF RET ;; Malloc isn't actually required if the program being built fits in the initial memory ;; However, it doesn't take much to add it. ;; Requires R12 to be initialized and RAX to have the number of desired bytes :malloc COPY_R12_to_RDI ; Using the current pointer ADD_RAX_to_RDI ; Request the number of desired bytes LOADI32_RAX %0xC ; the Syscall # for SYS_BRK PUSH_RCX ; Protect rcx PUSH_R11 ; Protect r11 SYSCALL ; call the Kernel POP_R11 ; Restore r11 POP_RCX ; Restore rcx COPY_R12_to_RAX ; Return pointer COPY_RDI_to_R12 ; Update pointer RET ;; Purge_LineComment function ;; Reads chars until LF and jumps to restart :Purge_LineComment CALLI32 %fgetc ; Get a char ZERO_EXTEND_AL ; Zero extend CMP_RAX_Immediate8 !10 ; While not LF JNE32 %Purge_LineComment ; Keep reading JMP32 %restart ;; Store_String Function ;; Receives C in RCX, HEAD in RDX and Input file in R14 ;; Uses RBX for terminator, RCX for C and RDX for string :Store_String PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX LOADI32_RAX %2 ; Using TYPE STRING STORE64_RAX_into_Address_RDX_Immediate8 !8 ; HEAD->TYPE = STRING LOADI32_RAX %256 ; Malloc the string CALLI32 %malloc ; Get pointer to P STORE64_RAX_into_Address_RDX_Immediate8 !16 ; HEAD->TEXT = STRING COPY_RCX_to_RBX ; Protect terminator COPY_RAX_to_RDX ; Protect string pointer :Store_String_Loop STORE8_CL_into_Address_RDX ; write byte CALLI32 %fgetc ; read next char ZERO_EXTEND_AL ; Zero extend it COPY_RAX_to_RCX ; Update C ADDI8_to_RDX !1 ; STRING = STRING + 1 CMP_RBX_to_RCX ; See if we hit terminator JNE32 %Store_String_Loop ; Otherwise keep looping POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX COPY_RDX_to_RAX ; return HEAD JMP32 %restart ;; Store_Atom Function ;; Receives C in RCX, HEAD in RDX and Input file in R15 ;; Uses RBX for in_set strings, RCX for C and RDX for string :Store_Atom PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX LOADI32_RAX %256 ; Malloc the string CALLI32 %malloc ; Get pointer to P STORE64_RAX_into_Address_RDX_Immediate8 !16 ; HEAD->TEXT = STRING LOADI32_RBX &terminators ; Get pointer to "\n\t " COPY_RAX_to_RDX ; Protect string pointer :Store_Atom_loop STORE8_CL_into_Address_RDX ; write byte CALLI32 %fgetc ; read next char ZERO_EXTEND_AL ; Zero extend it COPY_RAX_to_RCX ; Update C ADDI8_to_RDX !1 ; STRING = STRING + 1 CALLI32 %In_Set ; Check for terminators CMP_RAX_Immediate8 !0 ; Check for "\n\t " JE32 %Store_Atom_loop ; Loop otherwise POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX COPY_RDX_to_RAX ; return HEAD RET ;; In_Set function ;; Receives Char C in RAX and CHAR* in RBX ;; Returns 1 if true, zero if false in RAX :In_Set PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX :In_Set_loop LOAD8_CL_from_Address_RBX ; Read char ZERO_EXTEND_CL ; Zero extend it CMP_RCX_to_RAX ; See if they match JE32 %In_Set_True ; return true CMP_RCX_Immediate8 !0 ; Check for NULL JE32 %In_Set_False ; return false ADDI8_to_RBX !1 ; s = s + 1 JMP32 %In_Set_loop ; Keep looping :In_Set_True LOADI32_RAX %1 ; Set True POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET :In_Set_False LOADI32_RAX %0 ; Set FALSE POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; Char sets :terminators " " :comments "#;" :string_char '22 27 00' ;; Reverse_List function ;; Receives List in RAX ;; Returns the list reversed in RAX :Reverse_List PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX COPY_RAX_to_RBX ; Set HEAD LOADI32_RAX %0 ; ROOT = NULL :Reverse_List_Loop CMP_RBX_Immediate8 !0 ; WHILE HEAD != NULL JE32 %Reverse_List_Done ; Stop otherwise LOAD64_into_RCX_from_Address_RBX ; NEXT = HEAD->NEXT STORE64_RAX_into_Address_RBX ; HEAD->NEXT = ROOT COPY_RBX_to_RAX ; ROOT = HEAD COPY_RCX_to_RBX ; HEAD = NEXT JMP32 %Reverse_List_Loop ; Keep Going :Reverse_List_Done POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; Identify_Macros function ;; Receives List in RAX ;; Updates the list in place; does not modify registers ;; Uses RBX for DEFINE, RCX for I :Identify_Macros PUSH_RAX ; Protect RAX PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX LOADI32_RBX &DEFINE_str ; Setup define string COPY_RAX_to_RCX ; I = HEAD :Identify_Macros_Loop LOAD64_into_RAX_from_Address_RCX_Immediate8 !16 ; I->TEXT CALLI32 %match ; IF "DEFINE" == I->TEXT CMP_RAX_Immediate8 !0 ; Check if match JNE32 %Identify_Macros_Next ; Skip the work ;; Deal with MACRO LOADI32_RAX %1 ; Using MACRO STORE64_RAX_into_Address_RCX_Immediate8 !8 ; I->TYPE = MACRO LOAD64_into_RAX_from_Address_RCX ; I->NEXT LOAD64_into_RAX_from_Address_RAX_Immediate8 !16 ; I->NEXT->TEXT STORE64_RAX_into_Address_RCX_Immediate8 !16 ; I->TEXT = I->NEXT->TEXT LOAD64_into_RAX_from_Address_RCX ; I->NEXT LOAD64_into_RAX_from_Address_RAX ; I->NEXT->NEXT LOAD64_into_RAX_from_Address_RAX_Immediate8 !16 ; I->NEXT->NEXT->TEXT STORE64_RAX_into_Address_RCX_Immediate8 !24 ; I->EXPRESSION = I->NEXT->NEXT->TEXT LOAD64_into_RAX_from_Address_RCX ; I->NEXT LOAD64_into_RAX_from_Address_RAX ; I->NEXT->NEXT LOAD64_into_RAX_from_Address_RAX ; I->NEXT->NEXT->NEXT STORE64_RAX_into_Address_RCX ; I->NEXT = I->NEXT->NEXT->NEXT :Identify_Macros_Next LOAD64_into_RCX_from_Address_RCX ; I = I->NEXT CMP_RCX_Immediate8 !0 ; Check for NULL JNE32 %Identify_Macros_Loop ; Keep looping otherwise POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX POP_RAX ; Restore RAX RET :DEFINE_str "DEFINE" ;; match function ;; Receives CHAR* in RAX and CHAR* in RBX ;; Returns 0 (TRUE) or 1 (FALSE) in RAX :match PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX COPY_RAX_to_RCX ; S1 in place COPY_RBX_to_RDX ; S2 in place :match_Loop LOAD8_AL_from_Address_RCX ; S1[0] ZERO_EXTEND_AL ; Make it useful LOAD8_BL_from_Address_RDX ; S2[0] ZERO_EXTEND_BL ; Make it useful CMP_RBX_to_RAX ; See if they match JNE32 %match_False ; If not ADDI8_to_RCX !1 ; S1 = S1 + 1 ADDI8_to_RDX !1 ; S2 = S2 + 1 CMP_RAX_Immediate8 !0 ; If reached end of string JE32 %match_Done ; Perfect match JMP32 %match_Loop ; Otherwise keep looping :match_False LOADI32_RAX %1 ; Return false :match_Done POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; Line_Macro function ;; Receives List in RAX ;; Updates the list in place; does not modify registers ;; Uses RAX for I, RBX for I->TEXT, RCX for I->EXPRESSION :Line_Macro PUSH_RAX ; Protect RAX PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX :Line_Macro_Loop LOAD64_into_RBX_from_Address_RAX_Immediate8 !8 ; I->TYPE CMP_RBX_Immediate8 !1 ; IF MACRO == I->TYPE JNE32 %Line_Macro_Next ; Otherwise move on ;; Is a macro apply LOAD64_into_RBX_from_Address_RAX_Immediate8 !16 ; I->TEXT LOAD64_into_RCX_from_Address_RAX_Immediate8 !24 ; I->EXPRESSION LOAD64_into_RAX_from_Address_RAX ; I->NEXT CALLI32 %Set_Expression ; Apply it JMP32 %Line_Macro_Loop ; Move on to next :Line_Macro_Next LOAD64_into_RAX_from_Address_RAX ; I->NEXT CMP_RAX_Immediate8 !0 ; Check for NULL JNE32 %Line_Macro_Loop ; Keep going POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX POP_RAX ; Restore RAX RET ;; Set_Expression function ;; Receives List in RAX, CHAR* in RBX and CHAR* in RCX ;; Updates the list in place; does not modify registers ;; Uses RBX for C, RCX for EXP and RDX for I :Set_Expression PUSH_RAX ; Protect RAX PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX COPY_RAX_to_RDX ; Set I :Set_Expression_Loop LOAD64_into_RAX_from_Address_RDX_Immediate8 !8 ; I->TYPE CMP_RAX_Immediate8 !1 ; IF MACRO == I->TYPE JE32 %Set_Expression_Next ; Ignore and move on LOAD64_into_RAX_from_Address_RDX_Immediate8 !16 ; I->TEXT CALLI32 %match ; Check for match CMP_RAX_Immediate8 !0 ; If match JNE32 %Set_Expression_Next ; Otherwise next ;; We have a non-macro match STORE64_RCX_into_Address_RDX_Immediate8 !24 ; I->EXPRESSION = EXP :Set_Expression_Next LOAD64_into_RDX_from_Address_RDX ; I = I->NEXT CMP_RDX_Immediate8 !0 ; IF NULL == I JNE32 %Set_Expression_Loop ; Otherwise keep looping POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX POP_RAX ; Restore RAX RET ;; Process_String function ;; Receives List in RAX ;; Update the list in place; does not modify registers ;; Uses RBX for I->TEXT, RCX for I and RDX for S :Process_String PUSH_RAX ; Protect RAX PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX COPY_RAX_to_RCX ; I = HEAD :Process_String_loop LOAD64_into_RAX_from_Address_RCX_Immediate8 !8 ; I->TYPE CMP_RAX_Immediate8 !2 ; IF STRING == I->TYPE JNE32 %Process_String_Next ; Skip to next LOAD64_into_RBX_from_Address_RCX_Immediate8 !16 ; I->TEXT LOAD8_AL_from_Address_RBX ; I->TEXT[0] ZERO_EXTEND_AL ; make it useful CMP_RAX_Immediate8 !39 ; IF '\'' == I->TEXT[0] JNE32 %Process_String_Raw ; Deal with "\"" ;; Deal with '\'' ADDI8_to_RBX !1 ; I->TEXT + 1 STORE64_RBX_into_Address_RCX_Immediate8 !24 ; I->EXPRESSION = I->TEXT + 1 JMP32 %Process_String_Next ; Move on to next :Process_String_Raw COPY_RBX_to_RAX ; Get length of I->TEXT CALLI32 %string_length ; Do it SHIFT_RIGHT_RAX_Immediate8 !2 ; LENGTH = LENGTH >> 2 ADDI8_to_RAX !1 ; LENGTH = LENGTH + 1 SHIFT_LEFT_RAX_Immediate8 !3 ; LENGTH = LENGTH << 3 CALLI32 %malloc ; Get string COPY_RBX_to_RDX ; S = I->TEXT ADDI8_to_RDX !1 ; S = S + 1 STORE64_RAX_into_Address_RCX_Immediate8 !24 ; I->EXPRESSION = hexify COPY_RAX_to_RBX ; Put hexify buffer in rbx :Process_String_Raw_Loop LOAD8_AL_from_Address_RDX ; Read 1 chars ZERO_EXTEND_AL ; Make it useful ADDI8_to_RDX !1 ; S = S + 1 CMP_AL_Immediate8 !0 ; Check for NULL PUSH_FLAGS ; Protect condition CALLI32 %hex8 ; write them all POP_FLAGS ; restore condition JNE32 %Process_String_Raw_Loop ; Keep looping :Process_String_Next LOAD64_into_RCX_from_Address_RCX ; I = I->NEXT CMP_RCX_Immediate8 !0 ; IF NULL == I JNE32 %Process_String_loop ; Otherwise keep looping POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX POP_RAX ; Restore RAX RET ;; string_length function ;; Receives CHAR* in RAX ;; Returns INT in RAX ;; Uses RAX for CH, RBX for S and RCX for INDEX :string_length PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX COPY_RAX_to_RBX ; Set S LOADI32_RCX %0 ; INDEX = 0 :string_length_loop LOAD8_AL_from_Address_RBX_Index_RCX ; S[0] ZERO_EXTEND_AL ; make it useful CMP_RAX_Immediate8 !0 ; IF NULL == S[0] JE32 %string_length_done ; Stop ADDI8_to_RCX !1 ; INDEX = INDEX + 1 JMP32 %string_length_loop ; Keep going :string_length_done COPY_RCX_to_RAX ; RETURN INDEX POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; Eval_Immediates function ;; Receives List in RAX ;; Updates the list in place; does not modify registers ;; Uses RBX for I->TEXT[0], RCX for I->TEXT[1] and RDX for I :Eval_Immediates PUSH_RAX ; Protect RAX PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX COPY_RAX_to_RDX ; I = HEAD :Eval_Immediates_Loop ;; Check for MACRO LOAD64_into_RAX_from_Address_RDX_Immediate8 !8 ; I->TYPE CMP_RAX_Immediate8 !1 ; IF MACRO == I-TYPE JE32 %Eval_Immediates_Next ; Skip to next ;; Check for NULL EXPRESSION LOAD64_into_RAX_from_Address_RDX_Immediate8 !24 ; I->EXPRESSION CMP_RAX_Immediate8 !0 ; IF NULL == I->EXPRESSION JNE32 %Eval_Immediates_Next ; Skip to next ;; Check if number LOAD64_into_RAX_from_Address_RDX_Immediate8 !16 ; I->TEXT LOAD8_BL_from_Address_RAX ; I->TEXT[0] ZERO_EXTEND_BL ; Extend to use ADDI8_to_RAX !1 ; I->TEXT + 1 LOAD8_CL_from_Address_RAX ; I->TEXT[1] ZERO_EXTEND_CL ; Extend to use CALLI32 %numerate_string ; Convert string to INT CMP_RAX_Immediate8 !0 ; IF 0 == numerate_number(I->TEXT + 1) JNE32 %Eval_Immediates_value ; Has a value ;; Last chance for Immediate CMP_RCX_Immediate8 !48 ; If '0' == I->TEXT[1] JNE32 %Eval_Immediates_Next ; Skip to next :Eval_Immediates_value CALLI32 %express_number ; Convert value to hex string STORE64_RAX_into_Address_RDX_Immediate8 !24 ; I->EXPRESSION = express_number(value, I-TEXT[0]) :Eval_Immediates_Next LOAD64_into_RDX_from_Address_RDX ; I = I->NEXT CMP_RDX_Immediate8 !0 ; IF NULL == I JNE32 %Eval_Immediates_Loop ; Otherwise keep looping POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX POP_RAX ; Restore RAX RET ;; numerate_string function ;; Receives CHAR* in RAX ;; Returns value of CHAR* in RAX ;; Only supports negative decimals and Uppercase Hex (eg 5, -3 and 0xCC) ;; Uses RAX for VALUE, RBX for S, RCX for CH and RSI for NEGATIVE? :numerate_string PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX PUSH_RSI ; Protect RSI COPY_RAX_to_RBX ; put S in correct place LOADI32_RAX %0 ; Initialize to Zero :numerate_string_loop LOAD8_CL_from_Address_RBX_Immediate8 !1 ; S[1] ZERO_EXTEND_CL ; make it useful CMP_RCX_Immediate8 !120 ; IF 'x' == S[1] JE32 %numerate_hex ; Deal with hex input ;; Assume decimal input LOADI32_RSI %0 ; Assume no negation LOAD8_CL_from_Address_RBX ; S[0] ZERO_EXTEND_CL ; make it useful CMP_RCX_Immediate8 !45 ; IF '-' == S[0] JNE32 %numerate_decimal ; Skip negation LOADI32_RSI %1 ; Set FLAG ADDI8_to_RBX !1 ; S = S + 1 :numerate_decimal LOAD8_CL_from_Address_RBX ; S[0] ZERO_EXTEND_CL ; make it useful CMP_RCX_Immediate8 !0 ; IF NULL == S[0] JE32 %numerate_decimal_done ; We are done IMUL_RAX_Immediate8 !10 ; VALUE = VALUE * 10 SUBI8_RCX !48 ; CH = CH - '0' CMP_RCX_Immediate8 !9 ; Check for illegal JG32 %numerate_string_fail ; If CH > '9' CMP_RCX_Immediate8 !0 ; Check for illegal JL32 %numerate_string_fail ; IF CH < 0 ADD_RCX_to_RAX ; VALUE = VALUE + CH ADDI8_to_RBX !1 ; S = S + 1 JMP32 %numerate_decimal ; Keep looping :numerate_decimal_done CMP_RSI_Immediate8 !1 ; Check if need to negate JNE32 %numerate_string_done ; Nope IMUL_RAX_Immediate8 !-1 ; VALUE = VALUE * -1 JMP32 %numerate_string_done ; Done :numerate_hex ADDI8_to_RBX !2 ; S = S + 2 :numerate_hex_loop LOAD8_CL_from_Address_RBX ; S[0] ZERO_EXTEND_CL ; make it useful CMP_RCX_Immediate8 !0 ; IF NULL == S[0] JE32 %numerate_string_done ; We are done SHIFT_LEFT_RAX_Immediate8 !4 ; VALUE = VALUE << 4 SUBI8_RCX !48 ; CH = CH - '0' CMP_RCX_Immediate8 !10 ; IF 10 >= CH JL32 %numerate_hex_digit ; NO SUBI8_RCX !7 ; Push A-F into range :numerate_hex_digit CMP_RCX_Immediate8 !15 ; Check for illegal JG32 %numerate_string_fail ; If CH > 'F' CMP_RCX_Immediate8 !0 ; Check for illegal JL32 %numerate_string_fail ; IF CH < 0 ADD_RCX_to_RAX ; VALUE = VALUE + CH ADDI8_to_RBX !1 ; S = S + 1 JMP32 %numerate_hex_loop ; Keep looping :numerate_string_fail LOADI32_RAX %0 ; return ZERO :numerate_string_done POP_RSI ; Restore RSI POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; express_number function ;; Receives INT in RAX and CHAR in RBX ;; Allocates a string and expresses the value in hex ;; Returns string in RAX ;; Uses RAX for VALUE, RBX for S and RCX for CH :express_number PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX COPY_RBX_to_RCX ; Put CH in right place COPY_RAX_to_RBX ; Protect VALUE CMP_RCX_Immediate8 !37 ; IF '%' == CH JNE32 %express_number2 ; Otherwise try @ LOADI32_RAX %9 ; We need 3bytes CALLI32 %malloc ; Get S pointer SWAP_RAX_RBX ; Put S and VALUE in place PUSH_RBX ; Protect S CALLI32 %hex32l ; Store 32bits JMP32 %express_number_done ; done :express_number2 CMP_RCX_Immediate8 !64 ; IF '@' == CH JNE32 %express_number1 ; Othrewise try ! LOADI32_RAX %5 ; We need 3bytes CALLI32 %malloc ; Get S pointer SWAP_RAX_RBX ; Put S and VALUE in place PUSH_RBX ; Protect S CALLI32 %hex16l ; Store 16bits JMP32 %express_number_done ; done :express_number1 LOADI32_RAX %3 ; We need 3bytes CALLI32 %malloc ; Get S pointer SWAP_RAX_RBX ; Put S and VALUE in place PUSH_RBX ; Protect S CALLI32 %hex8 ; Store 8bit :express_number_done POP_RAX ; Restore S POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; HEX to ascii routine ;; Receives INT in RAX and CHAR* in RBX ;; Stores ascii of INT in CHAR* ;; Returns only modifying RAX :hex64l PUSH_RAX ; Protect top 32 CALLI32 %hex32l ; Store it POP_RAX ; do top 32 SHIFT_RIGHT_RAX_Immediate8 !32 ; do bottom 32 first :hex32l PUSH_RAX ; Protect top 16 CALLI32 %hex16l ; Store it POP_RAX ; do top 16 SHIFT_RIGHT_RAX_Immediate8 !16 ; do bottom 16 first :hex16l PUSH_RAX ; Protect top byte CALLI32 %hex8 ; Store it POP_RAX ; do high byte SHIFT_RIGHT_RAX_Immediate8 !8 ; do bottom byte first :hex8 PUSH_RAX ; Protect bottom nibble SHIFT_RIGHT_RAX_Immediate8 !4 ; do high nibble first CALLI32 %hex4 ; Store it POP_RAX ; do low nibble :hex4 AND_RAX_Immediate8 !0xF ; isolate nibble ADDI8_to_AL !48 ; convert to ascii CMP_AL_Immediate8 !57 ; valid digit? JBE8 !hex1 ; yes ADDI8_to_AL !7 ; use alpha range :hex1 STORE8_AL_into_Address_RBX ; store result ADDI8_to_RBX !1 ; next position RET ;; Preserve_Other function ;; Receives List in RAX ;; Updates the list in place; does not modify registers ;; Uses RAX for I, RBX for I->TEXT :Preserve_Other PUSH_RAX ; Protect RAX PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX PUSH_RDX ; Protect RDX :Preserve_Other_Loop LOAD64_into_RBX_from_Address_RAX_Immediate8 !24 ; I->EXPRESSION CMP_RBX_Immediate8 !0 ; IF NULL == I->EXPRESSION JNE32 %Preserve_Other_Next ; Otherwise next ;; Needs preserving LOAD64_into_RBX_from_Address_RAX_Immediate8 !16 ; I->TEXT STORE64_RBX_into_Address_RAX_Immediate8 !24 ; I->EXPRESSION = I->TEXT :Preserve_Other_Next LOAD64_into_RAX_from_Address_RAX ; I = I->NEXT CMP_RAX_Immediate8 !0 ; IF NULL == I JNE32 %Preserve_Other_Loop ; Otherwise keep looping POP_RDX ; Restore RDX POP_RCX ; Restore RCX POP_RBX ; Restore RBX POP_RAX ; Restore RAX RET ;; Print_Hex function ;; Receives list in RAX ;; walks the list and prints the I->EXPRESSION for all nodes followed by newline ;; Uses RBX for I :Print_Hex PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX COPY_R13_to_RBX ; I = Head :Print_Hex_Loop LOAD64_into_RAX_from_Address_RBX_Immediate8 !8 ; I->TYPE CMP_RAX_Immediate8 !1 ; IF MACRO == I->TYPE JE32 %Print_Hex_Next ; Skip LOAD64_into_RAX_from_Address_RBX_Immediate8 !24 ; Using EXPRESSION CALLI32 %File_Print ; Print it LOADI32_RAX %10 ; NEWLINE CALLI32 %fputc ; Append it :Print_Hex_Next LOAD64_into_RBX_from_Address_RBX ; Iterate to next Token CMP_RBX_Immediate8 !0 ; Check for NULL JNE32 %Print_Hex_Loop ; Otherwise keep looping POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; File_Print function ;; Receives CHAR* in RAX ;; calls fputc for every non-null char :File_Print PUSH_RBX ; Protect RBX PUSH_RCX ; Protect RCX COPY_RAX_to_RBX ; Protect S CMP_RAX_Immediate8 !0 ; Protect against nulls JE32 %File_Print_Done ; Simply don't try to print them :File_Print_Loop LOAD8_AL_from_Address_RBX ; Read byte ZERO_EXTEND_AL ; zero extend CMP_RAX_Immediate8 !0 ; Check for NULL JE32 %File_Print_Done ; Stop at NULL CALLI32 %fputc ; write it ADDI8_to_RBX !1 ; S = S + 1 JMP32 %File_Print_Loop ; Keep going :File_Print_Done POP_RCX ; Restore RCX POP_RBX ; Restore RBX RET ;; fputc function ;; receives CHAR in RAX and FILE* in R14 ;; writes char and returns :fputc PUSH_RAX ; We are writing rax LEA_RSI ; Get stack address COPY_R14_to_RDI ; Write to target file LOADI32_RAX %1 ; the syscall number for write PUSH_RDX ; Protect RDX LOADI32_RDX %1 ; set the size of chars we want PUSH_R11 ; Protect HEAD SYSCALL ; call the Kernel POP_R11 ; Restore HEAD POP_RDX ; Restore RDX POP_RAX ; Restore stack RET :ELF_end