;; 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 . section .text global _start ; 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 mov ecx, 0 ;·prepare·read_only mov edx, 0 ;·extra sure mov eax, 5 ;·the·syscall·number·for·open() int 0x80 ; Now open that damn file mov [fin], eax ; Preserve the file pointer we were given pop ebx ;·Get·the·actual·output name mov ecx, 577 ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC mov edx, 448 ; Prepare file as RWX for owner only (700 in octal) mov eax, 5 ;·the·syscall·number·for·open() int 0x80 ; Now open that damn file mov [fout], eax ; Preserve the file pointer we were given mov ebp, -1 ; Our flag for byte processing mov esi, 0 ; temp storage for the sum mov edi, 0 ; Our starting IP call First_pass ; Process it ; rewind input file mov ebx, [fin] ; Using our input file mov ecx, 0 ; Offset Zero mov edx, 0 ; Whence Zero mov eax, 19 ; lseek int 0x80 mov ebp, -1 ; Our flag for byte processing mov esi, 0 ; temp storage for the sum mov edi, 0 ; Our starting IP call Second_pass ; Process it jmp Done First_pass: call Read_byte ; Deal with EOF cmp eax, -4 je First_pass_done ; Check for : cmp eax, 0x3a jne First_pass_0 ; Deal with label call StoreLabel First_pass_0: ; Check for : cmp eax, 0x25 je First_pass_pointer ; Deal with everything else call hex ; Process our char ; Deal with EOF cmp eax, -4 je First_pass_done ; deal with -1 values cmp eax, 0 jl First_pass ; deal with toggle cmp ebp, 0 je First_pass_1 add edi, 1 ; Increment IP First_pass_1: not ebp jmp First_pass First_pass_pointer: ; Deal with Pointer to label call Read_byte ; Drop the char add edi, 4 ; Increment IP jmp First_pass ; Loop again First_pass_done: RET hex: ; deal with EOF cmp eax, -4 je EOF ; deal with line comments starting with ; cmp eax, 0x23 je ascii_comment ; deal with line comments starting with ; cmp eax, 0x3b je ascii_comment ; deal all ascii less than 0 cmp eax, 0x30 jl ascii_other ; deal with 0-9 cmp eax, 0x3a jl ascii_num ; deal with all ascii less than A cmp eax, 0x41 jl ascii_other ; deal with A-F cmp eax, 0x47 jl ascii_high ;deal with all ascii less than a cmp eax, 0x61 jl ascii_other ;deal with a-f cmp eax, 0x67 jl ascii_low ; The rest that remains needs to be ignored jmp ascii_other Second_pass: call Read_byte ; Deal with EOF cmp eax, -4 je Second_pass_done ; Simply drop the label cmp eax, 0x3a jne Second_pass_0 call Read_byte jmp Second_pass Second_pass_0: ; Deal with pointer cmp eax, 0x25 jne Second_pass_1 call StorePointer jmp Second_pass Second_pass_1: ; Deal with everything else call hex ; Process our char ; Deal with EOF cmp eax, -4 je Second_pass_done ; deal with -1 values cmp eax, 0 jl Second_pass ; deal with toggle cmp ebp, 0 je print ; process first byte of pair mov esi, eax mov ebp, 0 jmp Second_pass Second_pass_done: ret EOF: ret ascii_num: sub eax, 0x30 ret ascii_low: sub eax, 0x57 ret ascii_high: sub eax, 0x37 ret ascii_other: mov eax, -1 ret ascii_comment: call Read_byte cmp eax, 0xd je ascii_comment_cr cmp eax, 0xa jne ascii_comment ascii_comment_cr: mov eax, -1 ret ; process second byte of pair print: ; update the sum and store in output shl esi, 4 add eax, esi mov [table], al ; flip the toggle not ebp ; Print our first Hex mov edx, 1 ; set the size of chars we want call print_chars add edi, 1 ; Increment IP jmp Second_pass Done: ; program completed Successfully mov ebx, 0 ; All is well mov eax, 1 ; put the exit syscall number in eax int 0x80 ; Call it a good day Read_byte: ; Attempt to read 1 byte from STDIN mov edx, 1 ; set the size of chars we want mov ecx, table ; Where to put it mov ebx, [fin] ; Where are we reading from mov eax, 3 ; the syscall number for read int 0x80 ; call the Kernel test eax, eax ; check what we got je Read_byte_1 ; Got EOF call it done ; load byte mov al, [table] ; load char movzx eax, al ; We have to zero extend it to use it ret ; Deal with EOF Read_byte_1: mov eax, -4 ; Put EOF in eax ret print_chars: mov ecx, table ; What we are writing mov ebx, [fout] ; Write to target file mov eax, 4 ; the syscall number for write int 0x80 ; call the Kernel ret Get_table_target: call Read_byte ; Get single char label shl eax, 2 ; Each label in table takes 4 bytes to store add eax, table ; Calculate offset ret StoreLabel: call Get_table_target mov [eax], edi ; Write out pointer to table ret StorePointer: add edi, 4 ; Increment IP call Get_table_target ; Get address of pointer mov eax, [eax] ; Get pointer sub eax, edi ; target - ip mov [table], eax ; put value in output mov edx, 4 ; set the size of chars we want call print_chars ret section .data ELF_end: fin: dq 0 fout: dq 0 table: dq 0