;; 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_EAX 05 DEFINE ADDI8_EDI 83C7 DEFINE ADD_ESI_to_EAX 01F0 DEFINE CALLI32 E8 DEFINE CMPI8_EAX 83F8 DEFINE CMPI8_EBP 83FD DEFINE COPY_EAX_to_ESI 89C6 DEFINE INT_80 CD80 DEFINE JE32 0F84 DEFINE JL32 0F8C DEFINE JMP32 E9 DEFINE JNE32 0F85 DEFINE LOAD32_Absolute32_ebx 8B1D DEFINE LOAD32_Address_EAX_into_EAX 8B00 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 LOADI32_ESI BE DEFINE MOVZX 0FB6C0 DEFINE NOT_EBP F7D5 DEFINE NULL 00000000 DEFINE POP_EAX 58 DEFINE POP_EBX 5B DEFINE RET C3 DEFINE SHLI8_EAX C1E0 DEFINE SHLI8_ESI C1E6 DEFINE STORE32_Absolute32_eax A3 DEFINE STORE32_EDI_into_Address_EAX 8938 DEFINE STORE8_Absolute32_al A2 DEFINE SUBI8_EAX 83E8 DEFINE SUB_EDI_from_EAX 29F8 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 LOADI32_EBP %-1 ; Our flag for byte processing LOADI32_ESI %0 ; temp storage for the sum LOADI32_EDI %0 ; Our starting IP CALLI32 %First_pass ; Process it ; rewind input file LOAD32_Absolute32_ebx &fin ; Using our input file LOADI32_ECX %0 ; Offset Zero LOADI32_EDX %0 ; Whence Zero LOADI32_EAX %19 ; lseek INT_80 LOADI32_EBP %-1 ; Our flag for byte processing LOADI32_ESI %0 ; temp storage for the sum LOADI32_EDI %0 ; Our starting IP CALLI32 %Second_pass ; Process it JMP32 %Done :First_pass CALLI32 %Read_byte ; Deal with EOF CMPI8_EAX !-4 JE32 %First_pass_done ; Check for : CMPI8_EAX !58 JNE32 %First_pass_0 ; Deal with label CALLI32 %StoreLabel :First_pass_0 ; Check for : CMPI8_EAX !37 JE32 %First_pass_pointer ; Deal with everything else CALLI32 %hex ; Process our char ; Deal with EOF CMPI8_EAX !-4 JE32 %First_pass_done ; deal with -1 values CMPI8_EAX !0 JL32 %First_pass ; deal with toggle CMPI8_EBP !0 JE32 %First_pass_1 ADDI8_EDI !1 ; Increment IP :First_pass_1 NOT_EBP JMP32 %First_pass :First_pass_pointer ; Deal with Pointer to label CALLI32 %Read_byte ; Drop the char ADDI8_EDI !4 ; Increment IP JMP32 %First_pass ; Loop again :First_pass_done RET :hex ; deal with EOF CMPI8_EAX !-4 JE32 %EOF ; deal with line comments starting with ; CMPI8_EAX !35 JE32 %ascii_comment ; deal with line comments starting with ; CMPI8_EAX !59 JE32 %ascii_comment ; deal all ascii less than 0 CMPI8_EAX !48 JL32 %ascii_other ; deal with 0-9 CMPI8_EAX !58 JL32 %ascii_num ; deal with all ascii less than A CMPI8_EAX !65 JL32 %ascii_other ; deal with A-F CMPI8_EAX !71 JL32 %ascii_high ;deal with all ascii less than a CMPI8_EAX !97 JL32 %ascii_other ;deal with a-f CMPI8_EAX !103 JL32 %ascii_low ; The rest that remains needs to be ignored JMP32 %ascii_other :Second_pass CALLI32 %Read_byte ; Deal with EOF CMPI8_EAX !-4 JE32 %Second_pass_done ; Simply drop the label CMPI8_EAX !58 JNE32 %Second_pass_0 CALLI32 %Read_byte JMP32 %Second_pass :Second_pass_0 ; Deal with pointer CMPI8_EAX !37 JNE32 %Second_pass_1 CALLI32 %StorePointer JMP32 %Second_pass :Second_pass_1 ; Deal with everything else CALLI32 %hex ; Process our char ; Deal with EOF CMPI8_EAX !-4 JE32 %Second_pass_done ; deal with -1 values CMPI8_EAX !0 JL32 %Second_pass ; deal with toggle CMPI8_EBP !0 JE32 %print ; process first byte of pair COPY_EAX_to_ESI LOADI32_EBP %0 JMP32 %Second_pass :Second_pass_done RET :EOF 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 :ascii_comment CALLI32 %Read_byte CMPI8_EAX !13 JE32 %ascii_comment_cr CMPI8_EAX !10 JNE32 %ascii_comment :ascii_comment_cr LOADI32_EAX %-1 RET ; process second byte of pair :print ; update the sum and store in output SHLI8_ESI !4 ADD_ESI_to_EAX STORE8_Absolute32_al &table ; flip the toggle NOT_EBP ; Print our first Hex LOADI32_EDX %1 ; set the size of chars we want CALLI32 %print_chars ADDI8_EDI !1 ; Increment IP JMP32 %Second_pass :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 :Read_byte ; Attempt to read 1 byte from STDIN LOADI32_EDX %1 ; set the size of chars we want LOADI32_ECX &table ; 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 JE32 %Read_byte_1 ; Got EOF call it done ; load byte LOAD8_Absolute32_al &table ; load char MOVZX ; We have to zero extend it to use it RET ; Deal with EOF :Read_byte_1 LOADI32_EAX %-4 ; Put EOF in eax RET :print_chars LOADI32_ECX &table ; What we are writing LOAD32_Absolute32_ebx &fout ; Write to target file LOADI32_EAX %4 ; the syscall number for write INT_80 ; call the Kernel RET :Get_table_target CALLI32 %Read_byte ; Get single char label SHLI8_EAX !2 ; Each label in table takes 4 bytes to store ADDI32_EAX &table ; Calculate offset RET :StoreLabel CALLI32 %Get_table_target STORE32_EDI_into_Address_EAX ; Write out pointer to table RET :StorePointer ADDI8_EDI !4 ; Increment IP CALLI32 %Get_table_target ; Get address of pointer LOAD32_Address_EAX_into_EAX ; Get pointer SUB_EDI_from_EAX ; target - ip STORE32_Absolute32_eax &table ; put value in output LOADI32_EDX %4 ; set the size of chars we want CALLI32 %print_chars RET :fin NULL :fout NULL :table :ELF_end