hex0.hex0 (7994B)
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 01 # e_ident[EI_CLASS] Indicating 32 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 54 00 60 00 # e_entry Address of the entry point 44 34 00 00 00 # e_phoff Address of program header table 45 00 00 00 00 # e_shoff Address of section header table 46 47 00 00 00 00 # e_flags 48 49 34 00 # e_ehsize Indicating our 52 Byte header 50 51 20 00 # e_phentsize size of a program header table 52 01 00 # e_phnum number of entries in program table 53 54 00 00 # e_shentsize size of a section header table 55 00 00 # e_shnum number of entries in section table 56 57 00 00 # e_shstrndx index of the section names 58 59 ## Program Header 60 #:ELF_program_headers 61 #:ELF_program_header__text 62 01 00 00 00 # ph_type: PT-LOAD = 1 63 00 00 00 00 # ph_offset 64 65 00 00 60 00 # ph_vaddr 66 00 00 60 00 # ph_physaddr 67 68 64 01 00 00 # ph_filesz 69 64 01 00 00 # ph_memsz 70 71 07 00 00 00 # ph_flags: PF-X|PF-W|PF-R = 7 72 01 00 00 00 # ph_align 73 74 # :_start ; (0x0600054) 75 13 0A 00 00 # rd_s4 mv ; Initialize register 76 83 25 81 00 # rd_a1 rs1_sp !8 lw ; Input file name 77 78 ; Open input file and store FD in s2 79 93 08 80 03 # rd_a7 !56 addi ; sys_openat 80 13 05 C0 F9 # rd_a0 !-100 addi ; AT_FDCWD 81 13 06 00 00 # rd_a2 mv ; read only 82 73 00 00 00 # ecall 83 13 09 05 00 # rd_s2 rs1_a0 mv ; Save fd in s2 for later 84 85 ; Open output file and store the FD in s3 86 13 05 C0 F9 # rd_a0 !-100 addi ; AT_FDCWD 87 83 25 C1 00 # rd_a1 rs1_sp !12 lw ; Output file (argument 3) 88 13 06 10 24 # rd_a2 !577 addi ; octal 00001101 89 ; O_TRUNC 00001000 90 ; O_CREAT 00000100 91 ; O_WRONLY 00000001 92 ; OCTAL! 93 94 93 06 00 1C # rd_a3 !448 addi ; Set read, write, execute permission on user 95 ; S_IRWXU 00700 96 ; OCTAL! 97 98 73 00 00 00 # ecall 99 93 09 05 00 # rd_s3 rs1_a0 mv ; Save fd in s3 for later 100 101 # :next_byte ; (0x0600088) 102 93 08 F0 03 # rd_a7 !63 addi ; sys_read 103 13 05 09 00 # rd_a0 rs1_s2 mv ; File descriptor 104 93 05 01 00 # rd_a1 rs1_sp mv ; Buffer 105 13 06 10 00 # rd_a2 !1 addi ; Size of what we want to read (set for all subsequent syscalls) 106 73 00 00 00 # ecall 107 108 ; If the file ended (0 bytes read) terminate 109 63 00 05 0C # rs1_a0 @terminate beqz 110 # +192B 111 112 ; Check if it's a comment 113 03 05 01 00 # rd_a0 rs1_sp lb 114 93 02 30 02 # rd_t0 !0x23 addi 115 63 08 55 00 # rs1_a0 rs2_t0 @loop beq ; a0 eq to '#' 116 # +16B 117 93 02 B0 03 # rd_t0 !0x3B addi 118 63 04 55 00 # rs1_a0 rs2_t0 @loop beq ; a0 eq to ';' 119 # +8B 120 6F 00 80 02 # $not_comment jal 121 # +40B 122 # :loop ; (0x06000B8) 123 13 05 09 00 # rd_a0 rs1_s2 mv ; File descriptor 124 73 00 00 00 # ecall ; sys_read 125 126 ; If the file ended (0 bytes read) terminate 127 63 0E 05 08 # rs1_a0 @terminate beqz 128 # +156B 129 ; Check if read byte is the end of the comment (i.e. a newline character), 130 ; in that case we continue processing 131 03 05 01 00 # rd_a0 rs1_sp lb 132 93 02 A0 00 # rd_t0 !0xA addi 133 E3 0E 55 FA # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \n 134 # -68B 135 93 02 D0 00 # rd_t0 !0xD addi 136 E3 0A 55 FA # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \r 137 # -76B 138 6F F0 1F FE # $loop jal 139 # :not_comment ; (0x06000DC) 140 ; Check if it's a hex character: 141 ; in the case it's not, ignores and reads next byte 142 03 05 01 00 # rd_a0 rs1_sp lb 143 144 ; Is it between '0' and '9'? 145 93 02 00 03 # rd_t0 !48 addi ; '0' character 146 63 4A 55 00 # rs1_a0 rs2_t0 @uppercase_alpha blt 147 # +20B 148 93 02 90 03 # rd_t0 !57 addi ; '9' character 149 63 C6 A2 00 # rs1_t0 rs2_a0 @uppercase_alpha blt 150 # +12B 151 13 05 05 FD # rd_a0 rs1_a0 !-48 addi 152 6F 00 00 03 # $hex_read jal 153 # +48B 154 # :uppercase_alpha ; (0x06000F8) 155 ; Is it between 'A' and 'F'? 156 93 02 10 04 # rd_t0 !65 addi ; 'A' character 157 63 4A 55 00 # rs1_a0 rs2_t0 @lowercase_alpha blt 158 # +20B 159 93 02 60 04 # rd_t0 !70 addi ; 'F' character 160 63 C6 A2 00 # rs1_t0 rs2_a0 @lowercase_alpha blt 161 # +12B 162 13 05 95 FC # rd_a0 rs1_a0 !-55 addi 163 6F 00 80 01 # $hex_read jal 164 # +24B 165 # :lowercase_alpha ; (0x0600110) 166 ; Is it between 'a' and 'f'? 167 93 02 10 06 # rd_t0 !97 addi ; 'a' character 168 E3 4A 55 F6 # rs1_a0 rs2_t0 @next_byte blt ; Not hex, continue reading 169 # -140B 170 93 02 60 06 # rd_t0 !102 addi ; 'f' character 171 E3 C6 A2 F6 # rs1_t0 rs2_a0 @next_byte blt ; Not hex, continue reading 172 # -148B 173 13 05 95 FA # rd_a0 rs1_a0 !-87 addi 174 # :hex_read ; (0x0600124) 175 ; END check hex -- leaves the half byte in a0 176 177 63 18 0A 00 # rs1_s4 @combine bnez ; if toggle != 0 -> combine 178 # +16B 179 ; Toggle == 0, we need to prepare for later 180 93 0A 05 00 # rd_s5 rs1_a0 mv ; Load hold 181 182 13 0A 10 00 # rd_s4 !1 addi ; Set toggle 183 6F F0 9F F5 # $next_byte jal ; Read next byte 184 # -168B 185 186 # :combine ; (0x0600134) 187 ; Combine half bytes 188 93 95 4A 00 # rd_a1 rs1_s5 rs2_x4 slli ; Shift logical left 4 times 189 33 05 B5 00 # rd_a0 rs1_a0 rs2_a1 add ; Combine two half bytes 190 ; Leaves the full byte in a0 191 192 ; Values are combined, now we write in the file 193 23 00 A1 00 # rs1_sp rs2_a0 sb ; Store prepared byte in buffer 194 93 08 00 04 # rd_a7 !64 addi ; sys_write 195 13 85 09 00 # rd_a0 rs1_s3 mv ; file descriptor (stdout) 196 93 05 01 00 # rd_a1 rs1_sp mv ; string address 197 73 00 00 00 # ecall 198 199 ; Update globals 200 13 0A 00 00 # rd_s4 mv ; Clear toggle 201 93 0A 00 00 # rd_s5 mv ; Clear hold 202 203 ; Read next byte 204 6F F0 1F F3 # $next_byte jal 205 # -208B 206 207 # :terminate ; (0x60015C) 208 ; Terminate program with 0 return code 209 93 08 D0 05 # rd_a7 !93 addi ; sys_exit 210 73 00 00 00 # ecall 211 # PROGRAM END 212 213 # :ELF_end ; (0x600164)