M0.hex2 (50189B)
1 ; Copyright (C) 2017 Jeremiah Orians 2 ; Copyright (C) 2020 Sanne Wouda 3 ; This file is part of stage0. 4 ; 5 ; stage0 is free software: you can redistribute it and/or modify 6 ; it under the terms of the GNU General Public License as published by 7 ; the Free Software Foundation, either version 3 of the License, or 8 ; (at your option) any later version. 9 ; 10 ; stage0 is distributed in the hope that it will be useful, 11 ; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 ; GNU General Public License for more details. 14 ; 15 ; You should have received a copy of the GNU General Public License 16 ; along with stage0. If not, see <http://www.gnu.org/licenses/>. 17 18 19 ; Register usage: 20 ; X0, X8, RSI, RDI => Temps 21 ; X12 => MALLOC 22 ; X13 => HEAD 23 ; X14 => Output_file 24 ; X15 => Input_file 25 26 ; Struct format: (size 32) 27 ; NEXT => 0 28 ; TYPE => 8 29 ; TEXT => 16 30 ; EXPRESSION => 24 31 32 ; Types 33 ; None => 0 34 ; MACRO => 1 35 ; STRING => 2 36 37 ; Where the ELF Header is going to hit 38 ; Simply jump to _start 39 ; Our main function 40 :_start 41 e10b40f9 # LDR_X1_[SP,16] ; Get the actual input name 42 600c8092 # SET_X0_TO_FCNTL_H_AT_FDCWD ; AT_FDCWD, relative to current working directory 43 020080d2 # SET_X2_TO_0 ; prepare read_only 44 080780d2 # SET_X8_TO_SYS_OPENAT ; The syscall number for openat(), aarch64 has no open() 45 010000d4 # SYSCALL ; Now open that damn file 46 ef0300aa # SET_X15_FROM_X0 ; Preserve the file pointer we were given 47 48 e10f40f9 # LDR_X1_[SP,24] ; Get the output name 49 600c8092 # SET_X0_TO_FCNTL_H_AT_FDCWD ; AT_FDCWD, relative to current working directory 50 224880d2 # SET_X2_TO_577 ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC 51 033080d2 # SET_X3_TO_384 ; Prepare file as RWX for owner only (600 in octal) 52 080780d2 # SET_X8_TO_SYS_OPENAT ; The syscall number for openat(), aarch64 has no open() 53 010000d4 # SYSCALL ; Open file! 54 1f0000f1 # CMP_X0_TO_0 ; Check for missing output 55 4d000054 # SKIP_INST_LE ; Have real output 56 ^~_start_out 14 # ^~_start_out FBRANCH 57 200080d2 # SET_X0_TO_1 ; Use stdout 58 59 :_start_out 60 ee0300aa # SET_X14_FROM_X0 ; Preserve the file pointer we were given 61 c81a80d2 # SET_X8_TO_SYS_BRK ; the Syscall # for SYS_BRK 62 000080d2 # SET_X0_TO_0 ; Get current brk 63 010000d4 # SYSCALL ; Let the kernel do the work 64 ec0300aa # SET_X12_FROM_X0 ; Set our malloc pointer 65 66 ^~Tokenize_Line 94 # ^~Tokenize_Line FCALL ; Get all lines 67 e0030daa # SET_X0_FROM_X13 ; prepare for Reverse_List 68 ^~Reverse_List 94 # ^~Reverse_List FCALL ; Correct order 69 ed0300aa # SET_X13_FROM_X0 ; Update HEAD 70 ^~Identify_Macros 94 # ^~Identify_Macros FCALL ; Find the DEFINEs 71 ^~Line_Macro 94 # ^~Line_Macro FCALL ; Apply the DEFINEs 72 ^~Process_String 94 # ^~Process_String FCALL ; Handle strings 73 ^~Eval_Immediates 94 # ^~Eval_Immediates FCALL ; Handle Numbers 74 ^~Preserve_Other 94 # ^~Preserve_Other FCALL ; Collect the remaining 75 ^~Print_Hex 94 # ^~Print_Hex FCALL ; Output our results 76 77 :Done 78 ; program completed Successfully 79 000080d2 # SET_X0_TO_0 ; All is well 80 a80b80d2 # SET_X8_TO_SYS_EXIT ; put the exit syscall number in eax 81 010000d4 # SYSCALL ; Call it a good day 82 83 84 ; Tokenize_Line Function 85 ; Using input file X15 and Head X13 86 ; Creates a linked list of structs 87 ; Uses X1 for in_set strings, X2 for Int C and X3 for Struct Token* p 88 :Tokenize_Line 89 e10f1ff8 # PUSH_X1 ; Protect X1 90 e20f1ff8 # PUSH_X2 ; Protect X2 91 e30f1ff8 # PUSH_X3 ; Protect X3 92 fe0f1ff8 # PUSH_LR 93 :restart 94 ^~fgetc 94 # ^~fgetc FCALL ; Read a char 95 1f1000b1 # CMP_X0_TO_MINUS_4 ; Check for EOF 96 41000054 # SKIP_INST_NE ; File is collected 97 ^~done 14 # ^~done FBRANCH 98 99 001c4092 # AND_X0_X0_0xFF ; We have to zero extend it to use it 100 e20300aa # SET_X2_FROM_X0 ; Protect C 101 102 41000018 # LOAD_W1_AHEAD ; Get pointer to ";;" 103 02000014 # SKIP_32_DATA 104 &comments # &comments 105 ^~In_Set 94 # ^~In_Set FCALL ; Check for comments 106 1f0400f1 # CMP_X0_TO_1 ; If comments 107 41000054 # SKIP_INST_NE ; try again 108 ^~Purge_LineComment 14 # ^~Purge_LineComment FBRANCH 109 110 e00302aa # SET_X0_FROM_X2 ; put C in place for check 111 41000018 # LOAD_W1_AHEAD ; Get pointer to "\n\t " 112 02000014 # SKIP_32_DATA 113 &terminators # &terminators 114 ^~In_Set 94 # ^~In_Set FCALL ; Check for terminators 115 1f0400f1 # CMP_X0_TO_1 ; If terminator 116 41000054 # SKIP_INST_NE ; try again 117 ^~restart 17 # ^~restart RBRANCH 118 119 000480d2 # SET_X0_TO_32 ; Malloc the struct P 120 ^~malloc 94 # ^~malloc FCALL ; Get pointer to P 121 e30300aa # SET_X3_FROM_X0 ; Protect P 122 6d0000f9 # STR_X13_[X3] ; P->NEXT = HEAD 123 ed0303aa # SET_X13_FROM_X3 ; HEAD = P 124 125 e00302aa # SET_X0_FROM_X2 ; put C in place for check 126 41000018 # LOAD_W1_AHEAD ; Get pointer to "\"'" 127 02000014 # SKIP_32_DATA 128 &string_char # &string_char 129 ^~In_Set 94 # ^~In_Set FCALL ; Check for string chars 130 1f0400f1 # CMP_X0_TO_1 ; If string char 131 41000054 # SKIP_INST_NE ; Get string 132 ^~Store_String 14 # ^~Store_String FBRANCH 133 134 ^~Store_Atom 94 # ^~Store_Atom FCALL ; Get whole token 135 ^~restart 17 # ^~restart RBRANCH 136 137 :done 138 fe0741f8 # POP_LR 139 e30741f8 # POP_X3 ; Restore X3 140 e20741f8 # POP_X2 ; Restore X2 141 e10741f8 # POP_X1 ; Restore X1 142 c0035fd6 # RETURN 143 144 145 ; fgetc function 146 ; Receives FILE* in X15 147 ; Returns -4 (EOF) or char in X0 148 :fgetc 149 e10f1ff8 # PUSH_X1 150 e20f1ff8 # PUSH_X2 151 60008092 # SET_X0_TO_MINUS_4 ; Put EOF in x0 152 e00f1ff8 # PUSH_X0 ; Assume bad (If nothing read, value will remain EOF) 153 e1030091 # SET_X1_FROM_SP ; Get stack addresss 154 e0030faa # SET_X0_FROM_X15 ; Where are we reading from 155 e80780d2 # SET_X8_TO_SYS_READ ; the syscall number for read 156 220080d2 # SET_X2_TO_1 ; set the size of chars we want 157 158 010000d4 # SYSCALL ; call the Kernel 159 160 e00741f8 # POP_X0 ; Get either char or EOF 161 e20741f8 # POP_X2 162 e10741f8 # POP_X1 163 c0035fd6 # RETURN 164 165 166 ; Malloc isn't actually required if the program being built fits in the initial memory 167 ; However, it doesn't take much to add it. 168 ; Requires X12 to be initialized and X0 to have the number of desired bytes 169 :malloc 170 e10f1ff8 # PUSH_X1 171 00000c8b # ADD_X0_X0_X12 ; Request the number of desired bytes 172 c81a80d2 # SET_X8_TO_SYS_BRK ; the Syscall # for SYS_BRK 173 010000d4 # SYSCALL ; call the Kernel 174 175 e1030caa # SET_X1_FROM_X12 ; save Return pointer 176 ec0300aa # SET_X12_FROM_X0 ; Update pointer 177 e00301aa # SET_X0_FROM_X1 ; return pointer 178 e10741f8 # POP_X1 179 c0035fd6 # RETURN 180 181 182 ; Purge_LineComment function 183 ; Reads chars until LF and jumps to restart 184 :Purge_LineComment 185 ^~fgetc 97 # ^~fgetc RCALL ; Get a char 186 001c4092 # AND_X0_X0_0xFF ; Zero extend 187 1f2800f1 # CMP_X0_TO_10 ; While not LF 188 40000054 # SKIP_INST_EQ ; Keep reading 189 ^~Purge_LineComment 17 # ^~Purge_LineComment RBRANCH 190 ^~restart 17 # ^~restart RBRANCH 191 192 193 ; Store_String Function 194 ; Receives C in X2, HEAD in X3 and Input file in X14 195 ; Uses X1 for terminator, X2 for C and X3 for string 196 :Store_String 197 e10f1ff8 # PUSH_X1 ; Protect X1 198 e20f1ff8 # PUSH_X2 ; Protect X2 199 e30f1ff8 # PUSH_X3 ; Protect X3 200 201 400080d2 # SET_X0_TO_2 ; Using TYPE STRING 202 600400f9 # STR_X0_[X3,8] ; HEAD->TYPE = STRING 203 004080d2 # SET_X0_TO_512 ; Malloc the string 204 ^~malloc 97 # ^~malloc RCALL ; Get pointer to P 205 600800f9 # STR_X0_[X3,16] ; HEAD->TEXT = STRING 206 e10302aa # SET_X1_FROM_X2 ; Protect terminator 207 e30300aa # SET_X3_FROM_X0 ; Protect string pointer 208 :Store_String_Loop 209 62140038 # STR_BYTE_W2_[X3]_1 210 ^~fgetc 97 # ^~fgetc RCALL ; read next char 211 001c4092 # AND_X0_X0_0xFF ; Zero extend it 212 e20300aa # SET_X2_FROM_X0 ; Update C 213 5f0001eb # CMP_X2_X1 ; See if we hit terminator 214 40000054 # SKIP_INST_EQ ; Otherwise keep looping 215 ^~Store_String_Loop 17 # ^~Store_String_Loop RBRANCH 216 217 e30741f8 # POP_X3 ; Restore X3 218 e20741f8 # POP_X2 ; Restore X2 219 e10741f8 # POP_X1 ; Restore X1 220 e00303aa # SET_X0_FROM_X3 ; Return HEAD 221 ^~restart 17 # ^~restart RBRANCH 222 223 224 ; Store_Atom Function 225 ; Receives C in X2, HEAD in X3 and Input file in X15 226 ; Uses X1 for in_set strings, X2 for C and X3 for string 227 :Store_Atom 228 e10f1ff8 # PUSH_X1 ; Protect X1 229 e20f1ff8 # PUSH_X2 ; Protect X2 230 e30f1ff8 # PUSH_X3 ; Protect X3 231 fe0f1ff8 # PUSH_LR 232 233 002080d2 # SET_X0_TO_256 ; Malloc the string 234 ^~malloc 97 # ^~malloc RCALL ; Get pointer to P 235 600800f9 # STR_X0_[X3,16] ; HEAD->TEXT = STRING 236 41000018 # LOAD_W1_AHEAD ; Get pointer to "\n\t " 237 02000014 # SKIP_32_DATA 238 &terminators # &terminators 239 e30300aa # SET_X3_FROM_X0 ; Protect string pointer 240 :Store_Atom_loop 241 62140038 # STR_BYTE_W2_[X3]_1 ; write byte 242 ^~fgetc 97 # ^~fgetc RCALL ; read next char 243 001c4092 # AND_X0_X0_0xFF ; Zero extend it 244 e20300aa # SET_X2_FROM_X0 ; Update C 245 ^~In_Set 94 # ^~In_Set FCALL ; Check for terminators 246 1f0000f1 # CMP_X0_TO_0 ; Check for "\n\t " 247 41000054 # SKIP_INST_NE ; Loop otherwise 248 ^~Store_Atom_loop 17 # ^~Store_Atom_loop RBRANCH 249 250 fe0741f8 # POP_LR 251 e30741f8 # POP_X3 ; Restore X3 252 e20741f8 # POP_X2 ; Restore X2 253 e10741f8 # POP_X1 ; Restore X1 254 e00303aa # SET_X0_FROM_X3 ; Return HEAD 255 c0035fd6 # RETURN 256 257 258 ; In_Set function 259 ; Receives Char C in X0 and CHAR* in X1 260 ; Returns 1 if true, zero if false in X0 261 :In_Set 262 e10f1ff8 # PUSH_X1 ; Protect X1 263 e20f1ff8 # PUSH_X2 ; Protect X2 264 :In_Set_loop 265 22144038 # LDR_BYTE_W2_[X1]_1 ; Read char 266 267 1f0002eb # CMP_X0_X2 ; See if they match 268 41000054 # SKIP_INST_NE ; return true 269 ^~In_Set_True 14 # ^~In_Set_True FBRANCH 270 271 5f0000f1 # CMP_X2_TO_0 ; Check for NULL 272 41000054 # SKIP_INST_NE ; return false 273 ^~In_Set_False 14 # ^~In_Set_False FBRANCH 274 275 ^~In_Set_loop 17 # ^~In_Set_loop RBRANCH ; Keep looping 276 277 :In_Set_True 278 200080d2 # SET_X0_TO_1 ; Set True 279 e20741f8 # POP_X2 ; Restore X2 280 e10741f8 # POP_X1 ; Restore X1 281 c0035fd6 # RETURN 282 283 :In_Set_False 284 000080d2 # SET_X0_TO_0 ; Set FALSE 285 e20741f8 # POP_X2 ; Restore X2 286 e10741f8 # POP_X1 ; Restore X1 287 c0035fd6 # RETURN 288 289 ; Char sets 290 :terminators 291 0A 09 20 00 # "\n\t " 292 293 :comments 294 23 3B 00 # "#;" 295 296 :string_char 297 22 27 00 # '22 27 00' 298 299 00 00 # '00 00' ; .p2align 2 300 301 ; Reverse_List function 302 ; Receives List in X0 303 ; Returns the list reversed in X0 304 :Reverse_List 305 e10f1ff8 # PUSH_X1 ; Protect X1 306 e20f1ff8 # PUSH_X2 ; Protect X2 307 e10300aa # SET_X1_FROM_X0 ; Set HEAD 308 000080d2 # SET_X0_TO_0 ; ROOT = NULL 309 :Reverse_List_Loop 310 3f0000f1 # CMP_X1_TO_0 ; WHILE HEAD != NULL 311 41000054 # SKIP_INST_NE ; Stop otherwise 312 ^~Reverse_List_Done 14 # ^~Reverse_List_Done FBRANCH 313 314 220040f9 # LDR_X2_[X1] ; NEXT = HEAD->NEXT 315 200000f9 # STR_X0_[X1] ; HEAD->NEXT = ROOT 316 e00301aa # SET_X0_FROM_X1 ; ROOT = HEAD 317 e10302aa # SET_X1_FROM_X2 ; HEAD = NEXT 318 ^~Reverse_List_Loop 17 # ^~Reverse_List_Loop RBRANCH ; Keep Going 319 320 :Reverse_List_Done 321 e20741f8 # POP_X2 ; Restore X2 322 e10741f8 # POP_X1 ; Restore X1 323 c0035fd6 # RETURN 324 325 326 ; Identify_Macros function 327 ; Receives List in X0 328 ; Updates the list in place; does not modify registers 329 ; Uses X1 for DEFINE, X2 for I 330 :Identify_Macros 331 e00f1ff8 # PUSH_X0 ; Protect X0 332 e10f1ff8 # PUSH_X1 ; Protect X1 333 e20f1ff8 # PUSH_X2 ; Protect X2 334 e30f1ff8 # PUSH_X3 ; Protect X3 335 fe0f1ff8 # PUSH_LR 336 337 41000018 # LOAD_W1_AHEAD ; Setup define string 338 02000014 # SKIP_32_DATA 339 &DEFINE_str # &DEFINE_str 340 e20300aa # SET_X2_FROM_X0 ; I = HEAD 341 :Identify_Macros_Loop 342 400840f9 # LDR_X0_[X2,16] ; I->TEXT 343 ^~match 94 # ^~match FCALL ; IF "DEFINE" == I->TEXT 344 1f0000f1 # CMP_X0_TO_0 ; Check if match 345 40000054 # SKIP_INST_EQ ; Skip the work 346 ^~Identify_Macros_Next 14 # ^~Identify_Macros_Next FBRANCH 347 348 ; Deal with MACRO 349 200080d2 # SET_X0_TO_1 ; Using MACRO 350 400400f9 # STR_X0_[X2,8] ; I->TYPE = MACRO 351 352 400040f9 # LDR_X0_[X2] ; I->NEXT 353 000840f9 # LDR_X0_[X0,16] ; I->NEXT->TEXT 354 400800f9 # STR_X0_[X2,16] ; I->TEXT = I->NEXT->TEXT 355 356 400040f9 # LDR_X0_[X2] ; I->NEXT 357 000040f9 # LDR_X0_[X0] ; I->NEXT->NEXT 358 000840f9 # LDR_X0_[X0,16] ; I->NEXT->NEXT->TEXT 359 400c00f9 # STR_X0_[X2,24] ; I->EXPRESSION = I->NEXT->NEXT->TEXT 360 361 400040f9 # LDR_X0_[X2] ; I->NEXT 362 000040f9 # LDR_X0_[X0] ; I->NEXT->NEXT 363 000040f9 # LDR_X0_[X0] ; I->NEXT->NEXT->NEXT 364 400000f9 # STR_X0_[X2] ; I->NEXT = I->NEXT->NEXT->NEXT 365 366 :Identify_Macros_Next 367 420040f9 # LDR_X2_[X2] ; I = I->NEXT 368 5f0000f1 # CMP_X2_TO_0 ; Check for NULL 369 40000054 # SKIP_INST_EQ ; Keep looping otherwise 370 ^~Identify_Macros_Loop 17 # ^~Identify_Macros_Loop RBRANCH 371 372 fe0741f8 # POP_LR 373 e30741f8 # POP_X3 ; Restore X3 374 e20741f8 # POP_X2 ; Restore X2 375 e10741f8 # POP_X1 ; Restore X1 376 e00741f8 # POP_X0 ; Restore X0 377 c0035fd6 # RETURN 378 379 :DEFINE_str 380 44 45 46 49 4E 45 00 # "DEFINE" 381 382 00 # '00' ; .p2align 2 383 384 ; match function 385 ; Receives CHAR* in X0 and CHAR* in X1 386 ; Returns 0 (TRUE) or 1 (FALSE) in X0 387 :match 388 e10f1ff8 # PUSH_X1 ; Protect X1 389 e20f1ff8 # PUSH_X2 ; Protect X2 390 e30f1ff8 # PUSH_X3 ; Protect X3 391 fe0f1ff8 # PUSH_LR 392 393 e20300aa # SET_X2_FROM_X0 ; S1 in place 394 e30301aa # SET_X3_FROM_X1 ; S2 in place 395 :match_Loop 396 40144038 # LDR_BYTE_W0_[X2]_1 ; S1[0] 397 61144038 # LDR_BYTE_W1_[X3]_1 ; S2[0] 398 1f0001eb # CMP_X0_X1 ; See if they match 399 40000054 # SKIP_INST_EQ ; If not 400 ^~match_False 14 # ^~match_False FBRANCH 401 402 1f0000f1 # CMP_X0_TO_0 ; If reached end of string 403 41000054 # SKIP_INST_NE ; Perfect match 404 ^~match_Done 14 # ^~match_Done FBRANCH 405 ^~match_Loop 17 # ^~match_Loop RBRANCH ; Otherwise keep looping 406 407 :match_False 408 200080d2 # SET_X0_TO_1 ; Return false 409 :match_Done 410 fe0741f8 # POP_LR 411 e30741f8 # POP_X3 ; Restore X3 412 e20741f8 # POP_X2 ; Restore X2 413 e10741f8 # POP_X1 ; Restore X1 414 c0035fd6 # RETURN 415 416 417 ; Line_Macro function 418 ; Receives List in X0 419 ; Updates the list in place; does not modify registers 420 ; Uses X0 for I, X1 for I->TEXT, X2 for I->EXPRESSION 421 :Line_Macro 422 e00f1ff8 # PUSH_X0 ; Protect X0 423 e10f1ff8 # PUSH_X1 ; Protect X1 424 e20f1ff8 # PUSH_X2 ; Protect X2 425 e30f1ff8 # PUSH_X3 ; Protect X3 426 fe0f1ff8 # PUSH_LR 427 :Line_Macro_Loop 428 010440f9 # LDR_X1_[X0,8] ; I->TYPE 429 3f0400f1 # CMP_X1_TO_1 ; IF MACRO == I->TYPE 430 40000054 # SKIP_INST_EQ ; Otherwise move on 431 ^~Line_Macro_Next 14 # ^~Line_Macro_Next FBRANCH 432 433 ; Is a macro apply 434 010840f9 # LDR_X1_[X0,16] ; I->TEXT 435 020c40f9 # LDR_X2_[X0,24] ; I->EXPRESSION 436 000040f9 # LDR_X0_[X0] ; I->NEXT 437 ^~Set_Expression 94 # ^~Set_Expression FCALL ; Apply it 438 ^~Line_Macro_Loop 17 # ^~Line_Macro_Loop RBRANCH ; Move on to next 439 440 :Line_Macro_Next 441 000040f9 # LDR_X0_[X0] ; I->NEXT 442 1f0000f1 # CMP_X0_TO_0 ; Check for NULL 443 40000054 # SKIP_INST_EQ ; Keep going 444 ^~Line_Macro_Loop 17 # ^~Line_Macro_Loop RBRANCH 445 446 fe0741f8 # POP_LR 447 e30741f8 # POP_X3 ; Restore X3 448 e20741f8 # POP_X2 ; Restore X2 449 e10741f8 # POP_X1 ; Restore X1 450 e00741f8 # POP_X0 ; Restore X0 451 c0035fd6 # RETURN 452 453 454 ; Set_Expression function 455 ; Receives List in X0, CHAR* in X1 and CHAR* in X2 456 ; Updates the list in place; does not modify registers 457 ; Uses X1 for C, X2 for EXP and X3 for I 458 :Set_Expression 459 e00f1ff8 # PUSH_X0 ; Protect X0 460 e10f1ff8 # PUSH_X1 ; Protect X1 461 e20f1ff8 # PUSH_X2 ; Protect X2 462 e30f1ff8 # PUSH_X3 ; Protect X3 463 fe0f1ff8 # PUSH_LR 464 e30300aa # SET_X3_FROM_X0 ; Set I 465 :Set_Expression_Loop 466 600440f9 # LDR_X0_[X3,8] ; I->TYPE 467 1f0400f1 # CMP_X0_TO_1 ; IF MACRO == I->TYPE 468 41000054 # SKIP_INST_NE ; Ignore and move on 469 ^~Set_Expression_Next 14 # ^~Set_Expression_Next FBRANCH 470 471 600840f9 # LDR_X0_[X3,16] ; I->TEXT 472 ^~match 97 # ^~match RCALL ; Check for match 473 1f0000f1 # CMP_X0_TO_0 ; If match 474 40000054 # SKIP_INST_EQ ; Otherwise next 475 ^~Set_Expression_Next 14 # ^~Set_Expression_Next FBRANCH 476 477 ; We have a non-macro match 478 620c00f9 # STR_X2_[X3,24] ; I->EXPRESSION = EXP 479 480 :Set_Expression_Next 481 630040f9 # LDR_X3_[X3] ; I = I->NEXT 482 7f0000f1 # CMP_X3_TO_0 ; IF NULL == I 483 40000054 # SKIP_INST_EQ ; Otherwise keep looping 484 ^~Set_Expression_Loop 17 # ^~Set_Expression_Loop RBRANCH 485 486 fe0741f8 # POP_LR 487 e30741f8 # POP_X3 ; Restore X3 488 e20741f8 # POP_X2 ; Restore X2 489 e10741f8 # POP_X1 ; Restore X1 490 e00741f8 # POP_X0 ; Restore X0 491 c0035fd6 # RETURN 492 493 494 ; Process_String function 495 ; Receives List in X0 496 ; Update the list in place; does not modify registers 497 ; Uses X1 for I->TEXT, X2 for I and X3 for S 498 :Process_String 499 e00f1ff8 # PUSH_X0 ; Protect X0 500 e10f1ff8 # PUSH_X1 ; Protect X1 501 e20f1ff8 # PUSH_X2 ; Protect X2 502 e30f1ff8 # PUSH_X3 ; Protect X3 503 fe0f1ff8 # PUSH_LR 504 505 e20300aa # SET_X2_FROM_X0 ; I = HEAD 506 :Process_String_loop 507 400440f9 # LDR_X0_[X2,8] ; I->TYPE 508 1f0800f1 # CMP_X0_TO_2 ; IF STRING == I->TYPE 509 40000054 # SKIP_INST_EQ ; Skip to next 510 ^~Process_String_Next 14 # ^~Process_String_Next FBRANCH 511 512 410840f9 # LDR_X1_[X2,16] ; I->TEXT 513 20004039 # LDR_BYTE_W0_[X1] ; I->TEXT[0] 514 1f9c00f1 # CMP_X0_TO_39 ; IF '\'' == I->TEXT[0] 515 40000054 # SKIP_INST_EQ ; Deal with '\"' 516 ^~Process_String_Raw 14 # ^~Process_String_Raw FBRANCH 517 518 ; Deal with '\'' 519 21040091 # ADD_X1_X1_1 ; I->TEXT + 1 520 410c00f9 # STR_X1_[X2,24] ; I->EXPRESSION = I->TEXT + 1 521 ^~Process_String_Next 14 # ^~Process_String_Next FBRANCH ; Move on to next 522 523 :Process_String_Raw 524 e00301aa # SET_X0_FROM_X1 ; Get length of I->TEXT 525 ^~string_length 94 # ^~string_length FCALL ; Do it 526 00fc42d3 # LSR_X0_X0_2 ; LENGTH = LENGTH >> 2 527 00040091 # ADD_X0_X0_1 ; LENGTH = LENGTH + 1 528 00f07dd3 # LSL_X0_X0_3 ; LENGTH = LENGTH << 3 529 ^~malloc 97 # ^~malloc RCALL ; Get string 530 e30301aa # SET_X3_FROM_X1 ; S = I->TEXT 531 63040091 # ADD_X3_X3_1 ; S = S + 1 532 400c00f9 # STR_X0_[X2,24] ; I->EXPRESSION = hexify 533 e10300aa # SET_X1_FROM_X0 ; Put hexify buffer in x1 534 535 :Process_String_Raw_Loop 536 60144038 # LDR_BYTE_W0_[X3]_1 ; Read 1 chars 537 e00f1ff8 # PUSH_X0 538 ^~hex8 94 # ^~hex8 FCALL ; write them all 539 e00741f8 # POP_X0 540 1f0000f1 # CMP_X0_TO_0 ; Check for NULL 541 40000054 # SKIP_INST_EQ ; Keep looping 542 ^~Process_String_Raw_Loop 17 # ^~Process_String_Raw_Loop RBRANCH 543 544 :Process_String_Next 545 420040f9 # LDR_X2_[X2] ; I = I->NEXT 546 5f0000f1 # CMP_X2_TO_0 ; IF NULL == I 547 40000054 # SKIP_INST_EQ ; Otherwise keep looping 548 ^~Process_String_loop 17 # ^~Process_String_loop RBRANCH 549 550 fe0741f8 # POP_LR 551 e30741f8 # POP_X3 ; Restore X3 552 e20741f8 # POP_X2 ; Restore X2 553 e10741f8 # POP_X1 ; Restore X1 554 e00741f8 # POP_X0 ; Restore X0 555 c0035fd6 # RETURN 556 557 558 ; string_length function 559 ; Receives CHAR* in X0 560 ; Returns INT in X0 561 ; Uses X0 for CH, X1 for S and X2 for INDEX 562 :string_length 563 e10f1ff8 # PUSH_X1 ; Protect X1 564 e20f1ff8 # PUSH_X2 ; Protect X2 565 e10300aa # SET_X1_FROM_X0 ; Set S 566 020080d2 # SET_X2_TO_0 ; INDEX = 0 567 :string_length_loop 568 20686238 # LDR_BYTE_W0_[X1,X2] ; S[INDEX] 569 1f0000f1 # CMP_X0_TO_0 ; IF NULL == S[INDEX] 570 41000054 # SKIP_INST_NE ; Stop 571 ^~string_length_done 14 # ^~string_length_done FBRANCH 572 573 42040091 # ADD_X2_X2_1 ; INDEX = INDEX + 1 574 ^~string_length_loop 17 # ^~string_length_loop RBRANCH ; Keep going 575 576 :string_length_done 577 e00302aa # SET_X0_FROM_X2 ; RETURN INDEX 578 e20741f8 # POP_X2 ; Restore X2 579 e10741f8 # POP_X1 ; Restore X1 580 c0035fd6 # RETURN 581 582 583 ; Eval_Immediates function 584 ; Receives List in X0 585 ; Updates the list in place; does not modify registers 586 ; Uses X1 for I->TEXT[0], X2 for I->TEXT[1] and X3 for I 587 :Eval_Immediates 588 e00f1ff8 # PUSH_X0 ; Protect X0 589 e10f1ff8 # PUSH_X1 ; Protect X1 590 e20f1ff8 # PUSH_X2 ; Protect X2 591 e30f1ff8 # PUSH_X3 ; Protect X3 592 fe0f1ff8 # PUSH_LR 593 e30300aa # SET_X3_FROM_X0 ; I = HEAD 594 :Eval_Immediates_Loop 595 ; Check for MACRO 596 600440f9 # LDR_X0_[X3,8] ; I->TYPE 597 1f0400f1 # CMP_X0_TO_1 ; IF MACRO == I-TYPE 598 41000054 # SKIP_INST_NE ; Skip to next 599 ^~Eval_Immediates_Next 14 # ^~Eval_Immediates_Next FBRANCH 600 601 ; Check for NULL EXPRESSION 602 600c40f9 # LDR_X0_[X3,24] ; I->EXPRESSION 603 1f0000f1 # CMP_X0_TO_0 ; IF NULL == I->EXPRESSION 604 40000054 # SKIP_INST_EQ ; Skip to next 605 ^~Eval_Immediates_Next 14 # ^~Eval_Immediates_Next FBRANCH 606 607 ; Check if number 608 600840f9 # LDR_X0_[X3,16] ; I->TEXT 609 01144038 # LDR_BYTE_W1_[X0]_1 ; I->TEXT[0] 610 02004039 # LDR_BYTE_W2_[X0] ; I->TEXT[1] 611 ^~numerate_string 94 # ^~numerate_string FCALL ; Convert string to INT 612 1f0000f1 # CMP_X0_TO_0 ; IF 0 == numerate_number(I->TEXT + 1) 613 40000054 # SKIP_INST_EQ ; Has a value 614 ^~Eval_Immediates_value 14 # ^~Eval_Immediates_value FBRANCH 615 616 ; Last chance for Immediate 617 5fc000f1 # CMP_X2_TO_48 ; If '0' == I->TEXT[1] 618 40000054 # SKIP_INST_EQ ; Skip to next 619 ^~Eval_Immediates_Next 14 # ^~Eval_Immediates_Next FBRANCH 620 621 :Eval_Immediates_value 622 ^~express_number 94 # ^~express_number FCALL ; Convert value to hex string 623 600c00f9 # STR_X0_[X3,24] ; I->EXPRESSION = express_number(value, I-TEXT[0]) 624 625 :Eval_Immediates_Next 626 630040f9 # LDR_X3_[X3] ; I = I->NEXT 627 7f0000f1 # CMP_X3_TO_0 ; IF NULL == I 628 40000054 # SKIP_INST_EQ ; Otherwise keep looping 629 ^~Eval_Immediates_Loop 17 # ^~Eval_Immediates_Loop RBRANCH 630 631 fe0741f8 # POP_LR 632 e30741f8 # POP_X3 ; Restore X3 633 e20741f8 # POP_X2 ; Restore X2 634 e10741f8 # POP_X1 ; Restore X1 635 e00741f8 # POP_X0 ; Restore X0 636 c0035fd6 # RETURN 637 638 639 ; numerate_string function 640 ; Receives CHAR* in X0 641 ; Returns value of CHAR* in X0 642 ; Uses X0 for VALUE, X1 for S, X2 for CH and X4 for NEGATIVE? 643 :numerate_string 644 e10f1ff8 # PUSH_X1 ; Protect X1 645 e20f1ff8 # PUSH_X2 ; Protect X2 646 e30f1ff8 # PUSH_X3 ; Protect X3 647 e40f1ff8 # PUSH_X4 648 e10300aa # SET_X1_FROM_X0 ; put S in correct place 649 000080d2 # SET_X0_TO_0 ; Initialize to Zero 650 :numerate_string_loop 651 22044039 # LDR_BYTE_W2_[X1,1] ; S[1] 652 5fe001f1 # CMP_X2_TO_120 ; IF 'x' == S[1] 653 41000054 # SKIP_INST_NE ; Deal with hex input 654 ^~numerate_hex 14 # ^~numerate_hex FBRANCH 655 656 ; Assume decimal input 657 040080d2 # SET_X4_TO_0 ; Assume no negation 658 22004039 # LDR_BYTE_W2_[X1] ; S[0] 659 5fb400f1 # CMP_X2_TO_45 ; IF '-' == S[0] 660 40000054 # SKIP_INST_EQ ; Skip negation 661 ^~numerate_decimal 14 # ^~numerate_decimal FBRANCH 662 663 240080d2 # SET_X4_TO_1 ; Set FLAG 664 21040091 # ADD_X1_X1_1 ; S = S + 1 665 666 :numerate_decimal 667 22004039 # LDR_BYTE_W2_[X1] ; S[0] 668 5f0000f1 # CMP_X2_TO_0 ; IF NULL == S[0] 669 41000054 # SKIP_INST_NE ; We are done 670 ^~numerate_decimal_done 14 # ^~numerate_decimal_done FBRANCH 671 672 e10f1ff8 # PUSH_X1 673 410180d2 # SET_X1_TO_10 674 007c019b # MUL_X0_X0_X1 ; VALUE = VALUE * 10 675 e10741f8 # POP_X1 676 677 42c000d1 # SUB_X2_X2_48 ; CH = CH - '0' 678 5f2400f1 # CMP_X2_TO_9 ; Check for illegal 679 4d000054 # SKIP_INST_LE ; If CH > '9' 680 ^~numerate_string_fail 14 # ^~numerate_string_fail FBRANCH 681 5f0000f1 # CMP_X2_TO_0 ; Check for illegal 682 4a000054 # SKIP_INST_GE ; IF CH < 0 683 ^~numerate_string_fail 14 # ^~numerate_string_fail FBRANCH 684 0000028b # ADD_X0_X0_X2 ; VALUE = VALUE + CH 685 21040091 # ADD_X1_X1_1 ; S = S + 1 686 ^~numerate_decimal 17 # ^~numerate_decimal RBRANCH ; Keep looping 687 688 :numerate_decimal_done 689 9f0400f1 # CMP_X4_TO_1 ; Check if need to negate 690 40000054 # SKIP_INST_EQ ; Nope 691 ^~numerate_string_done 14 # ^~numerate_string_done FBRANCH 692 693 e00300cb # NEG_X0_X0 ; VALUE = VALUE * -1 694 ^~numerate_string_done 14 # ^~numerate_string_done FBRANCH ; Done 695 696 :numerate_hex 697 21080091 # ADD_X1_X1_2 ; S = S + 2 698 :numerate_hex_loop 699 22004039 # LDR_BYTE_W2_[X1] ; S[0] 700 5f0000f1 # CMP_X2_TO_0 ; IF NULL == S[0] 701 41000054 # SKIP_INST_NE ; We are done 702 ^~numerate_string_done 14 # ^~numerate_string_done FBRANCH 703 704 00ec7cd3 # LSL_X0_X0_4 ; VALUE = VALUE << 4 705 42c000d1 # SUB_X2_X2_48 ; CH = CH - '0' 706 5f2800f1 # CMP_X2_TO_10 ; IF 10 >= CH 707 4a000054 # SKIP_INST_GE ; NO 708 ^~numerate_hex_digit 14 # ^~numerate_hex_digit FBRANCH 709 421c00d1 # SUB_X2_X2_7 ; Push A-F into range 710 :numerate_hex_digit 711 5f3c00f1 # CMP_X2_TO_15 ; Check for illegal 712 4d000054 # SKIP_INST_LE ; If CH > 'F' 713 ^~numerate_string_fail 14 # ^~numerate_string_fail FBRANCH 714 5f0000f1 # CMP_X2_TO_0 ; Check for illegal 715 4a000054 # SKIP_INST_GE ; IF CH < 0 716 ^~numerate_string_fail 14 # ^~numerate_string_fail FBRANCH 717 0000028b # ADD_X0_X0_X2 ; VALUE = VALUE + CH 718 21040091 # ADD_X1_X1_1 ; S = S + 1 719 ^~numerate_hex_loop 17 # ^~numerate_hex_loop RBRANCH ; Keep looping 720 721 :numerate_string_fail 722 000080d2 # SET_X0_TO_0 ; Return ZERO 723 724 :numerate_string_done 725 e40741f8 # POP_X4 ; Restore X4 726 e30741f8 # POP_X3 ; Restore X3 727 e20741f8 # POP_X2 ; Restore X2 728 e10741f8 # POP_X1 ; Restore X1 729 c0035fd6 # RETURN 730 731 732 ; express_number function 733 ; Receives INT in X0 and CHAR in X1 734 ; Allocates a string and expresses the value in hex 735 ; Returns string in X0 736 ; Uses X0 for VALUE, X1 for S and X2 for CH 737 :express_number 738 e10f1ff8 # PUSH_X1 ; Protect X1 739 e20f1ff8 # PUSH_X2 ; Protect X2 740 e30f1ff8 # PUSH_X3 ; Protect X3 741 fe0f1ff8 # PUSH_LR 742 743 e20301aa # SET_X2_FROM_X1 ; Put CH in right place 744 e10300aa # SET_X1_FROM_X0 ; Protect VALUE 745 5f9400f1 # CMP_X2_TO_37 ; IF '%' == CH 746 40000054 # SKIP_INST_EQ ; Otherwise try @ 747 ^~express_number2 14 # ^~express_number2 FBRANCH 748 749 200180d2 # SET_X0_TO_9 ; We need 9bytes 750 ^~malloc 97 # ^~malloc RCALL ; Get S pointer 751 e30300aa # SET_X3_FROM_X0 ; Put S and VALUE in place 752 e00301aa # SET_X0_FROM_X1 753 e10303aa # SET_X1_FROM_X3 754 e10f1ff8 # PUSH_X1 ; Protect S 755 ^~hex32l 94 # ^~hex32l FCALL ; Store 32bits 756 ^~express_number_done 14 # ^~express_number_done FBRANCH ; done 757 758 :express_number2 759 5f0001f1 # CMP_X2_TO_64 ; IF '@' == CH 760 40000054 # SKIP_INST_EQ ; Othrewise try ! 761 ^~express_number1 14 # ^~express_number1 FBRANCH 762 763 a00080d2 # SET_X0_TO_5 ; We need 5bytes 764 ^~malloc 97 # ^~malloc RCALL ; Get S pointer 765 e30300aa # SET_X3_FROM_X0 ; Put S and VALUE in place 766 e00301aa # SET_X0_FROM_X1 767 e10303aa # SET_X1_FROM_X3 768 e10f1ff8 # PUSH_X1 ; Protect S 769 ^~hex16l 94 # ^~hex16l FCALL ; Store 16bits 770 ^~express_number_done 14 # ^~express_number_done FBRANCH ; done 771 772 :express_number1 773 600080d2 # SET_X0_TO_3 ; We need 3bytes 774 ^~malloc 97 # ^~malloc RCALL ; Get S pointer 775 e30300aa # SET_X3_FROM_X0 ; Put S and VALUE in place 776 e00301aa # SET_X0_FROM_X1 777 e10303aa # SET_X1_FROM_X3 778 e10f1ff8 # PUSH_X1 ; Protect S 779 ^~hex8 94 # ^~hex8 FCALL ; Store 8bit 780 781 :express_number_done 782 e00741f8 # POP_X0 ; Restore S 783 fe0741f8 # POP_LR 784 e30741f8 # POP_X3 ; Restore X3 785 e20741f8 # POP_X2 ; Restore X2 786 e10741f8 # POP_X1 ; Restore X1 787 c0035fd6 # RETURN 788 789 790 ; HEX to ascii routine 791 ; Receives INT in X0 and CHAR* in X1 792 ; Stores ascii of INT in CHAR* 793 ; Returns only modifying X0 794 :hex64l 795 fe0f1ff8 # PUSH_LR 796 e00f1ff8 # PUSH_X0 ; Protect top 32 797 ^~hex32l 94 # ^~hex32l FCALL ; Store it 798 e00741f8 # POP_X0 ; do top 32 799 00fc60d3 # LSR_X0_X0_32 ; do bottom 32 first 800 ^~hex32l 94 # ^~hex32l FCALL 801 fe0741f8 # POP_LR 802 c0035fd6 # RETURN 803 804 :hex32l 805 fe0f1ff8 # PUSH_LR 806 e00f1ff8 # PUSH_X0 ; Protect top 16 807 ^~hex16l 94 # ^~hex16l FCALL ; Store it 808 e00741f8 # POP_X0 ; do top 16 809 00fc50d3 # LSR_X0_X0_16 ; do bottom 16 first 810 ^~hex16l 94 # ^~hex16l FCALL 811 fe0741f8 # POP_LR 812 c0035fd6 # RETURN 813 814 :hex16l 815 fe0f1ff8 # PUSH_LR 816 e00f1ff8 # PUSH_X0 ; Protect top byte 817 ^~hex8 94 # ^~hex8 FCALL ; Store it 818 e00741f8 # POP_X0 ; do high byte 819 00fc48d3 # LSR_X0_X0_8 ; do bottom byte first 820 ^~hex8 94 # ^~hex8 FCALL 821 fe0741f8 # POP_LR 822 c0035fd6 # RETURN 823 824 :hex8 825 fe0f1ff8 # PUSH_LR 826 e00f1ff8 # PUSH_X0 ; Protect bottom nibble 827 00fc44d3 # LSR_X0_X0_4 ; do high nibble first 828 ^~hex4 94 # ^~hex4 FCALL ; Store it 829 e00741f8 # POP_X0 ; do low nibble 830 ^~hex4 94 # ^~hex4 FCALL 831 fe0741f8 # POP_LR 832 c0035fd6 # RETURN 833 834 :hex4 835 000c4092 # AND_X0_X0_0xF ; isolate nibble 836 00c00091 # ADD_X0_X0_48 ; convert to ascii 837 1fe400f1 # CMP_X0_TO_57 ; valid digit? 838 4c000054 # SKIP_INST_GT ; yes 839 ^~hex1 14 # ^~hex1 FBRANCH 840 001c0091 # ADD_X0_X0_7 ; use alpha range 841 :hex1 842 20140038 # STR_BYTE_W0_[X1]_1 ; store result 843 c0035fd6 # RETURN 844 845 846 ; Preserve_Other function 847 ; Receives List in X0 848 ; Updates the list in place; does not modify registers 849 ; Uses X0 for I, X1 for I->TEXT 850 :Preserve_Other 851 e00f1ff8 # PUSH_X0 ; Protect X0 852 e10f1ff8 # PUSH_X1 ; Protect X1 853 e20f1ff8 # PUSH_X2 ; Protect X2 854 e30f1ff8 # PUSH_X3 ; Protect X3 855 :Preserve_Other_Loop 856 010c40f9 # LDR_X1_[X0,24] ; I->EXPRESSION 857 3f0000f1 # CMP_X1_TO_0 ; IF NULL == I->EXPRESSION 858 40000054 # SKIP_INST_EQ ; Otherwise next 859 ^~Preserve_Other_Next 14 # ^~Preserve_Other_Next FBRANCH 860 861 ; Needs preserving 862 010840f9 # LDR_X1_[X0,16] ; I->TEXT 863 010c00f9 # STR_X1_[X0,24] ; I->EXPRESSION = I->TEXT 864 865 :Preserve_Other_Next 866 000040f9 # LDR_X0_[X0] ; I = I->NEXT 867 1f0000f1 # CMP_X0_TO_0 ; IF NULL == I 868 40000054 # SKIP_INST_EQ ; Otherwise keep looping 869 ^~Preserve_Other_Loop 17 # ^~Preserve_Other_Loop RBRANCH 870 871 e30741f8 # POP_X3 ; Restore X3 872 e20741f8 # POP_X2 ; Restore X2 873 e10741f8 # POP_X1 ; Restore X1 874 e00741f8 # POP_X0 ; Restore X0 875 c0035fd6 # RETURN 876 877 878 ; Print_Hex function 879 ; Receives list in X0 880 ; walks the list and prints the I->EXPRESSION for all nodes followed by newline 881 ; Uses X1 for I 882 :Print_Hex 883 e10f1ff8 # PUSH_X1 ; Protect X1 884 e20f1ff8 # PUSH_X2 ; Protect X2 885 fe0f1ff8 # PUSH_LR 886 e1030daa # SET_X1_FROM_X13 ; I = Head 887 :Print_Hex_Loop 888 200440f9 # LDR_X0_[X1,8] ; I->TYPE 889 1f0400f1 # CMP_X0_TO_1 ; IF MACRO == I->TYPE 890 41000054 # SKIP_INST_NE ; Skip 891 ^~Print_Hex_Next 14 # ^~Print_Hex_Next FBRANCH 892 893 200c40f9 # LDR_X0_[X1,24] ; Using EXPRESSION 894 ^~File_Print 94 # ^~File_Print FCALL ; Print it 895 400180d2 # SET_X0_TO_10 ; NEWLINE 896 ^~fputc 94 # ^~fputc FCALL ; Append it 897 898 :Print_Hex_Next 899 210040f9 # LDR_X1_[X1] ; Iterate to next Token 900 3f0000f1 # CMP_X1_TO_0 ; Check for NULL 901 40000054 # SKIP_INST_EQ ; Otherwise keep looping 902 ^~Print_Hex_Loop 17 # ^~Print_Hex_Loop RBRANCH 903 904 fe0741f8 # POP_LR 905 e20741f8 # POP_X2 ; Restore X2 906 e10741f8 # POP_X1 ; Restore X1 907 c0035fd6 # RETURN 908 909 910 ; File_Print function 911 ; Receives CHAR* in X0 912 ; calls fputc for every non-null char 913 :File_Print 914 e10f1ff8 # PUSH_X1 ; Protect X1 915 e20f1ff8 # PUSH_X2 ; Protect X2 916 fe0f1ff8 # PUSH_LR 917 e10300aa # SET_X1_FROM_X0 ; Protect S 918 1f0000f1 # CMP_X0_TO_0 ; Protect against nulls 919 41000054 # SKIP_INST_NE ; Simply don't try to print them 920 ^~File_Print_Done 14 # ^~File_Print_Done FBRANCH 921 :File_Print_Loop 922 20004039 # LDR_BYTE_W0_[X1] ; Read byte 923 1f0000f1 # CMP_X0_TO_0 ; Check for NULL 924 41000054 # SKIP_INST_NE ; Stop at NULL 925 ^~File_Print_Done 14 # ^~File_Print_Done FBRANCH 926 927 ^~fputc 94 # ^~fputc FCALL ; write it 928 21040091 # ADD_X1_X1_1 ; S = S + 1 929 ^~File_Print_Loop 17 # ^~File_Print_Loop RBRANCH ; Keep going 930 931 :File_Print_Done 932 fe0741f8 # POP_LR 933 e20741f8 # POP_X2 ; Restore X2 934 e10741f8 # POP_X1 ; Restore X1 935 c0035fd6 # RETURN 936 937 938 ; fputc function 939 ; receives CHAR in X0 and FILE* in X14 940 ; writes char and Returns 941 :fputc 942 e10f1ff8 # PUSH_X1 943 e20f1ff8 # PUSH_X2 944 945 e00f1ff8 # PUSH_X0 ; We are writing x0 946 e1030091 # SET_X1_FROM_SP ; Get stack address 947 e0030eaa # SET_X0_FROM_X14 ; Write to target file 948 080880d2 # SET_X8_TO_SYS_WRITE ; the syscall number for write 949 220080d2 # SET_X2_TO_1 ; set the size of chars we want 950 951 010000d4 # SYSCALL ; call the Kernel 952 953 e00741f8 # POP_X0 ; Restore stack 954 e20741f8 # POP_X2 ; Restore X3 955 e10741f8 # POP_X1 956 c0035fd6 # RETURN 957 958 :ELF_end