hex2.hex1 (24767B)
1 # SPDX-FileCopyrightText: 2016 Jeremiah Orians <jeremiah@pdp10.guru> 2 # SPDX-FileCopyrightText: 2017 Jan Nieuwenhuizen <janneke@gnu.org> 3 # 4 # SPDX-License-Identifier: GPL-3.0-or-later 5 6 ## ELF Header 7 # :ELF_base 8 7F 45 4C 46 ## e_ident[EI_MAG0-3] ELF's magic number 9 10 02 ## e_ident[EI_CLASS] Indicating 64 bit 11 01 ## e_ident[EI_DATA] Indicating little endianness 12 01 ## e_ident[EI_VERSION] Indicating original elf 13 14 03 ## e_ident[EI_OSABI] Set at 3 because FreeBSD is strict 15 00 ## e_ident[EI_ABIVERSION] Set at 0 because none cares 16 17 00 00 00 00 00 00 00 ## e_ident[EI_PAD] 18 02 00 ## e_type Indicating Executable 19 3E 00 ## e_machine Indicating AMD64 20 01 00 00 00 ## e_version Indicating original elf 21 22 78 00 60 00 00 00 00 00 ## e_entry Address of the entry point (Number of bytes this header is + Base Address) 23 40 00 00 00 00 00 00 00 ## e_phoff Address of program header table 24 00 00 00 00 00 00 00 00 ## e_shoff Address of section header table 25 26 00 00 00 00 ## e_flags 27 40 00 ## e_ehsize Indicating our 64 Byte header 28 29 38 00 ## e_phentsize size of a program header table 30 01 00 ## e_phnum number of entries in program table 31 32 00 00 ## e_shentsize size of a section header table 33 00 00 ## e_shnum number of entries in section table 34 35 00 00 ## e_shstrndx index of the section names 36 37 ## Program Header 38 # :ELF_program_headers 39 01 00 00 00 ## p_type 40 07 00 00 00 ## ph_flags: PF-X|PF-W|PF-R = 7 41 00 00 00 00 00 00 00 00 ## p_offset 42 43 00 00 60 00 00 00 00 00 ## p_vaddr 44 00 00 60 00 00 00 00 00 ## p_physaddr 45 46 EF 05 00 00 00 00 00 00 ## p_filesz 47 EF 05 00 00 00 00 00 00 ## p_memsz 48 49 01 00 00 00 00 00 00 00 ## Required alignment 50 51 # :ELF_text 52 53 # Where the ELF Header is going to hit 54 # Simply jump to _start 55 # Our main function 56 57 # Register usage: 58 # RAX, RDX, RSI, RDI => Temps 59 # R15 => Flag 60 # R14 => High bits 61 # R13 => IP 62 # R12 => MALLOC 63 # R11 => HEAD 64 65 # Struct format: (size 24) 66 # NEXT => 0 67 # TARGET => 8 68 # NAME => 16 69 70 # :_start 71 48C7C7 00000000 ; mov_rdi, %0 # Get current pointer 72 E8 %w ; call %malloc # Get current HEAP 73 4889C7 ; mov_rdi,rax # Using current 74 4989C4 ; mov_r12,rax # Setup MALLOC 75 4881C7 00008000 ; add_rdi, %8388608 # Create space for temp [8MB] 76 E8 %w ; call %malloc # Give ourselves 8192000 bytes to work with 77 78 4C8925 %T ; mov_[rip+DWORD],r12 %scratch # Allocate space for scratch area 79 4981C4 00080000 ; add_r12, %0x800 # 2 KiB of scratch 80 81 58 ; pop_rax # Get the number of arguments 82 5F ; pop_rdi # Get the program name 83 5F ; pop_rdi # Get the actual input name 84 48C7C6 00000000 ; mov_rsi, %0 # prepare read_only 85 48C7C0 02000000 ; mov_rax, %2 # the syscall number for open() 86 0F05 ; syscall # Now open that damn file 87 4989C1 ; mov_r9,rax # Preserve the file pointer we were given 88 89 5F ; pop_rdi # Get the actual output name 90 48C7C6 41020000 ; mov_rsi, %577 # Prepare file as O_WRONLY|O_CREAT|O_TRUNC 91 48C7C2 C0010000 ; mov_rdx, %448 # Prepare file as RWX for owner only (700 in octal) 92 48C7C0 02000000 ; mov_rax, %2 # the syscall number for open() 93 0F05 ; syscall # Now open that damn file 94 4883F8 00 ; cmp_rax, !0 # Check for missing output 95 0F8F %R ; jg %_start_out # Have real input 96 48C7C0 01000000 ; mov_rax, %1 # Use stdout 97 98 :R # :_start_out 99 4989C2 ; mov_r10,rax # Preserve the file pointer we were given 100 101 E8 %H ; call %ClearScratch # Zero scratch 102 49C7C7 FFFFFFFF ; mov_r15, %-1 # Our flag for byte processing 103 49C7C6 00000000 ; mov_r14, %0 # temp storage for the sum 104 49C7C5 00006000 ; mov_r13, %0x00600000 # Our starting IP 105 49C7C3 00000000 ; mov_r11, %0 # HEAD = NULL 106 E8 %a ; call %First_pass # Process it 107 108 # rewind input file 109 4C89CF ; mov_rdi,r9 # Using our input file 110 48C7C6 00000000 ; mov_rsi, %0 # Offset Zero 111 48C7C2 00000000 ; mov_rdx, %0 # Whence Zero 112 48C7C0 08000000 ; mov_rax, %8 # lseek 113 4153 ; push_r11 # Protect HEAD 114 0F05 ; syscall 115 415B ; pop_r11 # Restore HEAD 116 117 49C7C7 FFFFFFFF ; mov_r15, %-1 # Our flag for byte processing 118 49C7C6 00000000 ; mov_r14, %0 # temp storage for the sum 119 49C7C5 00006000 ; mov_r13, %0x00600000 # Our starting IP 120 E8 %k ; call %Second_pass # Process it 121 122 E9 %v ; jmp %Done 123 124 :a # :First_pass 125 E8 %x ; call %Read_byte 126 127 # Deal with EOF 128 4883F8 FC ; cmp_rax, !-4 129 0F84 %i ; je %First_pass_done 130 131 # Check for : 132 4883F8 3A ; cmp_rax, !0x3A 133 0F85 %b ; jne %First_pass_0 134 135 # Deal with label 136 E9 %C ; jmp %StoreLabel 137 138 :b # :First_pass_0 139 # Check for ! 140 4883F8 21 ; cmp_rax, !0x21 141 0F84 %h ; je %First_pass_pointer 142 143 # Check for @ 144 4883F8 40 ; cmp_rax, !0x40 145 0F84 %h ; je %First_pass_pointer 146 147 # Check for $ 148 4883F8 24 ; cmp_rax, !0x24 149 0F84 %h ; je %First_pass_pointer 150 151 # Check for % 152 4883F8 25 ; cmp_rax, !0x25 153 0F84 %h ; je %First_pass_pointer 154 155 # Check for & 156 4883F8 26 ; cmp_rax, !0x26 157 0F84 %h ; je %First_pass_pointer 158 159 # Deal with everything else 160 E8 %j ; call %hex # Process our char 161 162 # Deal with EOF 163 4883F8 FC ; cmp_rax, !-4 164 0F84 %i ; je %First_pass_done 165 166 # deal with -1 values 167 4883F8 00 ; cmp_rax, !0 168 0F8C %a ; jl %First_pass 169 170 # deal with toggle 171 4983FF 00 ; cmp_r15, !0 172 0F84 %c ; je %First_pass_1 173 4983C5 01 ; add_r13, !1 # Increment IP 174 175 :c # :First_pass_1 176 49F7D7 ; not_r15 177 E9 %a ; jmp %First_pass 178 179 :d # :Update_Pointer 180 # Check for ! 181 4883F8 21 ; cmp_rax, !0x21 182 0F84 %g ; je %Update_Pointer_1 183 184 # Check for @ 185 4883F8 40 ; cmp_rax, !0x40 186 0F84 %f ; je %Update_Pointer_2 187 188 # Check for $ 189 4883F8 24 ; cmp_rax, !0x24 190 0F84 %f ; je %Update_Pointer_2 191 192 # Check for % 193 4883F8 25 ; cmp_rax, !0x25 194 0F84 %e ; je %Update_Pointer_4 195 196 # Check for & 197 4883F8 26 ; cmp_rax, !0x26 198 0F84 %e ; je %Update_Pointer_4 199 200 # deal with bad input 201 E8 %Q # call %fail 202 203 :e # :Update_Pointer_4 204 4983C5 02 ; add_r13, !2 # Increment IP 205 :f # :Update_Pointer_2 206 4983C5 01 ; add_r13, !1 # Increment IP 207 :g # :Update_Pointer_1 208 4983C5 01 ; add_r13, !1 # Increment IP 209 C3 ; ret 210 211 :h # :First_pass_pointer 212 # Deal with Pointer to label 213 E8 %d ; call %Update_Pointer # Increment IP 214 488B1D %T ; mov_rbx,[rip+DWORD] %scratch # Using scratch 215 E8 %A ; call %consume_token # Read token 216 E8 %H ; call %ClearScratch # Throw away token 217 4883F8 3E ; cmp_rax, !0x3E # check for '>' 218 0F85 %a ; jne %First_pass # Loop again 219 220 # Deal with %label>label case 221 488B1D %T ; mov_rbx,[rip+DWORD] %scratch # Write to scratch 222 E8 %A ; call %consume_token # get token 223 E8 %H ; call %ClearScratch # Clean up after ourselves 224 E9 %a ; jmp %First_pass # Loop again 225 226 :i # :First_pass_done 227 C3 ; ret 228 229 :j # :hex 230 # deal with EOF 231 4883F8 FC ; cmp_rax, !-4 232 0F84 %n ; je %EOF 233 # deal with line comments starting with # 234 4883F8 23 ; cmp_rax, !0x23 235 0F84 %s ; je %ascii_comment 236 # deal with line comments starting with ; 237 4883F8 3B ; cmp_rax, !0x3B 238 0F84 %s ; je %ascii_comment 239 # deal all ascii less than 0 240 4883F8 30 ; cmp_rax, !0x30 241 0F8C %r ; jl %ascii_other 242 # deal with 0-9 243 4883F8 3A ; cmp_rax, !0x3A 244 0F8C %o ; jl %ascii_num 245 # deal with all ascii less than A 246 4883F8 41 ; cmp_rax, !0x41 247 0F8C %r ; jl %ascii_other 248 # deal with A-F 249 4883F8 47 ; cmp_rax, !0x47 250 0F8C %q ; jl %ascii_high 251 # deal with all ascii less than a 252 4883F8 61 ; cmp_rax, !0x61 253 0F8C %r ; jl %ascii_other 254 # deal with a-f 255 4883F8 67 ; cmp_rax, !0x67 256 0F8C %p ; jl %ascii_low 257 # The rest that remains needs to be ignored 258 E9 %r ; jmp %ascii_other 259 260 :k # :Second_pass 261 E8 %x ; call %Read_byte 262 263 # Deal with EOF 264 4883F8 FC ; cmp_rax, !-4 265 0F84 %m ; je %Second_pass_done 266 267 # Simply drop the label 268 4883F8 3A ; cmp_rax, !0x3A 269 0F85 %l ; jne %Second_pass_0 270 271 488B1D %T ; mov_rbx,[rip+DWORD] %scratch # Using scratch 272 E8 %A ; call %consume_token # Read token 273 E8 %H ; call %ClearScratch # Throw away token 274 275 E9 %k ; jmp %Second_pass 276 277 :l # :Second_pass_0 278 # Deal with % pointer 279 4883F8 25 ; cmp_rax, !0x25 280 0F84 %L ; je %StorePointer_rel4 281 282 # Deal with @ pointer 283 4883F8 40 ; cmp_rax, !0x40 284 0F84 %M ; je %StorePointer_rel2 285 286 # Deal with ! pointer 287 4883F8 21 ; cmp_rax, !0x21 288 0F84 %N ; je %StorePointer_rel1 289 290 # Deal with & pointer 291 4883F8 26 ; cmp_rax, !0x26 292 0F84 %O ; je %StorePointer_abs4 293 294 # Deal with $ pointer 295 4883F8 24 ; cmp_rax, !0x24 296 0F84 %P ; je %StorePointer_abs2 297 298 # :Second_pass_1 299 # Deal with everything else 300 E8 %j ; call %hex # Process our char 301 302 # Deal with EOF 303 4883F8 FC ; cmp_rax, !-4 304 0F84 %m ; je %Second_pass_done 305 306 # deal with -1 values 307 4883F8 00 ; cmp_rax, !0 308 0F8C %k ; jl %Second_pass 309 310 # deal with toggle 311 4983FF 00 ; cmp_r15, !0 312 0F84 %u ; je %print 313 314 # process first byte of pair 315 4989C6 ; mov_r14,rax 316 49C7C7 00000000 ; mov_r15, %0 317 E9 %k ; jmp %Second_pass 318 319 :m # :Second_pass_done 320 :n # :EOF 321 C3 ; ret 322 323 :o # :ascii_num 324 83E8 30 ; sub_rax, !0x30 325 C3 ; ret 326 :p # :ascii_low 327 83E8 57 ; sub_rax, !0x57 328 C3 ; ret 329 :q # :ascii_high 330 83E8 37 ; sub_rax, !0x37 331 C3 ; ret 332 :r # :ascii_other 333 48C7C0 FFFFFFFF ; mov_rax, %-1 334 C3 ; ret 335 :s # :ascii_comment 336 E8 %x ; call %Read_byte 337 4883F8 0D ; cmp_rax, !0x0D 338 0F84 %t ; je %ascii_comment_cr 339 4883F8 0A ; cmp_rax, !0x0A 340 0F85 %s ; jne %ascii_comment 341 :t # :ascii_comment_cr 342 48C7C0 FFFFFFFF ; mov_rax, %-1 343 C3 ; ret 344 345 # process second byte of pair 346 :u # :print 347 # update the sum and store in output 348 49C1E6 04 ; shl_r14, !4 349 4C01F0 ; add_rax,r14 350 351 # flip the toggle 352 49F7D7 ; not_r15 353 354 # Print our first Hex 355 48C7C2 01000000 ; mov_rdx, %1 # set the size of chars we want 356 E8 %z ; call %print_chars 357 358 4983C5 01 ; add_r13, !1 # Increment IP 359 E9 %k ; jmp %Second_pass 360 361 :v # :Done 362 # program completed Successfully 363 48C7C7 00000000 ; mov_rdi, %0 # All is well 364 48C7C0 3C000000 ; mov_rax, %0x3C # put the exit syscall number in eax 365 0F05 ; syscall # Call it a good day 366 367 368 # Malloc isn't actually required if the program being built fits in the initial memory 369 # However, it doesn't take much to add it. 370 # Requires a value in RDI 371 :w # :malloc 372 48C7C0 0C000000 ; mov_rax, %12 # the Syscall # for SYS_BRK 373 4153 ; push_r11 # Protect r11 374 0F05 ; syscall # call the Kernel 375 415B ; pop_r11 # Restore r11 376 C3 ; ret 377 378 379 :x # :Read_byte 380 # Attempt to read 1 byte from STDIN 381 48C7C2 01000000 ; mov_rdx, %1 # set the size of chars we want 382 488D35 %S ; lea_rsi,[rip+DWORD] %write # Where to put it 383 4C89CF ; mov_rdi,r9 # Where are we reading from 384 48C7C0 00000000 ; mov_rax, %0 # the syscall number for read 385 4153 ; push_r11 # Protect r11 386 0F05 ; syscall # call the Kernel 387 415B ; pop_r11 # Restore r11 388 389 4885C0 ; test_rax,rax # check what we got 390 0F84 %y ; je %Read_byte_1 # Got EOF call it done 391 392 # load byte 393 8A05 %S ; mov_al,[rip+DWORD] %write # load char 394 480FB6C0 ; movzx_rax,al # We have to zero extend it to use it 395 C3 ; ret 396 397 # Deal with EOF 398 :y # :Read_byte_1 399 48C7C0 FCFFFFFF ; mov_rax, %-4 # Put EOF in rax 400 C3 ; ret 401 402 :z # :print_chars 403 50 ; push_rax # Push address of chars onto stack 404 4889E6 ; mov_rsi,rsp # What we are writing 405 4C89D7 ; mov_rdi,r10 # Write to target file 406 48C7C0 01000000 ; mov_rax, %1 # the syscall number for write 407 4153 ; push_r11 # Protect HEAD 408 0F05 ; syscall # call the Kernel 409 415B ; pop_r11 # Restore HEAD 410 58 ; pop_rax # deallocate stack 411 C3 ; ret 412 413 # Receives pointer in RBX 414 # Writes out char and updates RBX 415 :A # :consume_token 416 E8 %x ; call %Read_byte # Consume_token 417 418 # Check for \t 419 4883F8 09 ; cmp_rax, !0x09 420 0F84 %B ; je %consume_token_done 421 422 # Check for \n 423 4883F8 0A ; cmp_rax, !0x0A 424 0F84 %B ; je %consume_token_done 425 426 # Check for ' ' 427 4883F8 20 ; cmp_rax, !0x20 428 0F84 %B ; je %consume_token_done 429 430 # Check for '>' 431 4883F8 3E ; cmp_rax, !0x3E 432 0F84 %B ; je %consume_token_done 433 434 # Looks like we are still reading token 435 8803 ; mov_[rbx],al # Store char 436 4883C3 01 ; add_rbx, !1 # Point to next spot 437 E9 %A ; jmp %consume_token # loop until done 438 439 :B # :consume_token_done 440 48C7C1 00000000 ; mov_rcx, %0 # Pad with nulls 441 48890B ; mov_[rbx],rcx 442 4883C3 08 ; add_rbx, !8 443 C3 ; ret 444 445 :C # :StoreLabel 446 4C89E0 ; mov_rax,r12 # ENTRY 447 4981C4 18000000 ; add_r12, %24 # CALLOC 448 4C8968 08 ; mov_[rax+BYTE],r13 !8 # ENTRY->TARGET = IP 449 4C8918 ; mov_[rax],r11 # ENTRY->NEXT = JUMP_TABLE 450 4989C3 ; mov_r11,rax # JUMP_TABLE = ENTRY 451 4D8963 10 ; mov_[r11+BYTE],r12 !16 # ENTRY->NAME = TOKEN 452 4C89E3 ; mov_rbx,r12 # Write Starting after struct 453 E8 %A ; call %consume_token # Collect whole string 454 4989DC ; mov_r12,rbx # Update HEAP 455 E9 %a ; jmp %First_pass 456 457 :D # :GetTarget 458 488B3D %T ; mov_rdi,[rip+DWORD] %scratch # Reset scratch 459 4C89D9 ; mov_rcx,r11 # Grab JUMP_TABLE 460 488B71 10 ; mov_rsi,[rcx+BYTE] !16 # I->NAME 461 :E # :GetTarget_loop 462 8A06 ; mov_al,[rsi] # I->NAME[0] 463 8A1F ; mov_bl,[rdi] # scratch[0] 464 480FB6DB ; movzx_rbx,bl # Zero extend 465 480FB6C0 ; movzx_rax,al # Zero extend 466 38D8 ; cmp_al,bl # IF TOKEN == I->NAME 467 0F85 %F ; jne %GetTarget_miss # Oops 468 469 4883C6 01 ; add_rsi, !1 470 4881C7 01000000 ; add_rdi, %1 471 3C 00 ; cmp_al, !0 472 0F85 %E ; jne %GetTarget_loop # Loop until 473 E9 %G ; jmp %GetTarget_done # Match 474 475 # Miss 476 :F # :GetTarget_miss 477 488B09 ; mov_rcx,[rcx] # I = I->NEXT 478 4883F9 00 ; cmp_rcx, !0 # IF NULL == I 479 0F84 %Q ; je %fail # Abort hard 480 481 488B71 10 ; mov_rsi,[rcx+BYTE] !16 # I->NAME 482 488B3D %T ; mov_rdi,[rip+DWORD] %scratch # Reset scratch 483 E9 %E ; jmp %GetTarget_loop 484 485 :G # :GetTarget_done 486 488B41 08 ; mov_rax,[rcx+BYTE] !8 # Get address 487 C3 ; ret 488 489 :H # :ClearScratch 490 50 ; push_rax # Protect against changes 491 53 ; push_rbx # And overwrites 492 51 ; push_rcx # While we work 493 488B1D %T ; mov_rbx,[rip+DWORD] %scratch # Where our scratch is 494 48C7C0 00000000 ; mov_rax, %0 # Using null 495 496 :I # :ClearScratch_loop 497 488B0B ; mov_rcx,[rbx] # Get current value 498 8803 ; mov_[rbx],al # Because we want null 499 4883C3 01 ; add_rbx, !1 # Increment 500 4883F9 00 ; cmp_rcx, !0 # Check if we hit null 501 0F85 %I ; jne %ClearScratch_loop # Keep looping 502 503 59 ; pop_rcx # Don't Forget to 504 5B ; pop_rbx # Restore Damage 505 58 ; pop_rax # Entirely 506 C3 ; ret 507 508 :J # :StorePointer 509 E8 %d ; call %Update_Pointer # Increment IP 510 488B1D %T ; mov_rbx,[rip+DWORD] %scratch # Write to scratch 511 E8 %A ; call %consume_token # get token 512 50 ; push_rax # Protect base_sep_p 513 488B05 %T ; mov_rax,[rip+DWORD] %scratch # Pointer to scratch 514 E8 %D ; call %GetTarget # Get address of pointer 515 E8 %H ; call %ClearScratch # Clean up after ourselves 516 4C89EA ; mov_rdx,r13 # base = IP 517 5B ; pop_rbx # Restore base_sep_p 518 4883FB 3E ; cmp_rbx, !0x3E # If base_sep_p == '>' 519 0F85 %K ; jne %StorePointer_done # If not 520 521 # Deal with %label>label case 522 50 ; push_rax # We need to preserve main target 523 488B1D %T ; mov_rbx,[rip+DWORD] %scratch # Write to scratch 524 E8 %A ; call %consume_token # get token 525 488B05 %T ; mov_rax,[rip+DWORD] %scratch # Pointer to scratch 526 E8 %D ; call %GetTarget # Get address of pointer 527 E8 %H ; call %ClearScratch # Clean up after ourselves 528 4889C2 ; mov_rdx,rax # Use our new base 529 58 ; pop_rax # Restore main target 530 531 :K # :StorePointer_done 532 C3 ; ret 533 534 :L # :StorePointer_rel4 535 E8 %J ; call %StorePointer # Do Common 536 4829D0 ; sub_rax,rdx # target - ip 537 48C7C2 04000000 ; mov_rdx, %4 # set the size of chars we want 538 E8 %z ; call %print_chars 539 E8 %H ; call %ClearScratch # Clean up after ourselves 540 E9 %k ; jmp %Second_pass 541 542 :M # :StorePointer_rel2 543 E8 %J ; call %StorePointer # Do Common 544 4829D0 ; sub_rax,rdx # target - ip 545 48C7C2 02000000 ; mov_rdx, %2 # set the size of chars we want 546 E8 %z ; call %print_chars 547 E8 %H ; call %ClearScratch # Clean up after ourselves 548 E9 %k ; jmp %Second_pass 549 550 :N # :StorePointer_rel1 551 E8 %J ; call %StorePointer # Do Common 552 4829D0 ; sub_rax,rdx # target - ip 553 48C7C2 01000000 ; mov_rdx, %1 # set the size of chars we want 554 E8 %z ; call %print_chars 555 E8 %H ; call %ClearScratch # Clean up after ourselves 556 E9 %k ; jmp %Second_pass 557 558 :O # :StorePointer_abs4 559 E8 %J ; call %StorePointer # Do Common 560 48C7C2 04000000 ; mov_rdx, %4 # set the size of chars we want 561 E8 %z ; call %print_chars 562 E8 %H ; call %ClearScratch # Clean up after ourselves 563 E9 %k ; jmp %Second_pass 564 565 :P # :StorePointer_abs2 566 E8 %J ; call %StorePointer # Do Common 567 48C7C2 02000000 ; mov_rdx, %2 # set the size of chars we want 568 E8 %z ; call %print_chars 569 E8 %H ; call %ClearScratch # Clean up after ourselves 570 E9 %k ; jmp %Second_pass 571 572 :Q # :fail 573 # Some shit went wrong 574 48C7C7 01000000 ; mov_rdi, %1 # All is wrong 575 48C7C0 3C000000 ; mov_rax, %0x3C # put the exit syscall number in eax 576 0F05 ; syscall # Call it a good day 577 578 579 :S # :write 580 00000000 ; NULL 581 00000000 ; NULL 582 583 :T # :scratch 584 00000000 ; NULL 585 00000000 ; NULL 586 587 # :ELF_end