;; 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 ADD_EDI_to_EAX 01F8 DEFINE CALL E8 DEFINE CMPI8_EAX 83F8 DEFINE CMPI8_EBP 83FD DEFINE COPY_EAX_to_EDI 89C7 DEFINE INT_80 CD80 DEFINE JE8 74 DEFINE JGE8 7D DEFINE JL8 7C DEFINE JMP8 EB DEFINE JNE8 75 DEFINE LOAD32_Absolute32_ebx 8B1D DEFINE LOAD8_Absolute32_al A0 DEFINE LOADI32_EAX B8 DEFINE LOADI32_EBP BD DEFINE LOADI32_EBX BB DEFINE LOADI32_ECX B9 DEFINE LOADI32_EDI BF DEFINE LOADI32_EDX BA DEFINE MOVZX 0FB6C0 DEFINE NULL 00000000 DEFINE POP_EAX 58 DEFINE POP_EBX 5B DEFINE RET C3 DEFINE SHLI8_EDI C1E7 DEFINE STORE32_Absolute32_eax A3 DEFINE STORE8_Absolute32_al A2 DEFINE SUBI8_EAX 83E8 DEFINE TEST 85C0 ; Where the ELF Header is going to hit ; Simply jump to _start ; Our main function :_start POP_EAX ;·Get·the·number·of·arguments POP_EBX ;·Get·the·program·name POP_EBX ;·Get·the·actual·input name LOADI32_ECX %0 ;·prepare·read_only LOADI32_EDX %0 ; Extra sure LOADI32_EAX %5 ;·the·syscall·number·for·open() INT_80 ; Now open that damn file STORE32_Absolute32_eax &fin ; Preserve the file pointer we were given POP_EBX ;·Get·the·actual·output name LOADI32_ECX %577 ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC LOADI32_EDX %448 ; Prepare file as RWX for owner only (700 in octal) LOADI32_EAX %5 ;·the·syscall·number·for·open() INT_80 ; Now open that damn file STORE32_Absolute32_eax &fout ; Preserve the file pointer we were given ; Our flag for byte processing LOADI32_EBP %-1 ; temp storage for the sum LOADI32_EDI %0 :loop ; Read a byte CALL %Read_byte ; process byte CALL %hex ; Deal with -1 values CMPI8_EAX !0 JL8 !loop ; deal with toggle CMPI8_EBP !0 JGE8 !print ; process first byte of pair COPY_EAX_to_EDI LOADI32_EBP %0 JMP8 !loop ; process second byte of pair :print ; update the sum and store in output SHLI8_EDI !4 ADD_EDI_to_EAX STORE8_Absolute32_al &output ; flip the toggle LOADI32_EBP %-1 CALL %write_byte JMP8 !loop :hex ; Purge Comment Lines (#) CMPI8_EAX !35 JE8 !purge_comment ; Purge Comment Lines (;) CMPI8_EAX !59 JE8 !purge_comment ; deal all ascii less than 0 CMPI8_EAX !48 JL8 !ascii_other ; deal with 0-9 CMPI8_EAX !58 JL8 !ascii_num ; deal with all ascii less than A CMPI8_EAX !65 JL8 !ascii_other ; deal with A-F CMPI8_EAX !71 JL8 !ascii_high ;deal with all ascii less than a CMPI8_EAX !97 JL8 !ascii_other ;deal with a-f CMPI8_EAX !103 JL8 !ascii_low ; The rest that remains needs to be ignored JMP8 !ascii_other :purge_comment ; Read a byte CALL %Read_byte ; Loop if not LF CMPI8_EAX !10 JNE8 !purge_comment ; Otherwise return -1 LOADI32_EAX %-1 RET :ascii_num SUBI8_EAX !48 RET :ascii_low SUBI8_EAX !87 RET :ascii_high SUBI8_EAX !55 RET :ascii_other LOADI32_EAX %-1 RET :Done ; program completed Successfully LOADI32_EBX %0 ; All is well LOADI32_EAX %1 ; put the exit syscall number in eax INT_80 ; Call it a good day :write_byte ; Print our Hex LOADI32_EDX %1 ; set the size of chars we want LOADI32_ECX &output ; What we are writing LOAD32_Absolute32_ebx &fout ; Where are we writing to LOADI32_EAX %4 ; the syscall number for write INT_80 ; call the Kernel RET :Read_byte ; Attempt to read 1 byte from STDIN LOADI32_EDX %1 ; set the size of chars we want LOADI32_ECX &input ; Where to put it LOAD32_Absolute32_ebx &fin ; Where are we reading from LOADI32_EAX %3 ; the syscall number for read INT_80 ; call the Kernel TEST ; check what we got JE8 !Done ; Got EOF call it done ; load byte LOAD8_Absolute32_al &input ; load char MOVZX ; We have to zero extend it to use it RET :fin NULL :fout NULL :output NULL :input NULL :ELF_end