## Copyright (C) 2017 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 ADDI32_to_R13 4981C5 DEFINE ADDI32_to_RAX 4805 DEFINE ADD_R14_to_RAX 4C01F0 DEFINE ADD_RAX_R14 4C01F0 DEFINE CALLI32 E8 DEFINE CMPI32_R15 4981FF DEFINE CMPI32_RAX 483D DEFINE CMP_R15_Immediate8 4983FF DEFINE CMP_RAX_Immediate8 4883F8 DEFINE COPY_R9_to_RDI 4C89CF DEFINE COPY_R10_to_RDI 4C89D7 DEFINE COPY_RAX_to_R14 4989C6 DEFINE COPY_RAX_to_R9 4989C1 DEFINE COPY_RAX_to_R10 4989C2 DEFINE JE32 0F84 DEFINE JE8 74 DEFINE JGE8 7D DEFINE JL32 0F8C DEFINE JL8 7C DEFINE JMP32 E9 DEFINE JMP8 EB DEFINE JNE32 0F85 DEFINE JNE8 75 DEFINE LOAD32_Address_in_RAX_into_RAX 678B00 DEFINE LOAD8_al_Absolute32 8A0425 DEFINE LOADI32_R13 49C7C5 DEFINE LOADI32_R14 49C7C6 DEFINE LOADI32_R15 49C7C7 DEFINE LOADI32_RAX 48C7C0 DEFINE LOADI32_RDI 48C7C7 DEFINE LOADI32_RDX 48C7C2 DEFINE LOADI32_RSI 48C7C6 DEFINE MOVE_R14_RAX 4989C6 DEFINE MOVZBQ_RAX_AL 480FB6C0 DEFINE NOT_R15 49F7D7 DEFINE NULL 00000000 DEFINE POP_RAX 58 DEFINE POP_RDI 5F DEFINE RET C3 DEFINE RETQ C3 DEFINE SHL8_R14 49C1E6 DEFINE SHL8_RAX 48C1E0 DEFINE SHL_R14_Immediate8 49C1E6 DEFINE STORE32_R13_to_Address_in_RAX 4C8928 DEFINE STORE32_RAX_Absolute32 890425 DEFINE STORE8_al_Absolute32 880425 DEFINE SUBI8_from_RAX 4883E8 DEFINE SUB_R13_from_RAX 4C29E8 DEFINE SUB_RAX_Immediate8 4883E8 DEFINE SYSCALL 0F05 DEFINE TEST_RAX_RAX 4885C0 # 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_R9 # 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 %448 # Prepare file as RWX for owner only (700 in octal) LOADI32_RAX %2 #·the·syscall·number·for·open() SYSCALL # Now open that damn file COPY_RAX_to_R10 # Preserve the file pointer we were given LOADI32_R15 %-1 # Our flag for byte processing LOADI32_R14 %0 # temp storage for the sum LOADI32_R13 %0 # Our starting IP CALLI32 %First_pass # Process it # rewind input file COPY_R9_to_RDI # Using our input file LOADI32_RSI %0 # Offset Zero LOADI32_RDX %0 # Whence Zero LOADI32_RAX %8 # lseek SYSCALL LOADI32_R15 %-1 # Our flag for byte processing LOADI32_R14 %0 # temp storage for the sum LOADI32_R13 %0 # Our starting IP CALLI32 %Second_pass # Process it JMP32 %Done :First_pass CALLI32 %Read_byte # Deal with EOF CMPI32_RAX %-4 JE32 %First_pass_done # Check for : CMPI32_RAX %0x3a JNE32 %First_pass_0 # Deal with label CALLI32 %StoreLabel :First_pass_0 # Check for % CMPI32_RAX %0x25 JE32 %First_pass_pointer # Deal with everything else CALLI32 %hex # Process our char # Deal with EOF CMPI32_RAX %-4 JE32 %First_pass_done # deal with -1 values CMPI32_RAX %0 JL32 %First_pass # deal with toggle CMPI32_R15 %0 JE32 %First_pass_1 ADDI32_to_R13 %1 # Increment IP :First_pass_1 NOT_R15 JMP32 %First_pass :First_pass_pointer # Deal with Pointer to label CALLI32 %Read_byte # Drop the char ADDI32_to_R13 %4 # Increment IP JMP32 %First_pass # Loop again :First_pass_done RET :hex # deal with EOF CMPI32_RAX %-4 JE32 %EOF # deal with line comments starting with # CMPI32_RAX %0x23 JE32 %ascii_comment # deal with line comments starting with ; CMPI32_RAX %0x3b JE32 %ascii_comment # deal all ascii less than 0 CMPI32_RAX %0x30 JL32 %ascii_other # deal with 0-9 CMPI32_RAX %0x3a JL32 %ascii_num # deal with all ascii less than A CMPI32_RAX %0x41 JL32 %ascii_other # deal with A-F CMPI32_RAX %0x47 JL32 %ascii_high #deal with all ascii less than a CMPI32_RAX %0x61 JL32 %ascii_other #deal with a-f CMPI32_RAX %0x67 JL32 %ascii_low # The rest that remains needs to be ignored JMP32 %ascii_other :Second_pass CALLI32 %Read_byte # Deal with EOF CMPI32_RAX %-4 JE32 %Second_pass_done # Simply drop the label CMPI32_RAX %0x3a JNE32 %Second_pass_0 CALLI32 %Read_byte JMP32 %Second_pass :Second_pass_0 # Deal with % pointer CMPI32_RAX %0x25 JNE32 %Second_pass_1 CALLI32 %StorePointer JMP32 %Second_pass :Second_pass_1 # Deal with everything else CALLI32 %hex # Process our char # Deal with EOF CMPI32_RAX %-4 JE32 %Second_pass_done # deal with -1 values CMPI32_RAX %0 JL32 %Second_pass # deal with toggle CMPI32_R15 %0 JE32 %print # process first byte of pair COPY_RAX_to_R14 LOADI32_R15 %0 JMP32 %Second_pass :Second_pass_done RET :EOF RET :ascii_num SUBI8_from_RAX !0x30 RET :ascii_low SUBI8_from_RAX !0x57 RET :ascii_high SUBI8_from_RAX !0x37 RET :ascii_other LOADI32_RAX %-1 RET :ascii_comment CALLI32 %Read_byte CMPI32_RAX %0xd JE32 %ascii_comment_cr CMPI32_RAX %0xa JNE32 %ascii_comment :ascii_comment_cr LOADI32_RAX %-1 RET # process second byte of pair :print # update the sum and store in output SHL8_R14 !4 ADD_R14_to_RAX STORE8_al_Absolute32 &table # flip the toggle NOT_R15 # Print our first Hex LOADI32_RDX %1 # set the size of chars we want CALLI32 %print_chars ADDI32_to_R13 %1 # Increment IP JMP32 %Second_pass :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 :Read_byte # Attempt to read 1 byte from STDIN LOADI32_RDX %1 # set the size of chars we want LOADI32_RSI &table # Where to put it COPY_R9_to_RDI # Where are we reading from LOADI32_RAX %0 # the syscall number for read SYSCALL # call the Kernel TEST_RAX_RAX # check what we got JE32 %Read_byte_1 # Got EOF call it done # load byte LOAD8_al_Absolute32 &table # load char MOVZBQ_RAX_AL # We have to zero extend it to use it RET # Deal with EOF :Read_byte_1 LOADI32_RAX %-4 # Put EOF in rax RET :print_chars LOADI32_RSI &table # What we are writing COPY_R10_to_RDI # Write to target file LOADI32_RAX %1 # the syscall number for write SYSCALL # call the Kernel RET :Get_table_target CALLI32 %Read_byte # Get single char label SHL8_RAX !3 # Each label in table takes 8 bytes to store ADDI32_to_RAX &table # Calculate offset RET :StoreLabel CALLI32 %Get_table_target STORE32_R13_to_Address_in_RAX # Write out pointer to table RET :StorePointer ADDI32_to_R13 %4 # Increment IP CALLI32 %Get_table_target # Get address of pointer LOAD32_Address_in_RAX_into_RAX # Get pointer SUB_R13_from_RAX # target - ip STORE32_RAX_Absolute32 &table # put value in output LOADI32_RDX %4 # set the size of chars we want CALLI32 %print_chars RET :ELF_end :table