hex0.hex0 (8065B)
1 ## Copyright (C) 2021 Ekaitz Zarraga 2 ## Copyright (C) 2021 Andrius Štikonas 3 ## Copyright (C) 2021,2022 Gabriel Wicki 4 ## This file is part of stage0. 5 ## 6 ## stage0 is free software: you can redistribute it and/or modify 7 ## it under the terms of the GNU General Public License as published by 8 ## the Free Software Foundation, either version 3 of the License, or 9 ## (at your option) any later version. 10 ## 11 ## stage0 is distributed in the hope that it will be useful, 12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 ## GNU General Public License for more details. 15 ## 16 ## You should have received a copy of the GNU General Public License 17 ## along with stage0. If not, see <http://www.gnu.org/licenses/>. 18 19 ; Register use: 20 ; s2: input fd 21 ; s3: output fd 22 ; s4: toggle 23 ; s5: hold 24 25 ; Uses top of the stack as i/o buffer 26 27 ## ELF Header 28 #:ELF_base 29 7F 45 4C 46 ## e_ident[EI_MAG0-3] ELF's magic number 30 31 02 ## e_ident[EI_CLASS] Indicating 64 bit 32 01 ## e_ident[EI_DATA] Indicating little endianness 33 01 ## e_ident[EI_VERSION] Indicating original elf 34 35 03 ## e_ident[EI_OSABI] Set at 3 for Linux 36 00 ## e_ident[EI_ABIVERSION] Ignored for Statically linked executables 37 38 00 00 00 00 00 00 00 ## e_ident[EI_PAD] 39 02 00 ## e_type Indicating Executable 40 F3 00 ## e_machine Indicating RISC-V 41 01 00 00 00 ## e_version Indicating original elf 42 43 78 00 60 00 00 00 00 00 ## e_entry Address of the entry point (Number of bytes this header is + Base Address) 44 40 00 00 00 00 00 00 00 ## e_phoff Address of program header table 45 00 00 00 00 00 00 00 00 ## e_shoff Address of section header table 46 47 00 00 00 00 ## e_flags 48 40 00 ## e_ehsize Indicating our 64 Byte header 49 50 38 00 ## e_phentsize size of a program header table 51 01 00 ## e_phnum number of entries in program table 52 53 00 00 ## e_shentsize size of a section header table 54 00 00 ## e_shnum number of entries in section table 55 56 00 00 ## e_shstrndx index of the section names 57 58 ## Program Header 59 #:ELF_program_headers 60 01 00 00 00 ## p_type 61 07 00 00 00 ## Flags 62 00 00 00 00 00 00 00 00 ## p_offset 63 64 00 00 60 00 00 00 00 00 ## p_vaddr 65 00 00 60 00 00 00 00 00 ## p_physaddr 66 67 88 01 00 00 00 00 00 00 ## p_filesz 68 88 01 00 00 00 00 00 00 ## p_memsz 69 70 01 00 00 00 00 00 00 00 ## Required alignment 71 72 # :_start ; (0x0600078) 73 13 0A 00 00 # rd_s4 mv ; Initialize register 74 83 35 01 01 # rd_a1 rs1_sp !16 ld ; Input file name 75 76 ; Open input file and store FD in s2 77 93 08 80 03 # rd_a7 !56 addi ; sys_openat 78 13 05 C0 F9 # rd_a0 !-100 addi ; AT_FDCWD 79 13 06 00 00 # rd_a2 mv ; read only 80 73 00 00 00 # ecall 81 13 09 05 00 # rd_s2 rs1_a0 mv ; Save fd in s2 for later 82 83 ; Open output file and store the FD in s3 84 13 05 C0 F9 # rd_a0 !-100 addi ; AT_FDCWD 85 83 35 81 01 # rd_a1 rs1_sp !24 ld ; Output file (argument 3) 86 13 06 10 24 # rd_a2 !577 addi ; octal 00001101 87 ; O_TRUNC 00001000 88 ; O_CREAT 00000100 89 ; O_WRONLY 00000001 90 ; OCTAL! 91 92 93 06 00 1C # rd_a3 !448 addi ; Set read, write, execute permission on user 93 ; S_IRWXU 00700 94 ; OCTAL! 95 96 73 00 00 00 # ecall 97 93 09 05 00 # rd_s3 rs1_a0 mv ; Save fd in s3 for later 98 99 # :next_byte ; (0x06000AC) 100 93 08 F0 03 # rd_a7 !63 addi ; sys_read 101 13 05 09 00 # rd_a0 rs1_s2 mv ; File descriptor 102 93 05 01 00 # rd_a1 rs1_sp mv ; Buffer 103 13 06 10 00 # rd_a2 !1 addi ; Size of what we want to read (set for all subsequent syscalls) 104 73 00 00 00 # ecall 105 106 ; If the file ended (0 bytes read) terminate 107 63 00 05 0C # rs1_a0 @terminate beqz 108 # +192B 109 110 ; Check if it's a comment 111 03 05 01 00 # rd_a0 rs1_sp lb 112 93 02 30 02 # rd_t0 !0x23 addi 113 63 08 55 00 # rs1_a0 rs2_t0 @loop beq ; a0 eq to '#' 114 # +16B 115 93 02 B0 03 # rd_t0 !0x3B addi 116 63 04 55 00 # rs1_a0 rs2_t0 @loop beq ; a0 eq to ';' 117 # +8B 118 6F 00 80 02 # $not_comment jal 119 # +40B 120 # :loop ; (0x06000DC) 121 13 05 09 00 # rd_a0 rs1_s2 mv ; File descriptor 122 73 00 00 00 # ecall ; sys_read 123 124 ; If the file ended (0 bytes read) terminate 125 63 0E 05 08 # rs1_a0 @terminate beqz 126 # +156B 127 ; Check if read byte is the end of the comment (i.e. a newline character), 128 ; in that case we continue processing 129 03 05 01 00 # rd_a0 rs1_sp lb 130 93 02 A0 00 # rd_t0 !0xA addi 131 E3 0E 55 FA # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \n 132 # -68B 133 93 02 D0 00 # rd_t0 !0xD addi 134 E3 0A 55 FA # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \r 135 # -76B 136 6F F0 1F FE # $loop jal 137 # :not_comment ; (0x0600100) 138 ; Check if it's a hex character: 139 ; in the case it's not, ignores and reads next byte 140 03 05 01 00 # rd_a0 rs1_sp lb 141 142 ; Is it between '0' and '9'? 143 93 02 00 03 # rd_t0 !48 addi ; '0' character 144 63 4A 55 00 # rs1_a0 rs2_t0 @uppercase_alpha blt 145 # +20B 146 93 02 90 03 # rd_t0 !57 addi ; '9' character 147 63 C6 A2 00 # rs1_t0 rs2_a0 @uppercase_alpha blt 148 # +12B 149 13 05 05 FD # rd_a0 rs1_a0 !-48 addi 150 6F 00 00 03 # $hex_read jal 151 # +48B 152 # :uppercase_alpha ; (0x060011C) 153 ; Is it between 'A' and 'F'? 154 93 02 10 04 # rd_t0 !65 addi ; 'A' character 155 63 4A 55 00 # rs1_a0 rs2_t0 @lowercase_alpha blt 156 # +20B 157 93 02 60 04 # rd_t0 !70 addi ; 'F' character 158 63 C6 A2 00 # rs1_t0 rs2_a0 @lowercase_alpha blt 159 # +12B 160 13 05 95 FC # rd_a0 rs1_a0 !-55 addi 161 6F 00 80 01 # $hex_read jal 162 # +24B 163 # :lowercase_alpha ; (0x0600134) 164 ; Is it between 'a' and 'f'? 165 93 02 10 06 # rd_t0 !97 addi ; 'a' character 166 E3 4A 55 F6 # rs1_a0 rs2_t0 @next_byte blt ; Not hex, continue reading 167 # -140B 168 93 02 60 06 # rd_t0 !102 addi ; 'f' character 169 E3 C6 A2 F6 # rs1_t0 rs2_a0 @next_byte blt ; Not hex, continue reading 170 # -148B 171 13 05 95 FA # rd_a0 rs1_a0 !-87 addi 172 # :hex_read ; (0x0600148) 173 ; END check hex -- leaves the half byte in a0 174 175 63 18 0A 00 # rs1_s4 @combine bnez ; if toggle != 0 -> combine 176 # +16B 177 ; Toggle == 0, we need to prepare for later 178 93 0A 05 00 # rd_s5 rs1_a0 mv ; Load hold 179 180 13 0A 10 00 # rd_s4 !1 addi ; Set toggle 181 6F F0 9F F5 # $next_byte jal ; Read next byte 182 # -168B 183 184 # :combine ; (0x0600158) 185 ; Combine half bytes 186 93 95 4A 00 # rd_a1 rs1_s5 rs2_x4 slli ; Shift logical left 4 times 187 33 05 B5 00 # rd_a0 rs1_a0 rs2_a1 add ; Combine two half bytes 188 ; Leaves the full byte in a0 189 190 ; Values are combined, now we write in the file 191 23 00 A1 00 # rs1_sp rs2_a0 sb ; Store prepared byte in buffer 192 93 08 00 04 # rd_a7 !64 addi ; sys_write 193 13 85 09 00 # rd_a0 rs1_s3 mv ; file descriptor (stdout) 194 93 05 01 00 # rd_a1 rs1_sp mv ; string address 195 73 00 00 00 # ecall 196 197 ; Update globals 198 13 0A 00 00 # rd_s4 mv ; Clear toggle 199 93 0A 00 00 # rd_s5 mv ; Clear hold 200 201 ; Read next byte 202 6F F0 1F F3 # $next_byte jal 203 # -208B 204 205 # :terminate ; (0x600180) 206 ; Terminate program with 0 return code 207 93 08 D0 05 # rd_a7 !93 addi ; sys_exit 208 73 00 00 00 # ecall 209 # PROGRAM END 210 211 # :ELF_end ; (0x600188)