boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

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