5717 lines
214 KiB
Plaintext
5717 lines
214 KiB
Plaintext
# Copyright (C) 2017 Jeremiah Orians
|
|
# Copyright (C) 2022 Andrius Štikonas
|
|
# This file is part of stage0.
|
|
#
|
|
# stage0 is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# stage0 is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
DEFINE add_al, 04
|
|
DEFINE add_rax, 4805
|
|
DEFINE add_rbx, 4881C3
|
|
DEFINE add_rcx, 4881C1
|
|
DEFINE add_rdx, 4881C2
|
|
DEFINE add_rsp, 4881C4
|
|
DEFINE add_rsi, 4881C6
|
|
DEFINE add_rax,rbx 4801D8
|
|
DEFINE add_rax,rcx 4801C8
|
|
DEFINE add_rbx,rax 4801C3
|
|
DEFINE add_rcx,rdi 4801F9
|
|
DEFINE and_rax, 4825
|
|
DEFINE and_rax,rbx 4821D8
|
|
DEFINE add_rbx,[rdi+BYTE] 48035F
|
|
DEFINE call E8
|
|
DEFINE call_rax FFD0
|
|
DEFINE call_[rcx+BYTE] FF51
|
|
DEFINE call_[r14+DWORD] 41FF96
|
|
DEFINE cmp_al, 3C
|
|
DEFINE cmp_rax, 483D
|
|
DEFINE cmp_rbx, 4881FB
|
|
DEFINE cmp_rcx, 4881F9
|
|
DEFINE cmp_rdx, 4881FA
|
|
DEFINE cmp_rbp, 4881FD
|
|
DEFINE cmp_rsi, 4881FE
|
|
DEFINE cmp_r8, 4981F8
|
|
DEFINE cmp_r12, 4981FC
|
|
DEFINE cmp_r15, 4981FF
|
|
DEFINE cmp_rax,rbx 4839D8
|
|
DEFINE cmp_rax,rcx 4839C8
|
|
DEFINE cmp_rbx,rcx 4839CB
|
|
DEFINE cmp_rbx,rdx 4839D3
|
|
DEFINE cmp_rsi,rdi 4839FE
|
|
DEFINE cmp_rax,[rip+DWORD] 483B05
|
|
DEFINE dec_rax 48FFC8
|
|
DEFINE jbe 0F86
|
|
DEFINE je 0F84
|
|
DEFINE jg 0F8F
|
|
DEFINE jl 0F8C
|
|
DEFINE jle 0F8E
|
|
DEFINE jmp E9
|
|
DEFINE jne 0F85
|
|
DEFINE idiv_rbx 48F7FB
|
|
DEFINE imul_rax, 4869C0
|
|
DEFINE imul_rbp, 4869ED
|
|
DEFINE imul_rax,rbx 480FAFC3
|
|
DEFINE lea_rax,[rip+DWORD] 488D05
|
|
DEFINE lea_rbx,[rip+DWORD] 488D1D
|
|
DEFINE lea_rcx,[rip+DWORD] 488D0D
|
|
DEFINE lea_rdx,[rip+DWORD] 488D15
|
|
DEFINE mov_rax, 48C7C0
|
|
DEFINE mov_rbx, 48C7C3
|
|
DEFINE mov_rcx, 48C7C1
|
|
DEFINE mov_rdi, 48C7C7
|
|
DEFINE mov_rdx, 48C7C2
|
|
DEFINE mov_rsi, 48C7C6
|
|
DEFINE mov_r9, 49C7C1
|
|
DEFINE mov_r15, 49C7C7
|
|
DEFINE mov_rax,rbp 4889E8
|
|
DEFINE mov_rax,rbx 4889D8
|
|
DEFINE mov_rax,rcx 4889C8
|
|
DEFINE mov_rax,rdx 4889D0
|
|
DEFINE mov_rax,r12 4C89E0
|
|
DEFINE mov_rax,rsi 4889F0
|
|
DEFINE mov_rbp,rax 4889C5
|
|
DEFINE mov_rbp,rdx 4889D5
|
|
DEFINE mov_rbp,rsp 4889E5
|
|
DEFINE mov_rbx,rax 4889C3
|
|
DEFINE mov_rbx,rcx 4889CB
|
|
DEFINE mov_rbx,rdx 4889D3
|
|
DEFINE mov_rcx,rax 4889C1
|
|
DEFINE mov_rcx,rbx 4889D9
|
|
DEFINE mov_rcx,r8 4C89C1
|
|
DEFINE mov_rcx,r9 4C89C9
|
|
DEFINE mov_rdi,rax 4889C7
|
|
DEFINE mov_rdi,rsi 4889F7
|
|
DEFINE mov_rdx,rax 4889C2
|
|
DEFINE mov_rdx,rbx 4889DA
|
|
DEFINE mov_rdx,rsp 4889E2
|
|
DEFINE mov_rsi,rax 4889C6
|
|
DEFINE mov_rsi,rdi 4889FE
|
|
DEFINE mov_rsp,rbp 4889EC
|
|
DEFINE mov_r8,rsp 4989E0
|
|
DEFINE mov_r12,rax 4989C4
|
|
DEFINE mov_al,[rax] 8A00
|
|
DEFINE mov_al,[rbx] 8A03
|
|
DEFINE mov_al,[rcx] 8A01
|
|
DEFINE mov_al,[rdx] 8A02
|
|
DEFINE mov_bl,[rbx] 8A1B
|
|
DEFINE mov_bl,[rcx] 8A19
|
|
DEFINE mov_bl,[rdx] 8A1A
|
|
DEFINE mov_cl,[rbx] 8A0B
|
|
DEFINE mov_[rax], C600 # BYTE PTR
|
|
DEFINE mov_[rbx], C603 # BYTE PTR
|
|
DEFINE mov_rax,[rax] 488B00
|
|
DEFINE mov_rax,[rbx] 488B03
|
|
DEFINE mov_rax,[r12] 498B0424
|
|
DEFINE mov_rax,[r12+BYTE] 498B4424
|
|
DEFINE mov_rbx,[rax] 488B18
|
|
DEFINE mov_rbx,[rbx] 488B1B
|
|
DEFINE mov_rbx,[rbx+BYTE] 488B5B
|
|
DEFINE mov_rcx,[rbx] 488B0B
|
|
DEFINE mov_rcx,[rcx] 488B09
|
|
DEFINE mov_r12,[r12] 4D8B2424
|
|
DEFINE mov_[rbx],al 8803
|
|
DEFINE mov_[rcx],al 8801
|
|
DEFINE mov_[rcx],bl 8819
|
|
DEFINE mov_[rsi],al 8806
|
|
DEFINE mov_[rax],rbx 488918
|
|
DEFINE mov_[rax],rcx 488908
|
|
DEFINE mov_[rbx],rax 488903
|
|
DEFINE mov_[rdx],rax 488902
|
|
DEFINE mov_cl,[rbx+BYTE] 8A4B
|
|
DEFINE mov_rax,[rax+BYTE] 488B40
|
|
DEFINE mov_rax,[rbx+BYTE] 488B43
|
|
DEFINE mov_rax,[rcx+BYTE] 488B41
|
|
DEFINE mov_rax,[rdx+BYTE] 488B42
|
|
DEFINE mov_rbx,[rax+BYTE] 488B58
|
|
DEFINE mov_rbx,[rcx+BYTE] 488B59
|
|
DEFINE mov_rbx,[rdi+BYTE] 488B5F
|
|
DEFINE mov_rcx,[rax+BYTE] 488B48
|
|
DEFINE mov_rcx,[rcx+BYTE] 488B49
|
|
DEFINE mov_rcx,[rdi+BYTE] 488B4F
|
|
DEFINE mov_rcx,[rdx+BYTE] 488B4A
|
|
DEFINE mov_rdi,[rdx+BYTE] 488B7A
|
|
DEFINE mov_rdx,[rdx+BYTE] 488B52
|
|
DEFINE mov_r14,[rdx+BYTE] 4C8B72
|
|
DEFINE mov_rax,[rax+DWORD] 488B40
|
|
DEFINE mov_rbx,[rbx+DWORD] 488B5B
|
|
DEFINE mov_rax,[rip+DWORD] 488B05
|
|
DEFINE mov_rbx,[rip+DWORD] 488B1D
|
|
DEFINE mov_rcx,[rip+DWORD] 488B0D
|
|
DEFINE mov_rsp,[rip+DWORD] 488B25
|
|
DEFINE mov_r8,[rip+DWORD] 4C8B05
|
|
DEFINE mov_r9,[rip+DWORD] 4C8B0D
|
|
DEFINE mov_[rax+BYTE],rbx 488958
|
|
DEFINE mov_[rax+BYTE],rcx 488948
|
|
DEFINE mov_[rax+BYTE],rdx 488950
|
|
DEFINE mov_[rbp+BYTE],rax 488945
|
|
DEFINE mov_[rbp+BYTE],rdx 488955
|
|
DEFINE mov_[rbp+BYTE],rsi 488975
|
|
DEFINE mov_[rcx+BYTE],rax 488941
|
|
DEFINE mov_[rdx+BYTE],rax 488942
|
|
DEFINE mov_[rdx+BYTE],rbx 48895A
|
|
DEFINE mov_[rdx+BYTE],rcx 48894A
|
|
DEFINE mov_[rdx+BYTE],rbp 48896A
|
|
DEFINE mov_[rdx+BYTE],rsi 488972
|
|
DEFINE mov_[rip+DWORD],rax 488905
|
|
DEFINE mov_[rip+DWORD],rbx 48891D
|
|
DEFINE mov_[rip+DWORD],rcx 48890D
|
|
DEFINE mov_[rip+DWORD],rdx 488915
|
|
DEFINE mov_[rip+DWORD],rsp 488925
|
|
DEFINE movzx_rax,al 480FB6C0
|
|
DEFINE movzx_rbx,bl 480FB6DB
|
|
DEFINE movzx_rcx,cl 480FB6C9
|
|
DEFINE popf 9D
|
|
DEFINE pop_rax 58
|
|
DEFINE pop_rbp 5D
|
|
DEFINE pop_rbx 5B
|
|
DEFINE pop_rcx 59
|
|
DEFINE pop_rdi 5F
|
|
DEFINE pop_rdx 5A
|
|
DEFINE pop_rsi 5E
|
|
DEFINE pop_r8 4158
|
|
DEFINE push 6A
|
|
DEFINE pushf 9C
|
|
DEFINE push_rax 50
|
|
DEFINE push_rbp 55
|
|
DEFINE push_rbx 53
|
|
DEFINE push_rcx 51
|
|
DEFINE push_rdi 57
|
|
DEFINE push_rdx 52
|
|
DEFINE push_rsi 56
|
|
DEFINE ret C3
|
|
DEFINE ror_r9 49D1C9
|
|
DEFINE sal_rax, 48C1E0
|
|
DEFINE shl_rax, 48C1E0
|
|
DEFINE shr_rax, 48C1E8
|
|
DEFINE shr_rbx 48D1EB
|
|
DEFINE sub_rax, 482D
|
|
DEFINE sub_rbx, 4881EB
|
|
DEFINE sub_rcx, 4881E9
|
|
DEFINE sub_rsi, 4881EE
|
|
DEFINE sub_rsp, 4881EC
|
|
DEFINE xchg_rax,rbx 4893
|
|
|
|
DEFINE NULL 0000000000000000
|
|
|
|
# Register usage:
|
|
# RAX, RSI, RDI => Temps
|
|
# R13 => MALLOC
|
|
# R15 => stderr flag
|
|
|
|
# Struct TYPE format: (size 56)
|
|
# NEXT => 0
|
|
# SIZE => 8
|
|
# OFFSET => 16
|
|
# INDIRECT => 24
|
|
# MEMBERS => 32
|
|
# TYPE => 40
|
|
# NAME => 48
|
|
|
|
# Struct TOKEN_LIST format: (size 40)
|
|
# NEXT => 0
|
|
# LOCALS/PREV => 8
|
|
# S => 16
|
|
# TYPE => 24
|
|
# ARGS/DEPTH => 32
|
|
|
|
# efi_main(void *image_handle, struct efi_system_table *system)
|
|
:_start
|
|
mov_rbp,rsp # save stack pointer
|
|
mov_[rip+DWORD],rcx %image_handle # save image_handle
|
|
mov_[rip+DWORD],rdx %system # save system
|
|
mov_r14,[rdx+BYTE] !96 # system->boot
|
|
|
|
# Open Loaded Image protocol
|
|
mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle
|
|
lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL
|
|
mov_rcx,r9 # arg1 = image_handle
|
|
call %open_protocol # open protocol
|
|
mov_rdi,rax # save image
|
|
|
|
# Get root file system
|
|
mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle
|
|
lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL
|
|
mov_rcx,[rdi+BYTE] !24 # arg1 = root_device = image->device
|
|
mov_[rip+DWORD],rcx %root_device # save root_device
|
|
call %open_protocol # open protocol
|
|
mov_rcx,rax # get rootfs
|
|
|
|
# Get root directory
|
|
lea_rdx,[rip+DWORD] %rootdir # arg2 = &rootdir
|
|
sub_rsp, %16 # allocate shadow stack space for UEFI function
|
|
call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir)
|
|
add_rsp, %16 # deallocate stack
|
|
|
|
# Push command line arguments onto stack
|
|
mov_rbx,[rdi+BYTE] !56 # options = image->load_options
|
|
mov_rdx,rbx # save beginning of load_options
|
|
add_rbx,[rdi+BYTE] !48 # go to the end of load_options
|
|
push !0 # Save end of arguments (NULL) onto stack
|
|
:loop_options
|
|
cmp_rbx,rdx # Check if we are done
|
|
je %loop_options_done # We are done
|
|
sub_rbx, %2 # --options
|
|
mov_al,[rbx] # *options
|
|
cmp_al, !0x20 # if *options != ' '
|
|
jne %loop_options # then continue looping
|
|
mov_[rbx], !0 # zero it
|
|
add_rbx, %2 # ++options
|
|
push_rbx # push another argument onto stack
|
|
jmp %loop_options # next argument
|
|
:loop_options_done
|
|
|
|
# Open file for reading
|
|
pop_r8 # arg3 = in
|
|
push !1 # Set exit code in case of failure
|
|
cmp_r8, %0 # If NULL
|
|
je %failed_input # then exit
|
|
lea_rdx,[rip+DWORD] %fin # arg2 = &fin
|
|
push !1 # arg5 = EFI_FILE_READ_ONLY
|
|
mov_r9, %1 # arg4 = EFI_FILE_MODE_READ
|
|
mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir
|
|
sub_rsp, %32 # allocate shadow stack space for UEFI function
|
|
call_[rcx+BYTE] !8 # rootdir->open()
|
|
cmp_rax, %0 # If failed to open
|
|
jne %failed_input # then exit
|
|
add_rsp, %48 # deallocate stack
|
|
|
|
# Open file for writing
|
|
pop_r8 # arg3 = out
|
|
push !1 # Set exit code in case of failure
|
|
cmp_r8, %0 # If NULL
|
|
je %failed_output # then exit
|
|
lea_rdx,[rip+DWORD] %fout # arg2 = &fout
|
|
push !0 # arg5 = 0
|
|
mov_r9, %7 # to get 0x8000000000000003 we set the rightmost 3 bits and then do right rotation by 1
|
|
ror_r9 # arg4 = EFI_FILE_MODE_CREATE| EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ
|
|
mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir
|
|
sub_rsp, %32 # allocate shadow stack space for UEFI function
|
|
call_[rcx+BYTE] !8 # rootdir->open()
|
|
add_rsp, %48 # deallocate stack
|
|
|
|
# Allocate ourselves 16 MiB of memory
|
|
mov_rdx, %0x1000000 # allocate 16 MiB of memory for malloc pool
|
|
call %allocate_pool # allocate memory
|
|
|
|
mov_[rip+DWORD],rax %malloc_pointer # save malloc pointer
|
|
mov_[rip+DWORD],rax %malloc_pool # save the beginning of malloc pool
|
|
|
|
# Zero allocated memory buffer
|
|
add_rax, %0x1000000 # end of malloc area
|
|
:zero_loop
|
|
dec_rax # next byte
|
|
mov_[rax], !0 # zero it
|
|
cmp_rax,[rip+DWORD] %malloc_pointer # if we are not done yet
|
|
jne %zero_loop # then continue looping
|
|
|
|
# cc_amd64 needs quite a lot of stack space when building M2-Planet
|
|
# which is not guaranteed to be available on UEFI (it guarantees at least 128 KiB).
|
|
# Therefore we will allocate an extra space on heap and use part of it for user stack
|
|
mov_rax, %0x400000 # Allocate 4 MiB for user stack
|
|
call %malloc
|
|
mov_[rip+DWORD],rax %user_stack # Save user stack
|
|
call %exit_uefi_stack # Switch to user stack
|
|
|
|
mov_r15, %0 # Not writing to stderr yet
|
|
|
|
call %fix_types # Resolve relative addresses in types struct to absolute
|
|
mov_rax, %0 # HEAD = NULL
|
|
call %read_all_tokens # Read all tokens
|
|
call %Reverse_List # Reverse order
|
|
# call %debug_list # Try to figure out what is wrong
|
|
mov_[rip+DWORD],rax %global_token # Set global_token
|
|
call %program # Convert into program
|
|
lea_rax,[rip+DWORD] %header_string1 # Our header string
|
|
call %File_Print # Print it
|
|
mov_rax,[rip+DWORD] %output_list # Our output_list
|
|
call %recursive_output # Print core program
|
|
# lea_rax,[rip+DWORD] %header_string2 # Our Enable debug
|
|
# call %File_Print # Print it
|
|
lea_rax,[rip+DWORD] %header_string3 # Our second label
|
|
call %File_Print # Print it
|
|
mov_rax,[rip+DWORD] %globals_list # Our globals
|
|
call %recursive_output # Get them
|
|
lea_rax,[rip+DWORD] %header_string4 # Our final header
|
|
call %File_Print # Print it
|
|
mov_rax,[rip+DWORD] %strings_list # Our strings
|
|
call %recursive_output # Get them
|
|
lea_rax,[rip+DWORD] %header_string5 # Our final header
|
|
call %File_Print # Print it
|
|
|
|
|
|
:Done
|
|
# program completed Successfully
|
|
mov_rax, %0 # Set exit code 0
|
|
:Done_1
|
|
# Free pool
|
|
push_rax # save exit code
|
|
|
|
call %enter_uefi_stack # Switch back to UEFI stack
|
|
|
|
mov_rcx,[rip+DWORD] %malloc_pool # arg1 = malloc_pool
|
|
call %free_pool # system->boot->free_pool(malloc_pool)
|
|
|
|
mov_rcx,[rip+DWORD] %fout # get fout
|
|
call %close_file # close fout
|
|
|
|
:failed_output
|
|
mov_rcx,[rip+DWORD] %fin # get fin
|
|
call %close_file # close fin
|
|
|
|
:failed_input
|
|
mov_rcx,[rip+DWORD] %rootdir # get rootdir
|
|
call %close_file # close rootdir
|
|
|
|
mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle
|
|
lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL
|
|
mov_rcx,[rip+DWORD] %root_device # arg1 = root_device
|
|
call %close_protocol # close protocol
|
|
|
|
mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle
|
|
lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL
|
|
mov_rcx,r8 # arg1 = image_handle
|
|
call %close_protocol # close protocol
|
|
|
|
pop_rax # restore exit code
|
|
|
|
:abort # used for debugging only
|
|
mov_rsp,rbp # restore stack
|
|
ret # return to UEFI
|
|
|
|
|
|
:header_string1
|
|
"
|
|
# Core program
|
|
"
|
|
|
|
:header_string2
|
|
"
|
|
:ELF_data
|
|
"
|
|
|
|
:header_string3
|
|
"
|
|
# Program global variables
|
|
"
|
|
|
|
:header_string4
|
|
"
|
|
# Program strings
|
|
"
|
|
|
|
:header_string5
|
|
"
|
|
:ELF_end
|
|
"
|
|
|
|
|
|
# Resolve relative addresses in types struct to absolute
|
|
# Uses RAX to store current type, RBX for temp
|
|
:fix_types
|
|
push_rbx # Protect RBX
|
|
|
|
lea_rax,[rip+DWORD] %prim_types # Get address of prim_types
|
|
mov_[rip+DWORD],rax %global_types # Write it to global_types
|
|
|
|
:fix_type
|
|
mov_rbx,[rax+BYTE] !48 # Get offset to NAME
|
|
add_rbx,rax # Get NAME
|
|
mov_[rax+BYTE],rbx !48 # Store NAME
|
|
|
|
mov_rbx,[rax+BYTE] !40 # Get offset to TYPE
|
|
add_rbx,rax # Get TYPE
|
|
mov_[rax+BYTE],rbx !40 # Store TYPE
|
|
|
|
mov_rbx,[rax+BYTE] !24 # Get offset to INDIRECT
|
|
add_rbx,rax # Get INDIRECT
|
|
mov_[rax+BYTE],rbx !24 # Store INDIRECT
|
|
|
|
mov_rbx,[rax] # Get offset to NEXT
|
|
cmp_rbx, %0 # If no more types
|
|
je %fix_types_done # Then we are done
|
|
|
|
add_rbx,rax # Get NEXT
|
|
mov_[rax],rbx # Store NEXT
|
|
|
|
add_rax, %56 # Go to next type
|
|
jmp %fix_type
|
|
|
|
:fix_types_done
|
|
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# read_all_tokens function
|
|
# Receives FILE* in R15 and Token_List* in RAX
|
|
# Tokenizes all input and returns updated list in RAX
|
|
# Returns TOKEN in RAX
|
|
# Uses RAX for C
|
|
:read_all_tokens
|
|
mov_[rip+DWORD],rax %Token
|
|
call %fgetc
|
|
:read_all_tokens_loop
|
|
cmp_rax, %-4 # Check for EOF
|
|
je %read_all_tokens_done # Stop if found
|
|
call %get_token # Read all tokens
|
|
jmp %read_all_tokens_loop # Loop
|
|
:read_all_tokens_done
|
|
mov_rax,[rip+DWORD] %Token
|
|
ret
|
|
|
|
|
|
# get_token function
|
|
# Receives INT in RAX and FILE* in R15
|
|
# Makes a list of TOKEN_LIST
|
|
# C and STRING_INDEX are stored in memory, RCX is used for S and RDX is used for current
|
|
# Returns C in RAX
|
|
:get_token
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
|
|
mov_rax, %40 # Malloc CURRENT
|
|
call %malloc # Get Pointer
|
|
mov_rdx,rax # Set CURRENT
|
|
|
|
mov_rax, %256 # Malloc the string
|
|
call %malloc # Get pointer to S
|
|
mov_rcx,rax # Set S
|
|
mov_[rdx+BYTE],rcx !16 # CURRENT->S = S
|
|
:reset
|
|
mov_[rip+DWORD],rcx %string_index # S[0]
|
|
mov_rax,[rip+DWORD] %C # Using C
|
|
|
|
call %clear_white_space # Clear WhiteSpace
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
|
|
cmp_rax, %-4 # Check for EOF
|
|
je %get_token_abort # if EOF abort
|
|
|
|
cmp_rax, %35 # Check for '#'
|
|
jne %get_token_alpha # Nope
|
|
|
|
# Deal with # line comments
|
|
call %purge_macro # Let it handle it
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %reset # Try again
|
|
|
|
:get_token_alpha
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
lea_rbx,[rip+DWORD] %alphas # Get alphanumerics
|
|
call %In_Set # See if in set
|
|
cmp_rax, %1 # IF TRUE
|
|
jne %get_token_symbol # Otherwise
|
|
|
|
# Store keywords
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
call %preserve_keyword # Store
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %get_token_done # Be done with this token
|
|
|
|
:get_token_symbol
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
lea_rbx,[rip+DWORD] %symbols # Get symbols
|
|
call %In_Set # See if in set
|
|
cmp_rax, %1 # IF TRUE
|
|
jne %get_token_strings # Otherwise
|
|
|
|
# Store symbols
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
call %preserve_symbol # Store
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %get_token_done # Be done with this token
|
|
|
|
:get_token_strings
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
lea_rbx,[rip+DWORD] %strings # Get strings
|
|
call %In_Set # See if in set
|
|
cmp_rax, %1 # IF TRUE
|
|
jne %get_token_comment # Otherwise
|
|
|
|
# Store String
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
call %consume_word # Store
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %get_token_done # Be done with this token
|
|
|
|
:get_token_comment
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
cmp_rax, %47 # IF '/' == C
|
|
jne %get_token_else # Otherwise
|
|
|
|
call %consume_byte # Hope it just is '/'
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
|
|
cmp_rax, %42 # IF '*' we have '/*'
|
|
jne %get_token_comment_line # Check for '//'
|
|
|
|
# Deal with /* block comments */
|
|
call %fgetc # get next C
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
:get_token_comment_block_outer
|
|
mov_rax,[rip+DWORD] %C # Using C
|
|
cmp_rax, %47 # IF '/' != C
|
|
je %get_token_comment_block_done # be done
|
|
|
|
:get_token_comment_block_inner
|
|
mov_rax,[rip+DWORD] %C # Using C
|
|
cmp_rax, %42 # IF '*' != C
|
|
je %get_token_comment_block_iter # jump over
|
|
|
|
# Deal with inner loop
|
|
call %fgetc # get next C
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %get_token_comment_block_inner # keep going
|
|
|
|
:get_token_comment_block_iter
|
|
call %fgetc # get next C
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %get_token_comment_block_outer
|
|
|
|
:get_token_comment_block_done
|
|
call %fgetc # get next C
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %reset # throw away, try again
|
|
|
|
:get_token_comment_line
|
|
cmp_rax, %47 # IF '/' we have //
|
|
jne %get_token_done # keep if just '/'
|
|
|
|
# Deal with // line comment
|
|
call %fgetc # drop to match
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
jmp %reset # throw away, try again
|
|
|
|
:get_token_else
|
|
mov_rax,[rip+DWORD] %C # Send C
|
|
call %consume_byte
|
|
mov_[rip+DWORD],rax %C # Set C
|
|
|
|
:get_token_done
|
|
mov_rax,[rip+DWORD] %Token # TOKEN
|
|
mov_[rdx+BYTE],rax !8 # CURRENT->PREV = TOKEN
|
|
mov_[rdx],rax # CURRENT->NEXT = TOKEN
|
|
mov_[rip+DWORD],rdx %Token # TOKEN = CURRENT
|
|
|
|
:get_token_abort
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
mov_rax,[rip+DWORD] %C # Return C
|
|
ret
|
|
|
|
|
|
# Malloc isn't actually reserving memory here.
|
|
# It just updates the pointer in our already reserved storage pool.
|
|
:malloc
|
|
push_rbx # Protect RBX
|
|
mov_rbx,[rip+DWORD] %malloc_pointer # Get malloc pointer
|
|
xchg_rax,rbx # Put it in place
|
|
add_rbx,rax # Request number of desired bytes
|
|
mov_[rip+DWORD],rbx %malloc_pointer # Save malloc_pointer
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# clear_white_space function
|
|
# Receives INT C in RAX and FILE* in R15
|
|
# Returns first non-whitespace char in RAX
|
|
:clear_white_space
|
|
cmp_rax, %32 # Check for ' '
|
|
je %clear_white_space_wipe # wipe it out
|
|
|
|
cmp_rax, %10 # Check for '\n'
|
|
je %clear_white_space_wipe # wipe it output
|
|
|
|
cmp_rax, %9 # Check for '\t'
|
|
jne %clear_white_space_done # looks like non-whitespace
|
|
|
|
:clear_white_space_wipe
|
|
call %fgetc # Read a new byte
|
|
cmp_rax, %-4 # Check for EOF
|
|
je %clear_white_space_done # Short circuit
|
|
jmp %clear_white_space # iterate
|
|
|
|
:clear_white_space_done
|
|
ret
|
|
|
|
|
|
# In_Set function
|
|
# Receives Char C in RAX and CHAR* in RBX
|
|
# Returns 1 if true, zero if false in RAX
|
|
:In_Set
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
:In_Set_loop
|
|
mov_cl,[rbx] # Read char
|
|
movzx_rcx,cl # Zero extend it
|
|
|
|
cmp_rax,rcx # See if they match
|
|
je %In_Set_True # return true
|
|
|
|
cmp_rcx, %0 # Check for NULL
|
|
je %In_Set_False # return false
|
|
|
|
add_rbx, %1 # s = s + 1
|
|
jmp %In_Set_loop # Keep looping
|
|
|
|
:In_Set_True
|
|
mov_rax, %1 # Set True
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:In_Set_False
|
|
mov_rax, %0 # Set FALSE
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:alphas
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
|
|
|
|
:symbols
|
|
"<=>|&!-"
|
|
|
|
:strings
|
|
'22 27 00'
|
|
|
|
|
|
# purge_macro function
|
|
# Receives CH in RAX
|
|
# Reads chars until Line feed is read
|
|
# returns line feed
|
|
:purge_macro
|
|
call %fgetc # read next char
|
|
cmp_rax, %10 # Check for '\n'
|
|
jne %purge_macro # Keep going
|
|
ret
|
|
|
|
|
|
# preserve_keyword function
|
|
# Receives INT C in RAX
|
|
# collects all chars in keyword
|
|
# Returns C in RAX
|
|
# Uses RCX for INT C
|
|
:preserve_keyword
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rax # Setup C
|
|
lea_rbx,[rip+DWORD] %alphas # Concerning ourselves with "abc.."
|
|
:preserve_keyword_loop
|
|
call %In_Set # Check if alphanumerics
|
|
cmp_rax, %1 # IF TRUE
|
|
jne %preserve_keyword_label # Otherwise check for label
|
|
|
|
mov_rax,rcx # Pass C
|
|
call %consume_byte # consume that byte
|
|
mov_rcx,rax # Update C
|
|
jmp %preserve_keyword_loop # keep looping
|
|
|
|
:preserve_keyword_label
|
|
mov_rax,rcx # Fix return
|
|
cmp_rax, %58 # Check for ':'
|
|
jne %preserve_keyword_done # be done
|
|
|
|
# Fix our goto label
|
|
call %fixup_label # Fix the label
|
|
mov_rax, %32 # Return Whitespace
|
|
|
|
:preserve_keyword_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# preserve_symbol function
|
|
# Receives INT C in RAX
|
|
# collects all chars in symbol
|
|
# Returns C in RAX
|
|
# Uses RCX for INT C
|
|
:preserve_symbol
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rax # Setup C
|
|
lea_rbx,[rip+DWORD] %symbols # Concerning ourselves with "<=>.."
|
|
:preserve_symbol_loop
|
|
call %In_Set # Check if symbol
|
|
cmp_rax, %1 # IF TRUE
|
|
jne %preserve_symbol_done # Otherwise be done
|
|
|
|
mov_rax,rcx # Pass C
|
|
call %consume_byte # consume that byte
|
|
mov_rcx,rax # Update C
|
|
jmp %preserve_symbol_loop # keep looping
|
|
|
|
:preserve_symbol_done
|
|
mov_rax,rcx # Fix return
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# consume_word function
|
|
# receives INT C in RAX
|
|
# returns INT C in RAX
|
|
# Uses RAX for C, RBX for FREQ and RCX for ESCAPE
|
|
:consume_word
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rbx,rax # FREQ = C
|
|
mov_rcx, %0 # ESCAPE = FALSE
|
|
:consume_word_loop
|
|
cmp_rcx, %0 # IF !ESCAPE
|
|
jne %consume_word_escape # Enable escape
|
|
|
|
cmp_rax, %92 # if '\\'
|
|
jne %consume_word_iter # keep state
|
|
|
|
mov_rcx, %1 # ESCAPE = TRUE
|
|
jmp %consume_word_iter # keep going
|
|
|
|
:consume_word_escape
|
|
mov_rcx, %0 # ESCAPE = FALSE
|
|
|
|
:consume_word_iter
|
|
call %consume_byte # read next char
|
|
|
|
cmp_rcx, %0 # IF ESCAPE
|
|
jne %consume_word_loop # keep looping
|
|
|
|
cmp_rax,rbx # IF C != FREQ
|
|
jne %consume_word_loop # keep going
|
|
|
|
call %fgetc # return next char
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# consume_byte function
|
|
# Receives INT C in RAX
|
|
# Inserts C into string S, updates String S
|
|
# Returns Next char in RAX
|
|
:consume_byte
|
|
push_rbx # Protect RBX
|
|
mov_rbx,[rip+DWORD] %string_index # S[0]
|
|
mov_[rbx],al # S[0] = C
|
|
add_rbx, %1 # S = S + 1
|
|
mov_[rip+DWORD],rbx %string_index # Update S
|
|
call %fgetc
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# fixup_label function
|
|
# Receives S in RCX
|
|
# prepends ':' to string and returns registers unchanged
|
|
# Uses RAX for HOLD, RBX for PREV and RCX for S[0]
|
|
:fixup_label
|
|
push_rax # Protect RAX
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax, %58 # HOLD = ':'
|
|
mov_rcx,[rdx+BYTE] !16 # HOLD_STRING[0]
|
|
:fixup_label_loop
|
|
mov_rbx,rax # PREV = HOLD
|
|
mov_al,[rcx] # HOLD = HOLD_STRING[I]
|
|
movzx_rax,al # make useful
|
|
mov_[rcx],bl # HOLD_STRING[I] = PREV
|
|
add_rcx, %1 # I = I + 1
|
|
cmp_rax, %0 # IF NULL == HOLD
|
|
jne %fixup_label_loop # Keep looping
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
pop_rax # Restore RAX
|
|
ret
|
|
|
|
|
|
# fgetc function
|
|
# Returns -4 (EOF) or char in RAX
|
|
:fgetc
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
|
|
mov_rcx,[rip+DWORD] %fin # arg1 = fin
|
|
push !1 # size = 1
|
|
mov_rdx,rsp # arg2 = &size
|
|
mov_rsi, %0 # zero rsi
|
|
push_rsi # allocate stack
|
|
mov_r8,rsp # arg3 = &input
|
|
sub_rsp, %24 # allocate shadow stack space for UEFI function
|
|
call_[rcx+BYTE] !32 # fin->read()
|
|
add_rsp, %24 # deallocate stack
|
|
pop_rax # save input to rax
|
|
pop_rsi # save size to rsi
|
|
|
|
# If the file ended (0 bytes read) return EOF
|
|
cmp_rsi, %0 # if size == 0
|
|
jne %fgetc_1
|
|
mov_rax, %-4 # Put EOF in rax
|
|
|
|
:fgetc_1
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
ret # return
|
|
|
|
|
|
# Reverse_List function
|
|
# Receives List in RAX
|
|
# Returns the list reversed in RAX
|
|
:Reverse_List
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rbx,rax # Set HEAD
|
|
mov_rax, %0 # ROOT = NULL
|
|
:Reverse_List_Loop
|
|
cmp_rbx, %0 # WHILE HEAD != NULL
|
|
je %Reverse_List_Done # Stop otherwise
|
|
|
|
mov_rcx,[rbx] # NEXT = HEAD->NEXT
|
|
mov_[rbx],rax # HEAD->NEXT = ROOT
|
|
mov_rax,rbx # ROOT = HEAD
|
|
mov_rbx,rcx # HEAD = NEXT
|
|
jmp %Reverse_List_Loop # Keep Going
|
|
|
|
:Reverse_List_Done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# recursive_output function
|
|
# Receives list in RAX
|
|
# walks the list and prints the I->S for all nodes backwards
|
|
# Uses RBX for I
|
|
:recursive_output
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
cmp_rax, %0 # Check for NULL
|
|
je %recursive_output_done # Skip the work
|
|
mov_rbx,rax # I = Head
|
|
|
|
mov_rax,[rbx] # Iterate to next Token
|
|
call %recursive_output # Recurse
|
|
|
|
mov_rax,[rbx+BYTE] !16 # Using S
|
|
call %File_Print # Print it
|
|
|
|
:recursive_output_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# File_Print function
|
|
# Receives CHAR* in RAX
|
|
# calls fputc for every non-null char
|
|
:File_Print
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rbx,rax # Protect S
|
|
cmp_rax, %0 # Protect against nulls
|
|
je %File_Print_Done # Simply don't try to print them
|
|
:File_Print_Loop
|
|
mov_al,[rbx] # Read byte
|
|
movzx_rax,al # zero extend
|
|
cmp_rax, %0 # Check for NULL
|
|
je %File_Print_Done # Stop at NULL
|
|
|
|
call %fputc # write it
|
|
add_rbx, %1 # S = S + 1
|
|
jmp %File_Print_Loop # Keep going
|
|
|
|
:File_Print_Done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# fputc function
|
|
# receives CHAR in RAX
|
|
# writes char and returns
|
|
:fputc
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
|
|
cmp_r15, %2 # Check if printing to system error
|
|
jne %fputc_file # Else print to file
|
|
|
|
# Print to stderr
|
|
cmp_rax, %0xA # If we have LF, we need to append CR
|
|
pushf # Protect condition
|
|
mov_rcx,[rip+DWORD] %system # get system
|
|
mov_rcx,[rcx+BYTE] !64 # system->out (system->err doesn't print anything for some reason)
|
|
mov_[rip+DWORD],rax %WCHAR # Convert to WCHAR
|
|
lea_rdx,[rip+DWORD] %WCHAR # arg3 = *WCHAR
|
|
sub_rsp, %16 # allocate shadow stack space for UEFI function
|
|
call_[rcx+BYTE] !8 # system->err->output_string(system->err, WCHAR*)
|
|
add_rsp, %16 # deallocate stack
|
|
|
|
popf # Restore condition
|
|
jne %fputc_done # We are done if not LF
|
|
mov_rax, %0xD # Carriage return
|
|
call %fputc # Print it
|
|
jmp %fputc_done # We are done
|
|
|
|
:fputc_file
|
|
mov_rcx,[rip+DWORD] %fout # arg1 = fout
|
|
push !1 # set size
|
|
mov_rdx,rsp # arg2 = &size
|
|
push_rax # allocate stack
|
|
mov_r8,rsp # arg3 = &output
|
|
sub_rsp, %24 # allocate shadow stack space for UEFI function
|
|
call_[rcx+BYTE] !40 # fout->write()
|
|
add_rsp, %40 # deallocate stack
|
|
|
|
:fputc_done
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
ret # return
|
|
|
|
|
|
# program function
|
|
# receives nothing, returns nothing
|
|
# Uses RAX for type_size
|
|
:program
|
|
# The binary initialized the globals to null, so we can skip those steps
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
|
|
:new_type
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
cmp_rax, %0 # Check if NULL
|
|
je %program_done # Be done if null
|
|
|
|
mov_rbx,[rax+BYTE] !16 # GLOBAL_TOKEN->S
|
|
lea_rax,[rip+DWORD] %constant # "CONSTANT"
|
|
call %match # IF GLOBAL_TOKEN->S == "CONSTANT"
|
|
cmp_rax, %0 # If true
|
|
jne %program_else # Looks like not a constant
|
|
|
|
# Deal with minimal constant case
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_rbx, %0 # NULL
|
|
mov_rcx,[rip+DWORD] %global_constant_list # global_constant_list
|
|
call %sym_declare # Declare that constant
|
|
mov_[rip+DWORD],rax %global_constant_list # global_constant_list = sym_declare(global_token->s, NULL, global_constant_list);
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx] # global_token->next
|
|
mov_[rax+BYTE],rbx !32 # global_constant_list->arguments = global_token->next
|
|
|
|
mov_rbx,[rbx] # global_token->next->next
|
|
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next->next;
|
|
jmp %new_type # go around again
|
|
|
|
:program_else
|
|
call %type_name # Figure out the type_size
|
|
cmp_rax, %0 # IF NULL == type_size
|
|
je %new_type # it was a new type
|
|
|
|
# Add to global symbol table
|
|
mov_rbx,rax # put type_size in the right spot
|
|
mov_rax,[rip+DWORD] %global_token # Using global token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_rcx,[rip+DWORD] %global_symbol_list # Using global_symbol_list
|
|
call %sym_declare # Declare symbol
|
|
mov_[rip+DWORD],rax %global_symbol_list # global_symbol_list = sym_declare(global_token->s, type_size, global_symbol_list);
|
|
mov_rbx,[rip+DWORD] %global_token # Using global token
|
|
mov_rbx,[rbx] # global_token->next
|
|
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %semicolon # ";"
|
|
call %match # if(match(";", global_token->s))
|
|
cmp_rax, %0 # If true
|
|
jne %program_function # looks like not a match
|
|
|
|
# Deal with the global variable
|
|
mov_rbx,[rip+DWORD] %globals_list # Using globals_list
|
|
lea_rax,[rip+DWORD] %program_string_0 # ":GLOBAL_"
|
|
call %emit # Emit it
|
|
mov_rbx,rax # update globals_list
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global token
|
|
mov_rax,[rax+BYTE] !8 # global token->prev
|
|
mov_rax,[rax+BYTE] !16 # global token->prev->s
|
|
call %emit # Emit it
|
|
|
|
mov_rbx,rax # update globals_list
|
|
lea_rax,[rip+DWORD] %program_string_1 # "\nNULL\n"
|
|
call %emit # Emit it
|
|
mov_[rip+DWORD],rax %globals_list # update globals_list
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
jmp %new_type # go around again
|
|
|
|
:program_function
|
|
mov_rbx,[rip+DWORD] %global_token # Using global token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %open_paren # "("
|
|
call %match # if(match(";", global_token->s))
|
|
cmp_rax, %0 # If true
|
|
jne %program_error # Otherwise deal with error case
|
|
|
|
# Deal with function definition
|
|
call %declare_function # Lets get the parsing rolling
|
|
jmp %new_type # Keep looping through functions
|
|
|
|
:program_error
|
|
# Deal with the case of something we don't support
|
|
|
|
:program_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
# Strings needed by the program function
|
|
:program_string_0
|
|
":GLOBAL_"
|
|
|
|
:program_string_1
|
|
"
|
|
NULL
|
|
"
|
|
|
|
|
|
# declare_function function
|
|
# Receives nothing and returns nothing
|
|
# Sets current function and adds it to the global function list
|
|
:declare_function
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax, %0 # Using NULL
|
|
mov_[rip+DWORD],rax %current_count # current_count = 0
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global token
|
|
mov_rax,[rax+BYTE] !8 # global token->prev
|
|
mov_rax,[rax+BYTE] !16 # global token->prev->s
|
|
mov_rbx, %0 # NULL
|
|
mov_rcx,[rip+DWORD] %global_function_list # global_function_list
|
|
call %sym_declare # sym_declare(global_token->prev->s, NULL, global_function_list);
|
|
mov_[rip+DWORD],rax %function # function = sym_declare(global_token->prev->s, NULL, global_function_list);
|
|
mov_[rip+DWORD],rax %global_function_list # global_function_list = function
|
|
|
|
call %collect_arguments # collect all of the function arguments
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global token
|
|
mov_rax,[rax+BYTE] !16 # global token->s
|
|
lea_rbx,[rip+DWORD] %semicolon # ";"
|
|
call %match # IF global token->s == ";"
|
|
cmp_rax, %0 # If true
|
|
jne %declare_function_full # It was a prototype
|
|
|
|
# Deal with prototypes
|
|
mov_rax,[rip+DWORD] %global_token # Using global token
|
|
mov_rax,[rax] # global token->next
|
|
mov_[rip+DWORD],rax %global_token # global token = global token->next
|
|
jmp %declare_function_done # Move on
|
|
|
|
:declare_function_full
|
|
# Deal with full function definitions
|
|
lea_rax,[rip+DWORD] %declare_function_string_0 # "# Defining function "
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # function
|
|
mov_rax,[rax+BYTE] !16 # function->s
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %declare_function_string_1 # "\n:FUNCTION_"
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # function
|
|
mov_rax,[rax+BYTE] !16 # function->s
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %declare_function_string_3 # "\n"
|
|
call %emit_out # emit it
|
|
|
|
call %statement # Recursively get the function pieces
|
|
|
|
mov_rax,[rip+DWORD] %output_list # output
|
|
mov_rax,[rax+BYTE] !16 # output->s
|
|
lea_rbx,[rip+DWORD] %declare_function_string_2 # "ret\n"
|
|
call %match # IF output->s == "ret\n"
|
|
cmp_rax, %0 # If true we can skip adding it
|
|
je %declare_function_done # otherwise we need to add it
|
|
|
|
# Add the return to the end of a function lacking a return;
|
|
lea_rax,[rip+DWORD] %declare_function_string_2 # "ret\n"
|
|
call %emit_out # emit it
|
|
|
|
:declare_function_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:declare_function_string_0
|
|
"# Defining function "
|
|
|
|
:declare_function_string_1
|
|
"
|
|
:FUNCTION_"
|
|
|
|
:declare_function_string_2
|
|
"ret
|
|
"
|
|
|
|
:declare_function_string_3
|
|
"
|
|
"
|
|
|
|
|
|
# collect_arguments function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Adds arguments to the function definition
|
|
# holds struct type* type_size in RCX, then replace with struct token_list* a in RCX when type_size is used
|
|
:collect_arguments
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
:collect_arguments_loop
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %close_paren # ")"
|
|
call %match # IF global_token->S == ")"
|
|
cmp_rax, %0 # we reached the end
|
|
je %collect_arguments_done # be done
|
|
|
|
# deal with the case of there are arguments
|
|
call %type_name # Get the type
|
|
mov_rcx,rax # put type_size safely out of the way
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %close_paren # ")"
|
|
call %match # IF global_token->S == ")"
|
|
cmp_rax, %0 # is a foo(int, char,void) case
|
|
je %collect_arguments_common # deal with commas
|
|
|
|
# Trying second else
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %comma # ","
|
|
call %match # IF global_token->S == ","
|
|
cmp_rax, %0 # then deal with the common
|
|
je %collect_arguments_common # case of commas between arguments
|
|
|
|
# deal with foo(int a, char b)
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+DWORD] !16 # global_token->S
|
|
mov_rbx,rcx # put type_size in the right place
|
|
mov_rcx,[rip+DWORD] %function # Using function
|
|
mov_rcx,[rcx+BYTE] !32 # function->args
|
|
call %sym_declare # sym_declare(global_token->s, type_size, function->arguments);
|
|
mov_rcx,rax # put a in a safe place
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !32 # function->args
|
|
cmp_rax, %0 # IF function->args == NULL
|
|
jne %collect_arguments_another # otherwise it isn't the first
|
|
|
|
# Deal with the case of first argument in the function
|
|
mov_rax, %-8 # -8
|
|
mov_[rcx+BYTE],rax !32 # a->depth = -8
|
|
jmp %collect_arguments_next # get to next
|
|
|
|
:collect_arguments_another
|
|
# deal with the case of non-first arguments
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !32 # function->args
|
|
mov_rax,[rax+BYTE] !32 # function->args->depth
|
|
sub_rax, %8 # function->args->depth - 8
|
|
mov_[rcx+BYTE],rax !32 # a->depth = function->args->depth - 8
|
|
|
|
:collect_arguments_next
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_[rax+BYTE],rcx !32 # function->args = a
|
|
|
|
:collect_arguments_common
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+DWORD] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %comma # ","
|
|
call %match # IF global_token->S == ","
|
|
cmp_rax, %0 # then deal with the comma
|
|
jne %collect_arguments_loop # otherwise loop
|
|
|
|
# keep foo(bar(), 1) expressions working
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
jmp %collect_arguments_loop # keep going
|
|
|
|
:collect_arguments_done
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# statement function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Walks down global_token recursively to collect the contents of the function
|
|
:statement
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %open_curly_brace # "{"
|
|
call %match # IF global_token->S == "{"
|
|
jne %statement_label # otherwise try label
|
|
|
|
# deal with { statement }
|
|
call %recursive_statement # Statements inside of statements for days
|
|
jmp %statement_done # Be done
|
|
|
|
:statement_label
|
|
mov_al,[rbx] # global_token->S[0]
|
|
movzx_rax,al # make it useful
|
|
cmp_rax, %58 # IF global_token->S == ':'
|
|
jne %statement_local # otherwise try locals
|
|
|
|
# deal with labels
|
|
mov_rax,rbx # put global_token->S in the right spot
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %statement_string_0 # Using "\t#C goto label\n"
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
jmp %statement_done # be done
|
|
|
|
:statement_local
|
|
mov_rax,rbx # put global_token->S in the right place
|
|
lea_rbx,[rip+DWORD] %prim_types # pointer to primative types
|
|
call %lookup_type # See if found
|
|
cmp_rax, %0 # IF NULL == lookup_type(global_token->S, prim_types)
|
|
jne %statement_local_success # Sweet a new local
|
|
|
|
# Second chance
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %struct # "struct"
|
|
call %match # IF global_token->S == "struct"
|
|
cmp_rax, %0 # then we are a local
|
|
jne %statement_if # otherwise try IF
|
|
|
|
:statement_local_success
|
|
call %collect_local # Grab those locals
|
|
jmp %statement_done # be done
|
|
|
|
:statement_if
|
|
lea_rax,[rip+DWORD] %if_string # Using "if"
|
|
call %match # IF global_token->S == "if"
|
|
cmp_rax, %0 # then we have an if statement
|
|
jne %statement_do # otherwise try DO
|
|
|
|
# Deal with IF statement
|
|
call %process_if # DO IT
|
|
jmp %statement_done # be done
|
|
|
|
:statement_do
|
|
lea_rax,[rip+DWORD] %do_string # Using "do"
|
|
call %match # IF global_token->S == "do"
|
|
cmp_rax, %0 # then we have a do statement
|
|
jne %statement_while # otherwise try WHILE
|
|
|
|
# Deal with DO statement
|
|
call %process_do # DO IT
|
|
jmp %statement_done # be done
|
|
|
|
:statement_while
|
|
lea_rax,[rip+DWORD] %while_string # Using "while"
|
|
call %match # IF global_token->S == "while"
|
|
cmp_rax, %0 # then we have a while statement
|
|
jne %statement_for # otherwise try FOR
|
|
|
|
# Deal with WHILE statement
|
|
call %process_while # DO IT
|
|
jmp %statement_done # be done
|
|
|
|
:statement_for
|
|
lea_rax,[rip+DWORD] %for_string # Using "for"
|
|
call %match # IF global_token->S == "for"
|
|
cmp_rax, %0 # then we have a for statement
|
|
jne %statement_asm # otherwise try ASM
|
|
|
|
# Deal with FOR statement
|
|
call %process_for # DO IT
|
|
jmp %statement_done # be done
|
|
|
|
:statement_asm
|
|
lea_rax,[rip+DWORD] %asm_string # Using "asm"
|
|
call %match # IF global_token->S == "asm"
|
|
cmp_rax, %0 # then we have an asm statement
|
|
jne %statement_goto # otherwise try GOTO
|
|
|
|
# Deal with ASM statement
|
|
call %process_asm # Hit it
|
|
jmp %statement_done # be done
|
|
|
|
:statement_goto
|
|
lea_rax,[rip+DWORD] %goto_string # Using "goto"
|
|
call %match # IF global_token->S == "goto"
|
|
cmp_rax, %0 # then we have a goto statement
|
|
jne %statement_return # Otherwise try RETURN
|
|
|
|
# Deal with GOTO statement
|
|
lea_rax,[rip+DWORD] %statement_string_1 # Using "jmp %"
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %statement_string_2 # Using "\n"
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
lea_rax,[rip+DWORD] %statement_string_4 # Using "ERROR in statement\nMissing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure it has the required
|
|
jmp %statement_done # Be done
|
|
|
|
:statement_return
|
|
lea_rax,[rip+DWORD] %return_string # Using "return"
|
|
call %match # IF global_token->S == "return"
|
|
cmp_rax, %0 # then we have a return statement
|
|
jne %statement_break # Otherwise try BREAK
|
|
|
|
# Deal with RETURN Statement
|
|
call %return_result # Return anything they want
|
|
jmp %statement_done # be done
|
|
|
|
:statement_break
|
|
lea_rax,[rip+DWORD] %break_string # Using "break"
|
|
call %match # IF global_token->S == "break"
|
|
cmp_rax, %0 # then we have a break statement
|
|
jne %statement_continue # Otherwise try CONTINUE
|
|
|
|
# Deal with BREAK statement
|
|
call %process_break # Lets do some damage
|
|
jmp %statement_done # be done
|
|
|
|
:statement_continue
|
|
lea_rax,[rip+DWORD] %continue_string # Using "continue"
|
|
call %match # IF global_token->S == "continue"
|
|
cmp_rax, %0 # then we have a continue statement
|
|
jne %statement_else # Otherwise we are punting to an expression
|
|
|
|
# Deal with CONTINUE statement
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
lea_rax,[rip+DWORD] %statement_string_3 # Using "\n#continue statement\n"
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %statement_string_4 # Using "ERROR in statement\nMissing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Don't forget the ";"
|
|
jmp %statement_done # Be done
|
|
|
|
:statement_else
|
|
call %expression # Collect expression
|
|
lea_rax,[rip+DWORD] %statement_string_4 # Using "ERROR in statement\nMissing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # make sure we have it
|
|
|
|
:statement_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:statement_string_0
|
|
" #C goto label
|
|
"
|
|
|
|
:statement_string_1
|
|
"jmp %"
|
|
|
|
:statement_string_2
|
|
"
|
|
"
|
|
|
|
:statement_string_3
|
|
"
|
|
#continue statement
|
|
"
|
|
|
|
:statement_string_4
|
|
"ERROR in statement
|
|
Missing ;
|
|
"
|
|
|
|
|
|
# recursive_statement function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Walks the global_token list to build the contents of statements
|
|
# Uses struct token_list* frame in RCX
|
|
:recursive_statement
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
mov_rcx,[rip+DWORD] %function # Using function
|
|
mov_rcx,[rcx+BYTE] !8 # frame = function->locals
|
|
|
|
:recursive_statement_loop
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %close_curly_brace # Using "}"
|
|
call %match # IF global_token->S == "}"
|
|
cmp_rax, %0 # Then we are done recursing
|
|
je %recursive_statement_cleanup # and then we clean up
|
|
|
|
# Deal with the recursive calls
|
|
call %statement # Deal with another statement
|
|
jmp %recursive_statement_loop # loop some more
|
|
|
|
:recursive_statement_cleanup
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
lea_rax,[rip+DWORD] %recursive_statement_string_0 # Using "ret\n"
|
|
mov_rbx,[rip+DWORD] %output_list # Using output
|
|
mov_rbx,[rbx+BYTE] !16 # output->S
|
|
call %match # IF output->S == "ret\n"
|
|
cmp_rax, %0 # Then we can skip the clean up
|
|
je %recursive_statement_done # and be done
|
|
|
|
# Deal with cleanup
|
|
mov_rbx,[rip+DWORD] %function # Using function
|
|
mov_rbx,[rbx+BYTE] !8 # i = function->locals
|
|
lea_rax,[rip+DWORD] %recursive_statement_string_1 # Using "pop_rbx\t# _recursive_statement_locals\n"
|
|
|
|
:recursive_statement_locals
|
|
cmp_rbx,rcx # IF frame != i
|
|
je %recursive_statement_done # Otherwise be done
|
|
|
|
# Lets emit
|
|
call %emit_out # emit it
|
|
mov_rbx,[rbx] # i = i->next
|
|
jmp %recursive_statement_locals # keep going
|
|
|
|
:recursive_statement_done
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_[rax+BYTE],rcx !8 # function->locals = frame
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:recursive_statement_string_0
|
|
"ret
|
|
"
|
|
|
|
:recursive_statement_string_1
|
|
"pop_rbx # _recursive_statement_locals
|
|
"
|
|
|
|
|
|
# return_result function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Cleans up function and generates return
|
|
# Also handles returning expressions
|
|
:return_result
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # make it useful
|
|
cmp_rax, %59 # If global_token->S[0] == ';'
|
|
je %return_result_cleanup # Go straight to cleanup
|
|
|
|
call %expression # get the expression we are returning
|
|
|
|
:return_result_cleanup
|
|
lea_rax,[rip+DWORD] %return_result_string_0 # Using "ERROR in return_result\nMISSING ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
mov_rbx,[rip+DWORD] %function # Using function
|
|
mov_rbx,[rbx+BYTE] !8 # function->locals
|
|
lea_rax,[rip+DWORD] %return_result_string_1 # Using "pop_rbx\t# _return_result_locals\n"
|
|
:return_result_locals
|
|
cmp_rbx, %0 # IF NULL == i
|
|
je %return_result_done # Be done
|
|
|
|
call %emit_out # Emit out pop
|
|
mov_rbx,[rbx] # i = i->NEXT
|
|
jmp %return_result_locals # Keep going
|
|
|
|
:return_result_done
|
|
lea_rax,[rip+DWORD] %return_result_string_2 # Using "ret\n"
|
|
call %emit_out # Emit it
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:return_result_string_0
|
|
"ERROR in return_result
|
|
MISSING ;
|
|
"
|
|
|
|
:return_result_string_1
|
|
"pop_rbx # _return_result_locals
|
|
"
|
|
|
|
:return_result_string_2
|
|
"ret
|
|
"
|
|
|
|
|
|
# collect_local function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Walks global_token list to create function locals
|
|
# Uses RCX for struct token_list* A
|
|
:collect_local
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
call %type_name # Get the local's type
|
|
|
|
mov_rbx,rax # Put struct type* type_size in the right place
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_rcx,[rip+DWORD] %function # Using function
|
|
mov_rcx,[rcx+BYTE] !8 # function->locals
|
|
call %sym_declare # Declare it
|
|
mov_rcx,rax # put it away safely
|
|
|
|
# Try for main
|
|
lea_rax,[rip+DWORD] %main_string # Using "main"
|
|
mov_rbx,[rip+DWORD] %function # Using function
|
|
mov_rbx,[rbx+BYTE] !16 # function->S
|
|
call %match # IF match("main", function->s)
|
|
cmp_rax, %0 # possible
|
|
jne %collect_local_fresh # try to see if fresh function
|
|
|
|
# Ok we are in main, now to see if main is fresh
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !8 # function->locals
|
|
cmp_rax, %0 # IF NULL == function->locals
|
|
jne %collect_local_fresh # try to see if fresh function
|
|
|
|
# Sweet we are in a fresh main
|
|
mov_rax, %-40 # We start at -40
|
|
mov_[rcx+BYTE],rax !32 # a->DEPTH = -40
|
|
jmp %collect_local_common # Go to the commons
|
|
|
|
:collect_local_fresh
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !32 # function->args
|
|
cmp_rax, %0 # IF NULL == function->args
|
|
jne %collect_local_first # Otherwise see if first
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !8 # function->locals
|
|
cmp_rax, %0 # IF NULL == function->locals
|
|
jne %collect_local_first # Otherwise try first
|
|
|
|
# Sweet we are in a fresh function
|
|
mov_rax, %-16 # We start at -16
|
|
mov_[rcx+BYTE],rax !32 # a->DEPTH = -16
|
|
jmp %collect_local_common # Go to the commons
|
|
|
|
:collect_local_first
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !8 # function->locals
|
|
cmp_rax, %0 # IF NULL == function->locals
|
|
jne %collect_local_else # Looks like we are just another local
|
|
|
|
# Ok we are the first local
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !32 # function->args
|
|
mov_rax,[rax+BYTE] !32 # function->args->depth
|
|
sub_rax, %16 # function->arguments->depth - 16
|
|
mov_[rcx+BYTE],rax !32 # a->DEPTH = function->arguments->depth - 16
|
|
jmp %collect_local_common # Go to the commons
|
|
|
|
:collect_local_else
|
|
# Always the last to know
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !8 # function->locals
|
|
mov_rax,[rax+BYTE] !32 # function->locals->depth
|
|
sub_rax, %8 # function->locals->depth - 8
|
|
mov_[rcx+BYTE],rax !32 # a->DEPTH = function->locals->depth - 8
|
|
|
|
:collect_local_common
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
|
|
mov_[rax+BYTE],rcx !8 # function->locals = a
|
|
mov_rcx,[rcx+BYTE] !16 # a->S
|
|
|
|
lea_rax,[rip+DWORD] %collect_local_string_0 # Using "# Defining local "
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %collect_local_string_1 # Using "\n"
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rbx,[rax+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %equal # Using "="
|
|
call %match # IF match("=", global_token->s)
|
|
cmp_rax, %0 # Deal with assignment
|
|
jne %collect_local_done # Otherwise finish it
|
|
|
|
# Deal with assignment
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
call %expression # Recurse
|
|
|
|
:collect_local_done
|
|
lea_rax,[rip+DWORD] %collect_local_string_2 # Using "ERROR in collect_local\nMissing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
lea_rax,[rip+DWORD] %collect_local_string_3 # Using "push_rax\t#"
|
|
call %emit_out # emit it
|
|
|
|
mov_rax,rcx # put A->S where it belongs
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %collect_local_string_1 # Using "\n"
|
|
call %emit_out # emit it
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:collect_local_string_0
|
|
"# Defining local "
|
|
|
|
:collect_local_string_1
|
|
"
|
|
"
|
|
|
|
:collect_local_string_2
|
|
"ERROR in collect_local
|
|
Missing ;
|
|
"
|
|
|
|
:collect_local_string_3
|
|
"push_rax #"
|
|
|
|
|
|
# process_asm function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Simply inlines the asm statements
|
|
# Uses RBX for global_token temp storage
|
|
:process_asm
|
|
push_rbx # Protect RBX
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %process_asm_string_0 # Using "ERROR in process_asm\nMISSING (\n"
|
|
lea_rbx,[rip+DWORD] %open_paren # Using "("
|
|
call %require_match # Make sure we have it
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
:process_asm_iter
|
|
mov_rax,[rbx+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %34 # IF global_token->S[0] == '"'
|
|
jne %process_asm_done # Otherwise be done
|
|
|
|
mov_rax,[rbx+BYTE] !16 # global_token->S
|
|
add_rax, %1 # global_token->S + 1
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %process_asm_string_1 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rbx,[rbx] # global_token->NEXT
|
|
mov_[rip+DWORD],rbx %global_token # global_token = global_token->NEXT
|
|
jmp %process_asm_iter # keep going
|
|
|
|
:process_asm_done
|
|
lea_rax,[rip+DWORD] %process_asm_string_2 # Using "ERROR in process_asm\nMISSING )\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
|
|
lea_rax,[rip+DWORD] %process_asm_string_3 # Using "ERROR in process_asm\nMISSING ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:process_asm_string_0
|
|
"ERROR in process_asm
|
|
MISSING (
|
|
"
|
|
|
|
:process_asm_string_1
|
|
"
|
|
"
|
|
|
|
:process_asm_string_2
|
|
"ERROR in process_asm
|
|
MISSING )
|
|
"
|
|
|
|
|
|
:process_asm_string_3
|
|
"ERROR in process_asm
|
|
MISSING ;
|
|
"
|
|
|
|
|
|
# process_if function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Increments current_count recurses into expression + statement
|
|
# Uses RCX for char* NUMBER_STRING
|
|
:process_if
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rip+DWORD] %current_count # Using current count
|
|
mov_rbx,rax # Preparing for update
|
|
add_rbx, %1 # current_count + 1
|
|
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
|
|
call %numerate_number # convert to string
|
|
mov_rcx,rax # put NUMBER_STRING in place
|
|
|
|
lea_rax,[rip+DWORD] %process_if_string_0 # Using "# IF_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %process_if_string_1 # Using "ERROR in process_if\nMISSING (\n"
|
|
lea_rbx,[rip+DWORD] %open_paren # Using "("
|
|
call %require_match # Make sure we have it
|
|
|
|
call %expression # Recurse to get the IF(...) part
|
|
|
|
lea_rax,[rip+DWORD] %process_if_string_2 # Using "test_rax,rax\nje %ELSE_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_if_string_3 # Using "ERROR in process_if\nMISSING )\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
|
|
call %statement # Recursive to get the IF(){...} part
|
|
|
|
lea_rax,[rip+DWORD] %process_if_string_4 # Using "jmp %_END_IF_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_if_string_5 # Using ":ELSE_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %else_string # Using "else"
|
|
call %match # IF global_token->S == "else"
|
|
cmp_rax, %0 # Then we need to collect the else too
|
|
jne %process_if_done # Otherwise finish up
|
|
|
|
# deal with else statement
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
call %statement # Recurse to get the ELSE {...} part
|
|
|
|
:process_if_done
|
|
lea_rax,[rip+DWORD] %process_if_string_6 # Using ":_END_IF_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:process_if_string_0
|
|
"# IF_"
|
|
|
|
:process_if_string_1
|
|
"ERROR in process_if
|
|
MISSING (
|
|
"
|
|
|
|
:process_if_string_2
|
|
"test_rax,rax
|
|
je %ELSE_"
|
|
|
|
:process_if_string_3
|
|
"ERROR in process_if
|
|
MISSING )
|
|
"
|
|
|
|
:process_if_string_4
|
|
"jmp %_END_IF_"
|
|
|
|
:process_if_string_5
|
|
":ELSE_"
|
|
|
|
:process_if_string_6
|
|
":_END_IF_"
|
|
|
|
|
|
# save_break_frame microfunction
|
|
# Overwrites RAX and RBX
|
|
# Saves break frame on stack
|
|
# Returns to caller
|
|
:save_break_frame
|
|
pop_rbx # Save return Address
|
|
mov_rax,[rip+DWORD] %break_frame # Get break_frame
|
|
push_rax # Store as nested_locals
|
|
mov_rax,[rip+DWORD] %break_target_head # Get break_target_head
|
|
push_rax # Store as nested_break_head
|
|
mov_rax,[rip+DWORD] %break_target_func # Get break_target_func
|
|
push_rax # Store as nested_break_func
|
|
mov_rax,[rip+DWORD] %break_target_num # Get break_target_num
|
|
push_rax # Store as nested_break_num
|
|
push_rbx # Put return back in place
|
|
ret # Return to caller
|
|
|
|
|
|
# restore_break_frame microfunction
|
|
# Overwrites RAX and RBX
|
|
# Restores break frame from stack
|
|
# Returns to caller
|
|
:restore_break_frame
|
|
pop_rbx # Save return Address
|
|
pop_rax # Get nested_break_num
|
|
mov_[rip+DWORD],rax %break_target_num # Restore break_target_num
|
|
pop_rax # Get nested_break_func
|
|
mov_[rip+DWORD],rax %break_target_func # Restore break_target_func
|
|
pop_rax # Get nested_break_head
|
|
mov_[rip+DWORD],rax %break_target_head # Restore break_target_head
|
|
pop_rax # Get nested_locals
|
|
mov_[rip+DWORD],rax %break_frame # Restore break_frame
|
|
push_rbx # Put return back in place
|
|
ret # Return to caller
|
|
|
|
|
|
# set_break_frame microfunction
|
|
# Receives char* head in RAX and char* num in RBX
|
|
# Overwrites RAX and RBX
|
|
# Returns to calling function
|
|
:set_break_frame
|
|
mov_[rip+DWORD],rax %break_target_head # update break_target_head
|
|
mov_[rip+DWORD],rbx %break_target_num # update break_target_num
|
|
mov_rbx,[rip+DWORD] %function # Using function
|
|
mov_rax,[rbx+BYTE] !8 # function->LOCALS
|
|
mov_[rip+DWORD],rax %break_frame # break_frame = function->LOCALS
|
|
mov_rax,[rbx+BYTE] !16 # function->S
|
|
mov_[rip+DWORD],rax %break_target_func # break_target_func = function->S
|
|
ret # Return to sender
|
|
|
|
|
|
# process_do function
|
|
# Receives Nothing
|
|
# Returns Nothing
|
|
# Increments current_count and leverages save/restore_break_frame pieces
|
|
# Uses RCX for char* NUMBER_STRING
|
|
:process_do
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
call %save_break_frame # Save the frame
|
|
|
|
mov_rax,[rip+DWORD] %current_count # Using current count
|
|
mov_rbx,rax # Preparing for update
|
|
add_rbx, %1 # current_count + 1
|
|
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
|
|
call %numerate_number # convert to string
|
|
mov_rcx,rax # put NUMBER_STRING in place
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_0 # Using "DO_END_"
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %set_break_frame # Set the frame
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_1 # Using ":DO_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
call %statement # Do the DO {...} part
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_2 # Using "ERROR in process_do\nMISSING while\n"
|
|
lea_rbx,[rip+DWORD] %while_string # Using "while"
|
|
call %require_match # Make sure we have it
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_3 # Using "ERROR in process_do\nMISSING (\n"
|
|
lea_rbx,[rip+DWORD] %open_paren # Using "("
|
|
call %require_match # Make sure we have it
|
|
|
|
call %expression # Do the WHILE (...) part
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_4 # Using "ERROR in process_do\nMISSING )\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_5 # Using "ERROR in process_do\nMISSING ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_6 # Using "test_rax,rax\njne %DO_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_do_string_7 # Using ":DO_END_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
call %restore_break_frame # Restore the old break frame
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:process_do_string_0
|
|
"DO_END_"
|
|
|
|
:process_do_string_1
|
|
":DO_"
|
|
|
|
:process_do_string_2
|
|
"ERROR in process_do
|
|
MISSING while
|
|
"
|
|
|
|
:process_do_string_3
|
|
"ERROR in process_do
|
|
MISSING (
|
|
"
|
|
|
|
:process_do_string_4
|
|
"ERROR in process_do
|
|
MISSING )
|
|
"
|
|
|
|
:process_do_string_5
|
|
"ERROR in process_do
|
|
MISSING ;
|
|
"
|
|
|
|
:process_do_string_6
|
|
"test_rax,rax
|
|
jne %DO_"
|
|
|
|
:process_do_string_7
|
|
":DO_END_"
|
|
|
|
|
|
# process_while function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Increments current_count and leverages save/restore_break_frame pieces
|
|
# Uses RCX for char* NUMBER_STRING
|
|
:process_while
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
call %save_break_frame # Save break_frame
|
|
|
|
mov_rax,[rip+DWORD] %current_count # Using current count
|
|
mov_rbx,rax # Preparing for update
|
|
add_rbx, %1 # current_count + 1
|
|
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
|
|
call %numerate_number # convert to string
|
|
mov_rcx,rax # put NUMBER_STRING in place
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_0 # Using "END_WHILE_"
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %set_break_frame # Set it and forget it
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_1 # Using ":WHILE_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_2 # Using "ERROR in process_while\nMISSING (\n"
|
|
lea_rbx,[rip+DWORD] %open_paren # Using "("
|
|
call %require_match # Make sure we have it
|
|
|
|
call %expression # Deal with the WHILE (...) part
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_3 # Using "test_rax,rax\nje %END_WHILE_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_4 # Using "# THEN_while_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_5 # Using "ERROR in process_while\nMISSING )\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
|
|
call %statement # Deal with the {....} part
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_6 # Using "jmp %WHILE_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_while_string_7 # Using ":END_WHILE_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
call %restore_break_frame # Restore the old break frame
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:process_while_string_0
|
|
"END_WHILE_"
|
|
|
|
:process_while_string_1
|
|
":WHILE_"
|
|
|
|
:process_while_string_2
|
|
"ERROR in process_while
|
|
MISSING (
|
|
"
|
|
|
|
:process_while_string_3
|
|
"test_rax,rax
|
|
je %END_WHILE_"
|
|
|
|
:process_while_string_4
|
|
"# THEN_while_"
|
|
|
|
:process_while_string_5
|
|
"ERROR in process_while
|
|
MISSING )
|
|
"
|
|
|
|
:process_while_string_6
|
|
"jmp %WHILE_"
|
|
|
|
:process_while_string_7
|
|
":END_WHILE_"
|
|
|
|
|
|
# process_for function
|
|
# Receives Nothing
|
|
# Returns Nothing
|
|
# Increments current_count and leverages save/restore_break_frame pieces
|
|
# Uses RCX for char* NUMBER_STRING
|
|
:process_for
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
call %save_break_frame # Save the frame
|
|
|
|
mov_rax,[rip+DWORD] %current_count # Using current count
|
|
mov_rbx,rax # Preparing for update
|
|
add_rbx, %1 # current_count + 1
|
|
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
|
|
call %numerate_number # convert to string
|
|
mov_rcx,rax # put NUMBER_STRING in place
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_0 # Using "FOR_END_"
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %set_break_frame # Set it and forget it
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_1 # Using "# FOR_initialization_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_2 # Using "ERROR in process_for\nMISSING (\n"
|
|
lea_rbx,[rip+DWORD] %open_paren # Using "("
|
|
call %require_match # Make Sure we have it
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %semicolon # Using ";"
|
|
call %match # IF global_token->S == ";"
|
|
cmp_rax, %0 # Then no initializer
|
|
je %process_for_terminator # And skip getting the expression
|
|
|
|
# Deal with FOR (...; case
|
|
call %expression # Get the FOR ( ... ; part
|
|
|
|
:process_for_terminator
|
|
lea_rax,[rip+DWORD] %process_for_string_3 # Using ":FOR_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_4 # Using "ERROR in process_for\nMISSING ;1\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
call %expression # Get the FOR ( ; ... ; Part
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_5 # Using "test_rax,rax\nje %FOR_END_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_6 # Using "jmp %FOR_THEN_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_7 # Using ":FOR_ITER_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_8 # Using "ERROR in process_for\nMISSING ;2\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
call %expression # Get the FOR (;;...) part
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_9 # Using "jmp %FOR_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_10 # Using ":FOR_THEN_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_11 # Using "ERROR in process_for\nMISSING )\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
|
|
call %statement # Get FOR (;;) {...} part
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_12 # Using "jmp %FOR_ITER_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Passing NUMBER_STRING
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
lea_rax,[rip+DWORD] %process_for_string_13 # Using ":FOR_END_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID_out # uniqueID_out(function->s, number_string)
|
|
|
|
call %restore_break_frame # Restore the old break frame
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:process_for_string_0
|
|
"FOR_END_"
|
|
|
|
:process_for_string_1
|
|
"# FOR_initialization_"
|
|
|
|
:process_for_string_2
|
|
"ERROR in process_for
|
|
MISSING (
|
|
"
|
|
|
|
:process_for_string_3
|
|
":FOR_"
|
|
|
|
:process_for_string_4
|
|
"ERROR in process_for
|
|
MISSING ;1
|
|
"
|
|
|
|
:process_for_string_5
|
|
"test_rax,rax
|
|
je %FOR_END_"
|
|
|
|
:process_for_string_6
|
|
"jmp %FOR_THEN_"
|
|
|
|
:process_for_string_7
|
|
":FOR_ITER_"
|
|
|
|
:process_for_string_8
|
|
"ERROR in process_for
|
|
MISSING ;2
|
|
"
|
|
|
|
:process_for_string_9
|
|
"jmp %FOR_"
|
|
|
|
:process_for_string_10
|
|
":FOR_THEN_"
|
|
|
|
:process_for_string_11
|
|
"ERROR in process_for
|
|
MISSING )
|
|
"
|
|
|
|
:process_for_string_12
|
|
"jmp %FOR_ITER_"
|
|
|
|
:process_for_string_13
|
|
":FOR_END_"
|
|
|
|
|
|
# process_break function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Handles the break out of loops case
|
|
# Uses RBX for struct token_list* break_frame and RCX for struct token_list* I
|
|
:process_break
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rip+DWORD] %break_target_head # Catch big error
|
|
cmp_rax, %0 # IF(NULL == break_target_head)
|
|
je %process_break_bad # I'm sorry Mr White but you have stage-3 lung cancer
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rcx,[rax+BYTE] !8 # I = function->LOCALS
|
|
mov_rbx,[rip+DWORD] %break_frame # Put break_frame in the right spot
|
|
lea_rax,[rip+DWORD] %process_break_string_1 # Using "pop_rbx\t# break_cleanup_locals\n"
|
|
|
|
:process_break_iter
|
|
cmp_rcx, %0 # IF (NULL == I)
|
|
je %process_break_cleaned # We are done
|
|
|
|
cmp_rbx,rcx # IF I != break_frame
|
|
je %process_break_cleaned # We are done
|
|
|
|
call %emit_out # Emit it
|
|
mov_rcx,[rcx] # I = I->NEXT
|
|
jmp %process_break_iter # Keep looping
|
|
|
|
:process_break_cleaned
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %process_break_string_2 # Using "jmp %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %break_target_head # Get what we are in
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %break_target_func # Get what function we are in
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %underline # Using "_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %break_target_num # Get dem digits
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %process_break_string_3 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %process_break_string_4 # Using "ERROR in break statement\nMissing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
:process_break_bad
|
|
# Breaking badly
|
|
mov_r15, %2 # write to standard error
|
|
# call %line_error # Write useful debug info
|
|
mov_rax,rcx # put S in the right place
|
|
call %File_Print # print it
|
|
|
|
lea_rax,[rip+DWORD] %process_break_string_0 # Ending string
|
|
call %File_Print # print it
|
|
jmp %Exit_Failure # Abort Hard
|
|
|
|
:process_break_string_0
|
|
"Not inside of a loop or case statement"
|
|
|
|
:process_break_string_1
|
|
"pop_rbx # break_cleanup_locals
|
|
"
|
|
|
|
:process_break_string_2
|
|
"jmp %"
|
|
|
|
:process_break_string_3
|
|
"
|
|
"
|
|
|
|
:process_break_string_4
|
|
"ERROR in break statement
|
|
Missing ;
|
|
"
|
|
|
|
|
|
# expression function
|
|
# Receives Nothing
|
|
# Returns Nothing
|
|
# Walks global_token and updates output_list
|
|
# Uses RAX and RBX for match and RCX for char* store
|
|
:expression
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
call %bitwise_expr # Collect bitwise expressions
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %equal # "="
|
|
call %match # IF global_token->S == "="
|
|
cmp_rax, %0 # We have to deal with assignment
|
|
jne %expression_done # Looks like nope
|
|
|
|
# Deal with possible assignment
|
|
lea_rcx,[rip+DWORD] %expression_string_1 # Assume "mov_[rbx],al\n" by default
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !8 # global_token->PREV
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->PREV->S
|
|
lea_rax,[rip+DWORD] %close_bracket # Using "]"
|
|
call %match # IF global_token->S == "]"
|
|
cmp_rax, %0 # Then we might have a char
|
|
jne %expression_int # Otherwise INT
|
|
|
|
mov_rbx,[rip+DWORD] %current_target # Using current_target
|
|
mov_rbx,[rbx+BYTE] !48 # current_target->NAME
|
|
lea_rax,[rip+DWORD] %type_char_indirect_name # Using "char*"
|
|
call %match # Intentional inefficiency because I feel like it
|
|
cmp_rax, %0 # IF current_target->NAME == "char*"
|
|
jne %expression_int # Do char anyway
|
|
|
|
jmp %expression_common # Looks like we have to use "mov_[rbx],al\n"
|
|
|
|
:expression_int
|
|
lea_rcx,[rip+DWORD] %expression_string_0 # Use "mov_[rbx],rax\n"
|
|
|
|
:expression_common
|
|
lea_rax,[rip+DWORD] %expression # Passing expression
|
|
call %common_recursion # Recurse
|
|
mov_rax,rcx # Using Store
|
|
call %emit_out # Emit it
|
|
mov_rax, %0 # Using NULL
|
|
mov_[rip+DWORD],rax %current_target # current_target = NULL
|
|
|
|
:expression_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:expression_string_0
|
|
"mov_[rbx],rax
|
|
"
|
|
|
|
:expression_string_1
|
|
"mov_[rbx],al
|
|
"
|
|
|
|
|
|
# bitwise_expr function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Walks global_token list and updates output list
|
|
# Just calls other functions
|
|
:bitwise_expr
|
|
call %relational_expr # Walk up the tree
|
|
call %bitwise_expr_stub # Let general recursion do the work
|
|
ret
|
|
|
|
|
|
# bitwise_expr_stub function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Just calls general_recursion a bunch
|
|
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
|
|
:bitwise_expr_stub
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
|
|
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
|
|
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_0 # Using "and_rax,rbx\n"
|
|
lea_rcx,[rip+DWORD] %bitwise_and # Using "&"
|
|
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
|
|
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_0 # Using "and_rax,rbx\n"
|
|
lea_rcx,[rip+DWORD] %logical_and # Using "&&"
|
|
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
|
|
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_1 # Using "or_rax,rbx\n"
|
|
lea_rcx,[rip+DWORD] %bitwise_or # Using "|"
|
|
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
|
|
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_1 # Using "or_rax,rbx\n"
|
|
lea_rcx,[rip+DWORD] %logical_or # Using "||"
|
|
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
|
|
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_2 # Using "xor_rax,rbx\n"
|
|
lea_rcx,[rip+DWORD] %bitwise_xor # Using "^"
|
|
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:bitwise_expr_stub_string_0
|
|
"and_rax,rbx
|
|
"
|
|
|
|
:bitwise_expr_stub_string_1
|
|
"or_rax,rbx
|
|
"
|
|
|
|
:bitwise_expr_stub_string_2
|
|
"xor_rax,rbx
|
|
"
|
|
|
|
|
|
# relational_expr function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Walks global_token list and updates output list
|
|
# just calls other function
|
|
:relational_expr
|
|
call %additive_expr # Walk up the tree
|
|
call %relational_expr_stub # Recurse
|
|
ret
|
|
|
|
|
|
# relational_expr_stub function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Just calls general_recursion a bunch
|
|
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
|
|
:relational_expr_stub
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
|
|
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
|
|
lea_rbx,[rip+DWORD] %relational_expr_stub_string_0 # Using "cmp_rbx,rax\nsetl_al\nmovzx_rax,al\n"
|
|
lea_rcx,[rip+DWORD] %less_than_string # Using "<"
|
|
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
|
|
lea_rbx,[rip+DWORD] %relational_expr_stub_string_1 # Using "cmp_rbx,rax\nsetle_al\nmovzx_rax,al\n"
|
|
lea_rcx,[rip+DWORD] %less_than_equal_string # Using "<="
|
|
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
|
|
lea_rbx,[rip+DWORD] %relational_expr_stub_string_2 # Using "cmp_rbx,rax\nsetge_al\nmovzx_rax,al\n"
|
|
lea_rcx,[rip+DWORD] %greater_than_equal_string # Using ">="
|
|
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
|
|
lea_rbx,[rip+DWORD] %relational_expr_stub_string_3 # Using "cmp_rbx,rax\nsetg_al\nmovzx_rax,al\n"
|
|
lea_rcx,[rip+DWORD] %greater_than_string # Using ">"
|
|
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
|
|
lea_rbx,[rip+DWORD] %relational_expr_stub_string_4 # Using "cmp_rbx,rax\nsete_al\nmovzx_rax,al\n"
|
|
lea_rcx,[rip+DWORD] %equal_to_string # Using "=="
|
|
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
|
|
lea_rbx,[rip+DWORD] %relational_expr_stub_string_5 # Using "cmp_rbx,rax\nsetne_al\nmovzx_rax,al\n"
|
|
lea_rcx,[rip+DWORD] %not_equal_string # Using "!="
|
|
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:relational_expr_stub_string_0
|
|
"cmp_rbx,rax
|
|
setl_al
|
|
movzx_rax,al
|
|
"
|
|
|
|
:relational_expr_stub_string_1
|
|
"cmp_rbx,rax
|
|
setle_al
|
|
movzx_rax,al
|
|
"
|
|
|
|
:relational_expr_stub_string_2
|
|
"cmp_rbx,rax
|
|
setge_al
|
|
movzx_rax,al
|
|
"
|
|
|
|
:relational_expr_stub_string_3
|
|
"cmp_rbx,rax
|
|
setg_al
|
|
movzx_rax,al
|
|
"
|
|
|
|
:relational_expr_stub_string_4
|
|
"cmp_rbx,rax
|
|
sete_al
|
|
movzx_rax,al
|
|
"
|
|
|
|
:relational_expr_stub_string_5
|
|
"cmp_rbx,rax
|
|
setne_al
|
|
movzx_rax,al
|
|
"
|
|
|
|
|
|
# additive_expr function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Walks global_token list and updates output list
|
|
# just calls other function
|
|
:additive_expr
|
|
call %postfix_expr # Walk up the tree
|
|
call %additive_expr_stub # Recurse
|
|
ret
|
|
|
|
|
|
# additive_expr_stub function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Just calls general_recursion a bunch
|
|
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
|
|
:additive_expr_stub
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
|
|
lea_rbx,[rip+DWORD] %additive_expr_stub_string_0 # Using "add_rax,rbx\n"
|
|
lea_rcx,[rip+DWORD] %plus_string # Using "+"
|
|
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
|
|
lea_rbx,[rip+DWORD] %additive_expr_stub_string_1 # Using "sub_rbx,rax\nmov_rax,rbx\n"
|
|
lea_rcx,[rip+DWORD] %minus_string # Using "-"
|
|
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
|
|
lea_rbx,[rip+DWORD] %additive_expr_stub_string_2 # Using "mul_rbx\n"
|
|
lea_rcx,[rip+DWORD] %multiply_string # Using "*"
|
|
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
|
|
lea_rbx,[rip+DWORD] %additive_expr_stub_string_3 # Using "xchg_rbx,rax\nmov_rdx, %0\ndiv_rbx\n"
|
|
lea_rcx,[rip+DWORD] %divide_string # Using "/"
|
|
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
|
|
lea_rbx,[rip+DWORD] %additive_expr_stub_string_4 # Using "xchg_rbx,rax\nmov_rdx, %0\ndiv_rbx\nmov_rax,rdx\n"
|
|
lea_rcx,[rip+DWORD] %modulus_string # Using "%"
|
|
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
|
|
lea_rbx,[rip+DWORD] %additive_expr_stub_string_5 # Using "mov_rcx,rax\nmov_rax,rbx\nsal_rax,cl\n"
|
|
lea_rcx,[rip+DWORD] %left_shift_string # Using "<<"
|
|
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
|
|
lea_rbx,[rip+DWORD] %additive_expr_stub_string_6 # Using "mov_rcx,rax\nmov_rax,rbx\nsar_rax,cl\n"
|
|
lea_rcx,[rip+DWORD] %right_shift_string # Using ">>"
|
|
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
|
|
call %general_recursion # Hit it
|
|
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:additive_expr_stub_string_0
|
|
"add_rax,rbx
|
|
"
|
|
|
|
:additive_expr_stub_string_1
|
|
"sub_rbx,rax
|
|
mov_rax,rbx
|
|
"
|
|
|
|
:additive_expr_stub_string_2
|
|
"mul_rbx
|
|
"
|
|
|
|
:additive_expr_stub_string_3
|
|
"xchg_rbx,rax
|
|
mov_rdx, %0
|
|
div_rbx
|
|
"
|
|
|
|
:additive_expr_stub_string_4
|
|
"xchg_rbx,rax
|
|
mov_rdx, %0
|
|
div_rbx
|
|
mov_rax,rdx
|
|
"
|
|
|
|
:additive_expr_stub_string_5
|
|
"mov_rcx,rax
|
|
mov_rax,rbx
|
|
sal_rax,cl
|
|
"
|
|
|
|
:additive_expr_stub_string_6
|
|
"mov_rcx,rax
|
|
mov_rax,rbx
|
|
sar_rax,cl
|
|
"
|
|
|
|
|
|
# postfix_expr function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Walks global_token list and updates output list
|
|
# just calls other function
|
|
:postfix_expr
|
|
call %primary_expr # Walk up the tree
|
|
call %postfix_expr_stub # Recurse
|
|
ret
|
|
|
|
|
|
# postfix_expr_stub function
|
|
# Receives nothing
|
|
# Returns Nothing
|
|
# Checks for "[" and "->" and deals with them otherwise does nothing
|
|
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
|
|
:postfix_expr_stub
|
|
push_rbx # Protect RBX
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %open_bracket # Using "["
|
|
call %match # IF global_token->S == "["
|
|
cmp_rax, %0 # then we have an array
|
|
jne %postfix_expr_stub_arrow # Otherwise try arrow
|
|
|
|
# Deal with array
|
|
call %postfix_expr_array # Get it
|
|
call %postfix_expr_stub # Recurse
|
|
|
|
:postfix_expr_stub_arrow
|
|
lea_rax,[rip+DWORD] %arrow_string # Using "->"
|
|
call %match # IF global_token->S == "->"
|
|
cmp_rax, %0 # Then we need to deal with struct offsets
|
|
jne %postfix_expr_stub_done # Otherwise be done
|
|
|
|
# Deal with arrow
|
|
call %postfix_expr_arrow # Get it
|
|
call %postfix_expr_stub # Recurse
|
|
|
|
:postfix_expr_stub_done
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# unary_expr_sizeof function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Uses RCX for A->SIZE
|
|
:unary_expr_sizeof
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_0 # Using "ERROR in unary_expr\nMissing (\n"
|
|
lea_rbx,[rip+DWORD] %open_paren # Using "("
|
|
call %require_match # Make sure we have it
|
|
|
|
call %type_name # Get the type
|
|
mov_rcx,[rax+BYTE] !8 # Set A->TYPE
|
|
|
|
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_1 # Using "ERROR in unary_expr\nMissing )\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
|
|
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_2 # Using "mov_rax, %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,rcx # Put A->SIZE in the right place
|
|
call %numerate_number # Turn into string
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_3 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:unary_expr_sizeof_string_0
|
|
"ERROR in unary_expr
|
|
Missing (
|
|
"
|
|
|
|
:unary_expr_sizeof_string_1
|
|
"ERROR in unary_expr
|
|
Missing )
|
|
"
|
|
|
|
:unary_expr_sizeof_string_2
|
|
"mov_rax, %"
|
|
|
|
:unary_expr_sizeof_string_3
|
|
"
|
|
"
|
|
|
|
|
|
# postfix_expr_array function
|
|
# Receives Nothing
|
|
# Returns Nothing
|
|
# Uses RBX for struct type* ARRAY and RCX for char* ASSIGN
|
|
:postfix_expr_array
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rip+DWORD] %current_target # ARRAY = current_target
|
|
push_rax # Protect it
|
|
|
|
lea_rax,[rip+DWORD] %expression # Using expression
|
|
call %common_recursion # Recurse
|
|
|
|
pop_rbx # Restore array
|
|
mov_[rip+DWORD],rbx %current_target # current_target = ARRAY
|
|
|
|
lea_rcx,[rip+DWORD] %postfix_expr_array_string_0 # ASSIGN = "mov_rax,[rax]\n"
|
|
|
|
lea_rax,[rip+DWORD] %type_char_indirect_name # Using "char*"
|
|
mov_rbx,[rbx+BYTE] !48 # current_target->NAME
|
|
call %match # IF current_target->NAME == "char*"
|
|
cmp_rax, %0 # load a byte
|
|
jne %postfix_expr_array_large # Otherwise adjust
|
|
|
|
# Deal with loading byte
|
|
lea_rcx,[rip+DWORD] %postfix_expr_array_string_1 # ASSIGN = "movsx_rax,BYTE_PTR_[rax]\n"
|
|
jmp %postfix_expr_array_common # Do the next bit
|
|
|
|
:postfix_expr_array_large
|
|
# deal with arrays made of things other than chars
|
|
lea_rax,[rip+DWORD] %postfix_expr_array_string_2 # Using "sal_rax, !"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %current_target # Using current_target
|
|
mov_rax,[rax+BYTE] !24 # current_target->INDIRECT
|
|
mov_rax,[rax+BYTE] !8 # current_target->INDIRECT->SIZE
|
|
call %ceil_log2 # ceil_log2(current_target->indirect->size)
|
|
call %numerate_number # numerate_number(ceil_log2(current_target->indirect->size))
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr_array_string_3 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
:postfix_expr_array_common
|
|
lea_rax,[rip+DWORD] %postfix_expr_array_string_4 # Using "add_rax,rbx\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr_array_string_5 # Using "ERROR in postfix_expr\nMissing ]\n"
|
|
lea_rbx,[rip+DWORD] %close_bracket # Using "]"
|
|
call %require_match # Make sure we have it
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %equal # Using "="
|
|
call %match # IF global_token->S == "="
|
|
cmp_rax, %0 # We need to preserve address
|
|
jne %postfix_expr_array_done # Otherwise be done
|
|
|
|
# Clearing out assign
|
|
lea_rcx,[rip+DWORD] %postfix_expr_array_string_6 # ASSIGN = ""
|
|
|
|
:postfix_expr_array_done
|
|
mov_rax,rcx # Using ASSIGN
|
|
call %emit_out # Emit it
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:postfix_expr_array_string_0
|
|
"mov_rax,[rax]
|
|
"
|
|
|
|
:postfix_expr_array_string_1
|
|
"movsx_rax,BYTE_PTR_[rax]
|
|
"
|
|
|
|
:postfix_expr_array_string_2
|
|
"sal_rax, !"
|
|
|
|
:postfix_expr_array_string_3
|
|
"
|
|
"
|
|
|
|
:postfix_expr_array_string_4
|
|
"add_rax,rbx
|
|
"
|
|
|
|
:postfix_expr_array_string_5
|
|
"ERROR in postfix_expr
|
|
Missing ]
|
|
"
|
|
|
|
:postfix_expr_array_string_6
|
|
'00'
|
|
|
|
|
|
# ceil_log2 function
|
|
# Receives int a in RAX
|
|
# Performs log2 on A and
|
|
# Returns result in RAX
|
|
# Uses RBX for INT A and RCX for INT RESULT
|
|
:ceil_log2
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx, %0 # RESULT = 0
|
|
|
|
mov_rbx,rax # put A in right place
|
|
sub_rax, %1 # (A - 1)
|
|
and_rax,rbx # A & (A - 1)
|
|
cmp_rax, %0 # IF 0 == (A & (A - 1))
|
|
jne %ceil_log2_iter # Starting from -1
|
|
|
|
mov_rcx, %-1 # RESULT = -1
|
|
|
|
:ceil_log2_iter
|
|
cmp_rbx, %0 # IF A > 0
|
|
jle %ceil_log2_done # Otherwise be done
|
|
|
|
add_rcx, %1 # RESULT = RESULT + 1
|
|
shr_rbx # A = A >> 1
|
|
jmp %ceil_log2_iter # Keep looping
|
|
|
|
:ceil_log2_done
|
|
mov_rax,rcx # Return RESULT
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# postfix_expr_arrow function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Emits a bunch and updates current_target
|
|
# Uses RBX for struct type* I
|
|
:postfix_expr_arrow
|
|
push_rbx # Protect RBX
|
|
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_0 # Using "# looking up offset\n"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rbx,[rax+BYTE] !16 # Using global_token->S
|
|
mov_rax,[rip+DWORD] %current_target # Using current_target
|
|
call %lookup_member # lookup_member(current_target, global_token->s)
|
|
mov_rbx,rax # struct type* I = lookup_member(current_target, global_token->s)
|
|
|
|
mov_rax,[rax+BYTE] !40 # I->TYPE
|
|
mov_[rip+DWORD],rax %current_target # current_target = I->TYPE
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rax,[rbx+BYTE] !16 # I->OFFSET
|
|
cmp_rax, %0 # IF 0 != I->OFFSET
|
|
je %postfix_expr_arrow_first # Then we don't need to do an offset
|
|
|
|
# Deal with needing an offset
|
|
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_1 # Using "# -> offset calculation\nmov_rbx, %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rbx+BYTE] !16 # I->OFFSET
|
|
call %numerate_number # Convert to string
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_2 # Using "\nadd_rax,rbx\n"
|
|
call %emit_out # Emit it
|
|
|
|
:postfix_expr_arrow_first
|
|
mov_rax,[rbx+BYTE] !8 # I->SIZE
|
|
cmp_rax, %4 # IF I->SIZE >= 4
|
|
jl %postfix_expr_arrow_done # Otherwise be done
|
|
|
|
# Last chance for load
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rax+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %equal # Using "="
|
|
call %match # IF global_token->S == "="
|
|
cmp_rax, %0 # Then we have assignment and should not load
|
|
je %postfix_expr_arrow_done # Be done
|
|
|
|
# Deal with load case
|
|
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_3 # Using "mov_rax,[rax]\n"
|
|
call %emit_out # Emit it
|
|
|
|
:postfix_expr_arrow_done
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:postfix_expr_arrow_string_0
|
|
"# looking up offset
|
|
"
|
|
|
|
:postfix_expr_arrow_string_1
|
|
"# -> offset calculation
|
|
mov_rbx, %"
|
|
|
|
:postfix_expr_arrow_string_2
|
|
"
|
|
add_rax,rbx
|
|
"
|
|
|
|
:postfix_expr_arrow_string_3
|
|
"mov_rax,[rax]
|
|
"
|
|
|
|
|
|
# primary_expr function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
:primary_expr
|
|
push_rbx # Protect RBX
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rax+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %sizeof_string # Using "sizeof"
|
|
call %match # See if match
|
|
cmp_rax, %0 # IF match
|
|
jne %primary_expr_neg # Otherwise try negatives
|
|
|
|
# Deal with sizeof
|
|
call %unary_expr_sizeof # Lets do this
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_neg
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %45 # IF global_token->S[0] == "-"
|
|
jne %primary_expr_not # Otherwise try logical NOT
|
|
|
|
# Deal with negative numbers
|
|
lea_rax,[rip+DWORD] %primary_expr_string_0 # Using "mov_rax, %0\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Passing postfix_expr
|
|
call %common_recursion # Get what it is notting
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_string_1 # Using "sub_rbx,rax\nmov_rax,rbx\n"
|
|
call %emit_out # Emit it
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_not
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %33 # IF global_token->S[0] == "!"
|
|
jne %primary_expr_bin # Otherwise try '~'
|
|
|
|
# Deal with logical not
|
|
lea_rax,[rip+DWORD] %primary_expr_string_2 # Using "mov_rax, %1\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %postfix_expr # Passing postfix_expr
|
|
call %common_recursion # Get what it is notting
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_string_3 # Using "xor_rax,rbx\n"
|
|
call %emit_out # Emit it
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_bin
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %126 # IF global_token->S[0] == "~"
|
|
jne %primary_expr_paren # Otherwise try paren
|
|
|
|
# Deal with binary NOT
|
|
lea_rax,[rip+DWORD] %postfix_expr # Passing postfix_expr
|
|
call %common_recursion # Get what it is notting
|
|
lea_rax,[rip+DWORD] %primary_expr_string_4 # Using "not_rax\n"
|
|
call %emit_out # Emit it
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_paren
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %40 # IF global_token->S[0] == "("
|
|
jne %primary_expr_ch # Otherwise try char
|
|
|
|
# deal with nesting
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
call %expression # Lets recurse
|
|
lea_rax,[rip+DWORD] %primary_expr_string_5 # Using "Error in Primary expression\nDidn't get )\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_ch
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %39 # Using "'"
|
|
jne %primary_expr_str # Otherwise try string
|
|
|
|
# Deal with chars
|
|
call %primary_expr_char # Handle that char
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_str
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %34 # Using '"'
|
|
jne %primary_expr_var # Otherwise try a variable
|
|
|
|
# Deal with strings
|
|
call %primary_expr_string # Handle that string
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_var
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
lea_rbx,[rip+DWORD] %primary_expr_string_6 # Using "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
|
|
call %In_Set # See if we have a match
|
|
cmp_rax, %1 # IF match
|
|
jne %primary_expr_num # otherwise try number
|
|
|
|
# Deal with variables
|
|
call %primary_expr_variable # Deal with variable
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_num
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
lea_rbx,[rip+DWORD] %primary_expr_string_7 # Using "0123456789"
|
|
call %In_Set # See if we have a match
|
|
cmp_rax, %1 # IF match
|
|
jne %primary_expr_fail # otherwise we failed hard
|
|
|
|
# Deal with numbers
|
|
call %primary_expr_number # Collect the number
|
|
jmp %primary_expr_done # Be done
|
|
|
|
:primary_expr_fail
|
|
# looks like we hit bad input
|
|
# abort before it gets bad
|
|
call %primary_expr_failure # No match means failure
|
|
:primary_expr_done
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:primary_expr_string_0
|
|
"mov_rax, %0
|
|
"
|
|
|
|
:primary_expr_string_1
|
|
"sub_rbx,rax
|
|
mov_rax,rbx
|
|
"
|
|
|
|
:primary_expr_string_2
|
|
"mov_rax, %1
|
|
"
|
|
|
|
:primary_expr_string_3
|
|
"xor_rax,rbx
|
|
"
|
|
|
|
:primary_expr_string_4
|
|
"not_rax
|
|
"
|
|
|
|
:primary_expr_string_5
|
|
"Error in Primary expression
|
|
Didn't get )
|
|
"
|
|
|
|
:primary_expr_string_6
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
|
|
|
|
:primary_expr_string_7
|
|
"0123456789"
|
|
|
|
|
|
# primary_expr_variable function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Walks global and updates output
|
|
# Uses RAX for struct token_list* a and RCX for char* S
|
|
:primary_expr_variable
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rcx,[rax+BYTE] !16 # S = global_token->S
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rax,rcx # Using S
|
|
mov_rbx,[rip+DWORD] %global_constant_list # Using global_constant_list
|
|
call %sym_lookup # sym_lookup(s, global_constant_list)
|
|
cmp_rax, %0 # IF NULL == sym_lookup(s, global_constant_list)
|
|
je %primary_expr_variable_local # Try locals next
|
|
|
|
# Deal with constant load
|
|
mov_rbx,[rax+BYTE] !32 # a->ARGS
|
|
lea_rax,[rip+DWORD] %primary_expr_variable_string_2 # Using "mov_rax, %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rbx+BYTE] !16 # a->ARGS->S
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_variable_string_1 # Using "\n"
|
|
call %emit_out # Emit it
|
|
jmp %primary_expr_variable_done # Be done
|
|
|
|
:primary_expr_variable_local
|
|
mov_rax,rcx # Using S
|
|
mov_rbx,[rip+DWORD] %function # Using function
|
|
mov_rbx,[rbx+BYTE] !8 # function->locals
|
|
call %sym_lookup # sym_lookup(s, function->locals)
|
|
cmp_rax, %0 # IF NULL == sym_lookup(s, function->locals)
|
|
je %primary_expr_variable_arguments # try arguments next
|
|
|
|
# Deal with local load
|
|
call %variable_load # Collect it
|
|
jmp %primary_expr_variable_done # Be done
|
|
|
|
:primary_expr_variable_arguments
|
|
mov_rax,rcx # Using S
|
|
mov_rbx,[rip+DWORD] %function # Using function
|
|
mov_rbx,[rbx+BYTE] !32 # function->args
|
|
call %sym_lookup # sym_lookup(s, function->args)
|
|
cmp_rax, %0 # IF NULL == sym_lookup(s, function->args)
|
|
je %primary_expr_variable_function # try functions next
|
|
|
|
# Deal with argument load
|
|
call %variable_load # Collect it
|
|
jmp %primary_expr_variable_done # Be done
|
|
|
|
:primary_expr_variable_function
|
|
mov_rax,rcx # Using S
|
|
mov_rbx,[rip+DWORD] %global_function_list # Using global_function_list
|
|
call %sym_lookup # sym_lookup(s, global_function_list)
|
|
cmp_rax, %0 # IF NULL == sym_lookup(s, global_function_list)
|
|
je %primary_expr_variable_global # try globals next
|
|
|
|
# Deal with functions
|
|
call %function_load # Deal with the function
|
|
jmp %primary_expr_variable_done # Be done
|
|
|
|
:primary_expr_variable_global
|
|
mov_rax,rcx # Using S
|
|
mov_rbx,[rip+DWORD] %global_symbol_list # Using global_symbol_list
|
|
call %sym_lookup # sym_lookup(s, global_symbol_list)
|
|
cmp_rax, %0 # IF NULL == sym_lookup(s, global_symbol_list)
|
|
je %primary_expr_variable_error # Give up
|
|
|
|
# Deal with globals
|
|
call %global_load # Collect that global
|
|
jmp %primary_expr_variable_done # Be done
|
|
|
|
:primary_expr_variable_error
|
|
mov_r15, %2 # write to standard error
|
|
# call %line_error # Write useful debug info
|
|
mov_rax,rcx # put S in the right place
|
|
call %File_Print # print it
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_variable_string_0 # Ending string
|
|
call %File_Print # print it
|
|
jmp %Exit_Failure # Abort Hard
|
|
|
|
:primary_expr_variable_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:primary_expr_variable_string_0
|
|
" is not a defined symbol
|
|
"
|
|
|
|
:primary_expr_variable_string_1
|
|
"
|
|
"
|
|
|
|
:primary_expr_variable_string_2
|
|
"mov_rax, %"
|
|
|
|
|
|
# function_call function
|
|
# Receives char* S in RAX and int BOOL in RBX
|
|
# Builds stack frames before and tears them down after function calls
|
|
# Uses RCX for char* S, RDX for int BOOL, RSI for PASSED
|
|
:function_call
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
push_rsi # Protect RSI
|
|
mov_rcx,rax # Put S in place
|
|
mov_rdx,rbx # Put BOOL in place
|
|
mov_rsi, %0 # PASSED = 0
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_0 # Using "ERROR in process_expression_list\nNo ( was found\n"
|
|
lea_rbx,[rip+DWORD] %open_paren # Using "("
|
|
call %require_match # Make sure we have it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_1 # Using "push_rdi\t# Prevent overwriting in recursion\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_2 # Using "push_rbp\t# Protect the old base pointer\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_3 # Using "mov_rdi,rsp\t# Copy new base pointer\n"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %41 # IF global_token->S[0] == ")"
|
|
je %function_call_gen_done # Then no arguments to send
|
|
|
|
# looks like we have arguments to collect
|
|
call %expression # Collect the argument
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_4 # Using "push_rax\t#_process_expression1\n"
|
|
call %emit_out # Emit it
|
|
mov_rsi, %1 # PASSED = 1
|
|
|
|
:function_call_gen_iter
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %44 # IF global_token->S[0] == ","
|
|
jne %function_call_gen_done # Otherwise we are done
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
call %expression # Collect the argument
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_5 # Using "push_rax\t#_process_expression2\n"
|
|
call %emit_out # Emit it
|
|
add_rsi, %1 # PASSED = PASSED + 1
|
|
jmp %function_call_gen_iter # Keep trying
|
|
|
|
:function_call_gen_done
|
|
# All is collected
|
|
lea_rax,[rip+DWORD] %function_call_string_6 # Using "ERROR in process_expression_list\nNo ) was found\n"
|
|
lea_rbx,[rip+DWORD] %close_paren # Using ")"
|
|
call %require_match # Make sure we have it
|
|
|
|
cmp_rdx, %0 # IF(BOOL == TRUE)
|
|
jne %function_call_static # Otherwise it is a static call
|
|
|
|
# Deal with a passed function pointer
|
|
lea_rax,[rip+DWORD] %function_call_string_7 # Using "lea_rax,[rbp+DWORD] %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,rcx # Using S
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_8 # Using "\nmov_rax,[rax]\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_9 # Using "mov_rbp,rdi\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_10 # Using "call_rax\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_13 # Using "pop_rbx\t# _process_expression_locals\n"
|
|
jmp %function_call_cleanup # Clean up
|
|
|
|
:function_call_static
|
|
# Deal with fixed function name
|
|
lea_rax,[rip+DWORD] %function_call_string_9 # Using "mov_rbp,rdi\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_11 # Using "call %FUNCTION_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,rcx # Using S
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_12 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_13 # Using "pop_rbx\t# _process_expression_locals\n"
|
|
|
|
:function_call_cleanup
|
|
cmp_rsi, %0 # IF PASSED > 0
|
|
jle %function_call_done # Otherwise be done
|
|
|
|
# The desired string is already in RAX
|
|
call %emit_out # Emit it
|
|
|
|
sub_rsi, %1 # PASSED = PASSED - 1
|
|
jmp %function_call_cleanup # Keep going
|
|
|
|
:function_call_done
|
|
lea_rax,[rip+DWORD] %function_call_string_14 # Using "POP_rbp\t# Restore old base pointer\n"
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_call_string_15 # Using "POP_rdi\t# Prevent overwrite\n"
|
|
call %emit_out # Emit it
|
|
|
|
pop_rsi # Restore RSI
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:function_call_string_0
|
|
"ERROR in process_expression_list
|
|
No ( was found
|
|
"
|
|
|
|
:function_call_string_1
|
|
"push_rdi # Prevent overwriting in recursion
|
|
"
|
|
|
|
:function_call_string_2
|
|
"push_rbp # Protect the old base pointer
|
|
"
|
|
|
|
:function_call_string_3
|
|
"mov_rdi,rsp # Copy new base pointer
|
|
"
|
|
|
|
:function_call_string_4
|
|
"push_rax #_process_expression1
|
|
"
|
|
|
|
:function_call_string_5
|
|
"push_rax #_process_expression2
|
|
"
|
|
|
|
:function_call_string_6
|
|
"ERROR in process_expression_list
|
|
No ) was found
|
|
"
|
|
|
|
:function_call_string_7
|
|
"lea_rax,[rbp+DWORD] %"
|
|
|
|
:function_call_string_8
|
|
"
|
|
mov_rax,[rax]
|
|
"
|
|
|
|
:function_call_string_9
|
|
"mov_rbp,rdi
|
|
"
|
|
|
|
:function_call_string_10
|
|
"call_rax
|
|
"
|
|
|
|
:function_call_string_11
|
|
"call %FUNCTION_"
|
|
|
|
:function_call_string_12
|
|
"
|
|
"
|
|
|
|
:function_call_string_13
|
|
"pop_rbx # _process_expression_locals
|
|
"
|
|
|
|
:function_call_string_14
|
|
"pop_rbp # Restore old base pointer
|
|
"
|
|
|
|
:function_call_string_15
|
|
"pop_rdi # Prevent overwrite
|
|
"
|
|
|
|
|
|
# variable_load function
|
|
# Receives struct token_list* A in RAX
|
|
# Returns nothing
|
|
# Updates output and current_target
|
|
# Uses RCX for A
|
|
:variable_load
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rax # Protect A
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %open_paren # Using "("
|
|
call %match # IF global_token->S == "("
|
|
cmp_rax, %0 # Then it might be a function
|
|
jne %variable_load_regular # Otherwise it is regular
|
|
|
|
mov_rbx,[rcx+BYTE] !24 # A->TYPE
|
|
mov_rbx,[rbx+BYTE] !48 # A->TYPE->NAME
|
|
lea_rax,[rip+DWORD] %type_function_name # Using "FUNCTION"
|
|
call %match # IF A->TYPE->NAME == "FUNCTION"
|
|
cmp_rax, %0 # Then it must be a function
|
|
jne %variable_load_regular # otherwise just another regular
|
|
|
|
# deal with function
|
|
mov_rax,[rcx+BYTE] !32 # A->DEPTH
|
|
call %numerate_number # Convert to string
|
|
mov_rbx, %0 # pass 0 for true
|
|
call %function_call # Create the function call
|
|
jmp %variable_load_done # Be done
|
|
|
|
:variable_load_regular
|
|
mov_rax,[rcx+BYTE] !24 # A->TYPE
|
|
mov_[rip+DWORD],rax %current_target # current_target = A->TYPE
|
|
|
|
lea_rax,[rip+DWORD] %variable_load_string_0 # Using "lea_rax,[rbp+DWORD] %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rcx+BYTE] !32 # A->DEPTH
|
|
call %numerate_number # Convert to string
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %variable_load_string_1 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
# Check for special case of assignment
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %equal # Using "="
|
|
call %match # IF global_token->S == "="
|
|
cmp_rax, %0 # Then we skip loading
|
|
je %variable_load_done # And be done
|
|
|
|
# Deal with common case
|
|
lea_rax,[rip+DWORD] %variable_load_string_2 # Using "mov_rax,[rax]\n"
|
|
call %emit_out # Emit it
|
|
|
|
:variable_load_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:variable_load_string_0
|
|
"lea_rax,[rbp+DWORD] %"
|
|
|
|
:variable_load_string_1
|
|
"
|
|
"
|
|
|
|
:variable_load_string_2
|
|
"mov_rax,[rax]
|
|
"
|
|
|
|
|
|
# function_load function
|
|
# Receives struct token_list* a in RAX
|
|
# Returns nothing
|
|
# Uses RCX to hold A->S
|
|
:function_load
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rax,[rax+BYTE] !16 # A->S
|
|
mov_rcx,rax # Protect A->S
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %open_paren # Using "("
|
|
call %match # IF global_token->S == "("
|
|
cmp_rax, %0 # The we need to do a function call
|
|
jne %function_load_regular # Otherwise just load it's address
|
|
|
|
# Deal with function call
|
|
mov_rax,rcx # Using A->S
|
|
mov_rbx, %1 # Using FALSE
|
|
call %function_call # Deal with it
|
|
jmp %function_load_done # Be done
|
|
|
|
:function_load_regular
|
|
lea_rax,[rip+DWORD] %function_load_string_0 # Using "lea_rax,[rip+DWORD] %FUNCTION_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,rcx # Using A->S
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %function_load_string_1 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
:function_load_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:function_load_string_0
|
|
"lea_rax,[rip+DWORD] %FUNCTION_"
|
|
|
|
:function_load_string_1
|
|
"
|
|
"
|
|
|
|
|
|
# global_load function
|
|
# Receives struct token_list* A in RAX
|
|
# Returns nothing
|
|
# Uses RBX to hold A->S
|
|
:global_load
|
|
push_rbx # Protect RBX
|
|
mov_rbx,rax # Set as A
|
|
mov_rbx,[rbx+BYTE] !16 # Set as A->S
|
|
|
|
mov_rax,[rax+BYTE] !24 # A->TYPE
|
|
mov_[rip+DWORD],rax %current_target # current_target = A->TYPE
|
|
|
|
lea_rax,[rip+DWORD] %global_load_string_0 # Using "lea_rax,[rip+DWORD] %GLOBAL_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,rbx # Using A->S
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %global_load_string_1 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %equal # "="
|
|
call %match # IF global_token->S == "="
|
|
cmp_rax, %0 # We need to skip for assignment
|
|
je %global_load_done # and be done
|
|
|
|
# Otherwise we are loading the contents
|
|
lea_rax,[rip+DWORD] %global_load_string_2 # Using "mov_rax,[rax]\n"
|
|
call %emit_out # Emit it
|
|
|
|
:global_load_done
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:global_load_string_0
|
|
"lea_rax,[rip+DWORD] %GLOBAL_"
|
|
|
|
:global_load_string_1
|
|
"
|
|
"
|
|
|
|
:global_load_string_2
|
|
"mov_rax,[rax]
|
|
"
|
|
|
|
|
|
# sym_lookup function
|
|
# Receives char* S in RAX and struct token_list* symbol_list in RBX
|
|
# Uses I->S in RAX, S in RBX and I in RCX
|
|
# Returns match or NULL
|
|
:sym_lookup
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rbx # I = symbol_list
|
|
mov_rbx,rax # Put S in the right place
|
|
:sym_lookup_iter
|
|
cmp_rcx, %0 # IF NULL == I
|
|
je %sym_lookup_done # We failed to find match
|
|
|
|
mov_rax,[rcx+BYTE] !16 # Using I->S
|
|
call %match # IF I->S == S
|
|
cmp_rax, %0 # then be done
|
|
je %sym_lookup_done # Failed
|
|
|
|
mov_rcx,[rcx] # I = I->NEXT
|
|
jmp %sym_lookup_iter # otherwise keep looping
|
|
|
|
:sym_lookup_done
|
|
mov_rax,rcx # Return I
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# primary_expr_number function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Simply uses current global token to update output and then steps to next global_token
|
|
:primary_expr_number
|
|
lea_rax,[rip+DWORD] %primary_expr_number_string_0 # Using "mov_rax, %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %emit_out # Emit it
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_number_string_1 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
ret
|
|
|
|
:primary_expr_number_string_0
|
|
"mov_rax, %"
|
|
|
|
:primary_expr_number_string_1
|
|
"
|
|
"
|
|
|
|
|
|
# primary_expr_string function
|
|
# receives nothing
|
|
# Returns nothing
|
|
# creates entries for string and calls to generate string output
|
|
# uses RCX for char* number_string
|
|
:primary_expr_string
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rbx,[rip+DWORD] %current_count # Using current_count
|
|
mov_rax,rbx # And putting it in the right place
|
|
call %numerate_number # Get the string
|
|
mov_rcx,rax # protect number_string
|
|
|
|
add_rbx, %1 # current_count + 1
|
|
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_string_string_0 # Using "lea_rax,[rip+DWORD] %STRING_"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
mov_rbx,rcx # Put number_string in the right place
|
|
call %uniqueID_out # Make it unique
|
|
|
|
# Generate the target
|
|
lea_rax,[rip+DWORD] %primary_expr_string_string_1 # Using ":STRING_"
|
|
mov_rbx,[rip+DWORD] %strings_list # Using strings_list
|
|
call %emit # Emit it
|
|
mov_rbx,rax # put new strings_list in place
|
|
|
|
mov_rax,[rip+DWORD] %function # Using function
|
|
mov_rax,[rax+BYTE] !16 # function->S
|
|
call %uniqueID # Make it unique
|
|
mov_rbx,rax # put new strings_list in place
|
|
|
|
# Parse the string
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %parse_string # convert to useful form
|
|
call %emit # Emit it
|
|
mov_[rip+DWORD],rax %strings_list # Update Strings _list
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:primary_expr_string_string_0
|
|
"lea_rax,[rip+DWORD] %STRING_"
|
|
|
|
:primary_expr_string_string_1
|
|
":STRING_"
|
|
|
|
|
|
# primary_expr_char function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Updates output_list using global_token
|
|
:primary_expr_char
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
lea_rax,[rip+DWORD] %primary_expr_char_string_0 # Using "mov_rax, %"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
add_rax, %1 # global_token->S + 1
|
|
call %escape_lookup # Get the char
|
|
call %numerate_number # Convert to string
|
|
call %emit_out # emit it
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_char_string_1 # Using "\n"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:primary_expr_char_string_0
|
|
"mov_rax, %"
|
|
|
|
:primary_expr_char_string_1
|
|
"
|
|
"
|
|
|
|
|
|
# primary_expr_failure function
|
|
# Receives nothing
|
|
# Does not return but aborts hard
|
|
# Complains about the bad input
|
|
:primary_expr_failure
|
|
# call %line_error # Get line of issue
|
|
mov_r15, %2 # write to standard error
|
|
lea_rax,[rip+DWORD] %primary_expr_failure_string_0 # Using "Received "
|
|
call %File_Print # Print it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %File_Print # Print it
|
|
|
|
lea_rax,[rip+DWORD] %primary_expr_failure_string_1 # Using " in primary_expr\n"
|
|
call %File_Print # Print it
|
|
jmp %Exit_Failure # Abort Hard
|
|
|
|
:primary_expr_failure_string_0
|
|
"Received "
|
|
|
|
:primary_expr_failure_string_1
|
|
" in primary_expr
|
|
"
|
|
|
|
|
|
# general_recursion function
|
|
# Receives FUNCTION F in RAX, char* S in RBX, char* name in RCX and FUNCTION iterate in RDX
|
|
# Returns nothing
|
|
# Uses RCX for char* S, RDX for FUNCTION iterate and RBP for FUNCTION F
|
|
# But generally recurses a shitload
|
|
:general_recursion
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
push_rbp # Protect RBP
|
|
mov_rbp,rax # Protect F
|
|
mov_rax,rcx # Put name in the right place
|
|
mov_rcx,rbx # Protect S
|
|
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
call %match # IF match(name, global_token->s)
|
|
cmp_rax, %0 # If true we do
|
|
jne %general_recursion_done # Otherwise skip it
|
|
|
|
# Deal with the recursion
|
|
mov_rax,rbp # Put F in the right place
|
|
call %common_recursion # Recurse
|
|
|
|
mov_rax,rcx # Put S in the right place
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,rdx # Put iterate in the right place
|
|
call_rax # Down the rabbit hole
|
|
|
|
:general_recursion_done
|
|
pop_rbp # Restore RBP
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# promote_type function
|
|
# Receives struct type* a in RAX and struct type* b in RBX
|
|
# Returns the most recent type in RAX
|
|
# Uses RAX for struct type* I, RCX for struct type* A and RDX for struct type* B
|
|
:promote_type
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
cmp_rbx, %0 # IF NULL == B
|
|
je %promote_type_done # Just return A
|
|
|
|
mov_rcx,rax # Put A in place
|
|
mov_rdx,rbx # Put B in place
|
|
mov_rax,rbx # IF NULL == A
|
|
cmp_rcx, %0 # Then we just return B
|
|
je %promote_type_done # Be done
|
|
|
|
# Looks like we need to walk the list
|
|
mov_rcx,[rcx+BYTE] !48 # A->NAME
|
|
mov_rdx,[rdx+BYTE] !48 # B->NAME
|
|
mov_rax,[rip+DWORD] %global_types # I = global_types
|
|
:promote_type_iter
|
|
cmp_rax, %0 # IF NULL == I
|
|
je %promote_type_done # Just be done
|
|
|
|
mov_rbx,[rax+BYTE] !48 # I->NAME
|
|
cmp_rbx,rcx # IF(A->NAME == I->NAME)
|
|
je %promote_type_done # Be done
|
|
|
|
cmp_rbx,rdx # IF(B->NAME == I->NAME)
|
|
je %promote_type_done # Be done
|
|
|
|
mov_rbx,[rax+BYTE] !24 # I->INDIRECT
|
|
mov_rbx,[rbx+BYTE] !48 # I->INDIRECT->NAME
|
|
|
|
cmp_rbx,rcx # IF(A->NAME == I->INDIRECT->NAME)
|
|
je %promote_type_done # Be done
|
|
|
|
cmp_rbx,rdx # IF(B->NAME == I->INDIRECT->NAME)
|
|
je %promote_type_done # Be done
|
|
|
|
mov_rax,[rax] # I = I->NEXT
|
|
jmp %promote_type_iter # Keep going
|
|
|
|
:promote_type_done
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# common_recursion function
|
|
# Receives FUNCTION F in RAX
|
|
# Returns Nothing
|
|
# Walks global_token list and update output_list
|
|
# Updates current_target
|
|
# Uses RBX to hold FUNCTION F and struct type* last_type
|
|
:common_recursion
|
|
push_rbx # Protect RBX
|
|
mov_rbx,rax # Put FUNCTION F safely out of the way
|
|
lea_rax,[rip+DWORD] %common_recursion_string_0 # Using "push_rax\t#_common_recursion\n"
|
|
call %emit_out # Emit it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rax,rbx # Prepare for function call
|
|
mov_rbx,[rip+DWORD] %current_target # Get last type
|
|
call_rax # F();
|
|
mov_rax,[rip+DWORD] %current_target # Get current_target
|
|
call %promote_type # get the right type
|
|
mov_[rip+DWORD],rax %current_target # Set new current_target
|
|
|
|
lea_rax,[rip+DWORD] %common_recursion_string_1 # Using "pop_rbx\t# _common_recursion\n"
|
|
call %emit_out # Emit it
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:common_recursion_string_0
|
|
"push_rax #_common_recursion
|
|
"
|
|
|
|
:common_recursion_string_1
|
|
"pop_rbx # _common_recursion
|
|
"
|
|
|
|
|
|
# require_match function
|
|
# Receives char* message in RAX and char* required in RBX
|
|
# Returns nothing
|
|
# Uses RCX to hold message and updates global_token
|
|
:require_match
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rax # put the message somewhere safe
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %match # IF required == global_token->S
|
|
cmp_rax, %0 # we are fine
|
|
je %require_match_good # otherwise pain
|
|
|
|
# Deal with bad times
|
|
# call %line_error # Tell user what went wrong
|
|
mov_r15, %2 # write to standard error
|
|
mov_rax,rcx # using our message
|
|
call %File_Print # Print it
|
|
jmp %Exit_Failure # Abort HARD
|
|
|
|
:require_match_good
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->next
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# uniqueID Function
|
|
# Receives char *S in RAX, struct token_list* l in RBX and char* num in RCX
|
|
# Returns updated struct token_list* L in RAX
|
|
:uniqueID
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
call %emit # emit(s, l)
|
|
mov_rbx,rax # Put L in correct place
|
|
lea_rax,[rip+DWORD] %underline # Using "_"
|
|
call %emit # emit("_", l)
|
|
mov_rbx,rax # Put L in correct place
|
|
mov_rax,rcx # Put num in correct place
|
|
call %emit # emit(num, l)
|
|
mov_rbx,rax # Put L in correct place
|
|
lea_rax,[rip+DWORD] %uniqueID_string_0 # Using "\n"
|
|
call %emit # emit("\n", l)
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:uniqueID_string_0
|
|
"
|
|
"
|
|
|
|
|
|
# uniqueID_out function
|
|
# Receives char* S in RAX and char* num in RBX
|
|
# Returns nothing
|
|
:uniqueID_out
|
|
push_rax # Protect RAX
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rbx # Put num in right spot
|
|
mov_rbx,[rip+DWORD] %output_list # Using output_list
|
|
call %uniqueID # Get updated list
|
|
mov_[rip+DWORD],rax %output_list # output_list = uniqueID(s, output_list, num)
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
pop_rax # Restore RAX
|
|
ret
|
|
|
|
|
|
# emit_out function
|
|
# Receives char* S in RAX
|
|
# Returns nothing
|
|
# Updates output_list
|
|
# MUST NOT ALTER REGISTERS
|
|
:emit_out
|
|
push_rax # Protect RAX
|
|
push_rbx # Protect RBX
|
|
mov_rbx,[rip+DWORD] %output_list # Using output_list
|
|
call %emit # emit it
|
|
mov_[rip+DWORD],rax %output_list # update it
|
|
pop_rbx # Restore RBX
|
|
pop_rax # Restore RAX
|
|
ret
|
|
|
|
|
|
# emit function
|
|
# Receives char *s in RAX and struct token_list* head in RBX
|
|
# Returns struct token_list* T in RAX
|
|
:emit
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rax # put S out of the way
|
|
mov_rax, %40 # sizeof(struct token_list)
|
|
call %malloc # get T
|
|
mov_[rax],rbx # t->next = head;
|
|
mov_[rax+BYTE],rcx !16 # t->s = s;
|
|
pop_rcx # Restore RCX
|
|
ret
|
|
|
|
|
|
# escape_lookup function
|
|
# Receives char* c in RAX
|
|
# Returns integer value of char in RAX
|
|
# Aborts hard if unknown escape is received
|
|
# Uses RCX to hold char* C
|
|
:escape_lookup
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rax # Put char* C in safe place
|
|
mov_al,[rcx] # Load c[0]
|
|
movzx_rax,al # make it useful
|
|
cmp_rax, %92 # If '\\' != c[0]
|
|
jne %escape_lookup_done # Be done
|
|
|
|
mov_rbx,rcx # Prepare for walk
|
|
add_rbx, %1 # increment
|
|
mov_bl,[rbx] # load c[1]
|
|
movzx_rbx,bl # make it useful
|
|
|
|
cmp_rbx, %120 # Check if \x??
|
|
je %escape_lookup_hex # Deal with hex
|
|
|
|
# Deal with \? escapes
|
|
mov_rax, %10 # Guess "\n"
|
|
cmp_rbx, %110 # If n
|
|
je %escape_lookup_done # Be done
|
|
|
|
mov_rax, %9 # Guess "\t"
|
|
cmp_rbx, %116 # If t
|
|
je %escape_lookup_done # Be done
|
|
|
|
mov_rax,rbx # "\\", "'" and '"' all encode as themselves
|
|
cmp_rbx, %92 # If "\\"
|
|
je %escape_lookup_done # Be done
|
|
cmp_rbx, %39 # IF "'"
|
|
je %escape_lookup_done # Be done
|
|
cmp_rbx, %34 # IF '"'
|
|
je %escape_lookup_done # Be done
|
|
|
|
mov_rax, %13 # Guess "\r"
|
|
cmp_rbx, %114 # IF r
|
|
je %escape_lookup_done # Be done
|
|
|
|
# Looks like we have no clue what we are doing
|
|
# Aborting hard
|
|
mov_r15, %2 # write to standard error
|
|
lea_rax,[rip+DWORD] %escape_lookup_string_0 # Using "Unknown escape received: "
|
|
call %File_Print # Print it
|
|
mov_rax,rcx # Using C
|
|
call %File_Print # Print it
|
|
lea_rax,[rip+DWORD] %escape_lookup_string_1 # Using " Unable to process\n"
|
|
call %File_Print # Print it
|
|
jmp %Exit_Failure # Abort Hard
|
|
|
|
:escape_lookup_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:escape_lookup_hex
|
|
# Give up on C and just assume they know what they are doing
|
|
add_rcx, %2 # increment
|
|
mov_al,[rcx] # c[2]
|
|
movzx_rax,al # make it useful
|
|
add_rcx, %1 # increment
|
|
call %char2hex # Get the hex value
|
|
sal_rax, !4 # c << 4
|
|
mov_bl,[rcx] # c[3]
|
|
movzx_rbx,bl # make it useful
|
|
xchg_rax,rbx # protect c << 4
|
|
call %char2hex # Get the hex value
|
|
add_rax,rbx # hex(c[2]) << 4 + hex(c[3])
|
|
jmp %escape_lookup_done # Be done
|
|
|
|
:escape_lookup_string_0
|
|
"Unknown escape received: "
|
|
|
|
:escape_lookup_string_1
|
|
" Unable to process
|
|
"
|
|
|
|
|
|
# char2hex function
|
|
# Receives char in RAX
|
|
# Returns hex or aborts hard
|
|
:char2hex
|
|
sub_rax, %48 # Try 0-9
|
|
cmp_rax, %10 # Otherwise fun times
|
|
jl %char2hex_done # Be done
|
|
|
|
# Deal with A-F
|
|
and_rax, %0xDF # Unset High bit turning a-f into A-F
|
|
sub_rax, %7 # Shift down into position
|
|
cmp_rax, %10 # Everything below A is bad
|
|
jl %char2hex_fail # And should fail
|
|
cmp_rax, %16 # Make sure we are below F
|
|
jl %char2hex_done # If so be done
|
|
|
|
:char2hex_fail
|
|
# Time to fail hard
|
|
mov_r15, %2 # write to standard error
|
|
lea_rax,[rip+DWORD] %char2hex_string_0 # Using "Tried to print non-hex number\n"
|
|
call %File_Print # Print it
|
|
jmp %Exit_Failure # Abort Hard
|
|
|
|
:char2hex_done
|
|
ret
|
|
|
|
:char2hex_string_0
|
|
"Tried to print non-hex number
|
|
"
|
|
|
|
|
|
# parse_string function
|
|
# Receives char* string in RAX
|
|
# Returns cleaned up string
|
|
# Protects char* string in RBX
|
|
:parse_string
|
|
push_rbx # Protect RBX
|
|
mov_rbx,rax # Protect char* string
|
|
call %weird # Determine if we have a weird string
|
|
cmp_rax, %0 # If weird
|
|
je %parse_string_weird # Deal with it
|
|
|
|
# Dealing with regular string
|
|
mov_rax,rbx # Passing Char* string
|
|
call %collect_regular_string # Collect it
|
|
jmp %parse_string_done # Be done
|
|
|
|
:parse_string_weird
|
|
mov_rax,rbx # Passing Char* string
|
|
call %collect_weird_string # Collect it
|
|
|
|
:parse_string_done
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# weird function
|
|
# Receives char* string in RAX
|
|
# Returns true(0) or false(1) in RAX
|
|
# Uses RCX to hold char* string
|
|
:weird
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rax # Place string in safe place
|
|
add_rcx, %1 # increment past the "
|
|
:weird_reset
|
|
mov_al,[rcx] # Load a char
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %0 # IF NULL == C
|
|
je %weird_false # Nothing weird found
|
|
|
|
cmp_rax, %92 # IF '\\'
|
|
jne %weird_escaped # Deal with escaping
|
|
|
|
# Deal with escape
|
|
mov_rax,rcx # We are passing the string
|
|
call %escape_lookup # to look it up
|
|
|
|
add_rcx, %1 # string = string + 1
|
|
mov_bl,[rcx] # get string[1]
|
|
movzx_rbx,bl # make it useful
|
|
cmp_rbx, %120 # IF 'x' == string[1]
|
|
jne %weird_escaped # otherwise skip the gap
|
|
|
|
add_rcx, %2 # string = string + 2
|
|
|
|
:weird_escaped
|
|
push_rax # Protect C in case we need it
|
|
lea_rbx,[rip+DWORD] %weird_string_0 # Use "\t\n !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
call %In_Set # To find if weird
|
|
cmp_rax, %1 # IF TRUE
|
|
pop_rax # Restore C
|
|
jne %weird_true # Then not weird
|
|
|
|
add_rcx, %1 # string = string + 1
|
|
|
|
# Last chance for weird
|
|
lea_rbx,[rip+DWORD] %weird_string_1 # Use "\t\n\r "
|
|
call %In_Set # Check for special case
|
|
cmp_rax, %1 # IF TRUE
|
|
jne %weird_reset # Otherwise not in the special case
|
|
|
|
# Deal with possible special case
|
|
mov_al,[rcx] # Load string[1]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %58 # IF string[1] == ":"
|
|
je %weird_true # Then we hit the special case
|
|
jmp %weird_reset # Keep trying
|
|
|
|
:weird_done
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:weird_true
|
|
mov_rax, %0 # Return true
|
|
jmp %weird_done # Be done
|
|
|
|
:weird_false
|
|
mov_rax, %1 # Return false
|
|
jmp %weird_done # Be done
|
|
|
|
:weird_string_0
|
|
"
|
|
!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
|
|
:weird_string_1
|
|
'09 0a 0d 20 00'
|
|
|
|
|
|
# collect_regular_string function
|
|
# Receives char* string in RAX
|
|
# Malloc and creates new string to return in RAX
|
|
# Uses RCX for return string and RDX for passed string
|
|
:collect_regular_string
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
mov_rdx,rax # Protect our passed string
|
|
mov_rax, %256 # We need 256 bytes of storage
|
|
call %malloc # Get our new pointer
|
|
mov_rcx,rax # put it in place
|
|
push_rax # protect until done
|
|
:collect_regular_string_reset
|
|
mov_al,[rdx] # string[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %0 # See if we hit the end
|
|
je %collect_regular_string_done # And be done
|
|
|
|
cmp_rax, %92 # IF string[0] == '\\'
|
|
je %collect_regular_string_escaped # Deal with that mess
|
|
|
|
# deal with boring char
|
|
mov_[rcx],al # hold_string[index] = string[0]
|
|
add_rcx, %1 # Increment it
|
|
add_rdx, %1 # Increment it
|
|
jmp %collect_regular_string_reset # And keep going
|
|
|
|
:collect_regular_string_escaped
|
|
mov_rax,rdx # Using string
|
|
call %escape_lookup # Get the char
|
|
mov_[rcx],al # hold_string[index] = escape_lookup(string)
|
|
add_rdx, %1 # Increment it
|
|
add_rcx, %1 # Increment it
|
|
mov_al,[rdx] # string[0]
|
|
movzx_rax,al # Make it useful
|
|
add_rdx, %1 # Increment it
|
|
cmp_rax, %120 # IF 'x' == string[1]
|
|
jne %collect_regular_string_reset # Otherwise keep going
|
|
|
|
add_rdx, %2 # Increment it
|
|
jmp %collect_regular_string_reset # Keep going
|
|
|
|
:collect_regular_string_done
|
|
mov_rax, %34 # Using '"'
|
|
mov_[rcx],al # hold_string[index] = '"'
|
|
add_rcx, %1 # Increment it
|
|
mov_rax, %10 # Using "\n"
|
|
mov_[rcx],al # hold_string[index] = '\n'
|
|
pop_rax # Return our new string
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# collect_weird_string function
|
|
# Receives char* string in RAX
|
|
# Mallocs and returns char* hold in RAX
|
|
# Uses RCX for char* hold and RDX for char* string
|
|
:collect_weird_string
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
mov_rdx,rax # Protect our passed string
|
|
mov_rax, %512 # We need 512 bytes of storage
|
|
call %malloc # Get our new pointer
|
|
mov_rcx,rax # put it in place
|
|
push_rax # protect until done
|
|
|
|
mov_rax, %39 # Using "'"
|
|
mov_[rcx],al # hold_string[index] = "'"
|
|
add_rcx, %1 # Increment it
|
|
add_rdx, %1 # Increment it
|
|
:collect_weird_string_reset
|
|
mov_al,[rdx] # Read a byte
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %0 # IF NULL == string[0]
|
|
je %collect_weird_string_done # Be done
|
|
|
|
mov_rax, %32 # Using ' '
|
|
mov_[rcx],al # hold_string[index] = ' '
|
|
add_rcx, %1 # Increment it
|
|
|
|
mov_rax,rdx # Using string
|
|
call %escape_lookup # Get the char
|
|
call %hex8 # Update RCX
|
|
|
|
mov_al,[rdx] # Read a byte
|
|
movzx_rax,al # Make it useful
|
|
add_rdx, %1 # Increment it
|
|
cmp_rax, %92 # IF string[0] == '\\'
|
|
jne %collect_weird_string_reset # Otherwise keep going
|
|
|
|
mov_al,[rdx] # Read a byte
|
|
movzx_rax,al # Make it useful
|
|
add_rdx, %1 # Increment it
|
|
cmp_rax, %120 # IF 'x' == string[1]
|
|
jne %collect_weird_string_reset # Otherwise keep going
|
|
|
|
add_rdx, %2 # Increment it
|
|
jmp %collect_weird_string_reset # Keep going
|
|
|
|
:collect_weird_string_done
|
|
mov_rax, %32 # Using ' '
|
|
mov_[rcx],al # hold_string[index] = ' '
|
|
add_rcx, %1 # Increment it
|
|
mov_rax, %48 # Using '0'
|
|
mov_[rcx],al # hold_string[index] = '0'
|
|
add_rcx, %1 # Increment it
|
|
mov_[rcx],al # hold_string[index] = '0'
|
|
add_rcx, %1 # Increment it
|
|
mov_rax, %39 # Using "'"
|
|
mov_[rcx],al # hold_string[index] = "'"
|
|
add_rcx, %1 # Increment it
|
|
mov_rax, %10 # Using "\n"
|
|
mov_[rcx],al # hold_string[index] = '\n'
|
|
pop_rax # Return our new string
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# HEX to ascii routine
|
|
# Receives INT in RAX and CHAR* in RCX
|
|
# Stores ascii of INT in CHAR*
|
|
# Returns only modifying RAX and RCX
|
|
:hex8
|
|
push_rax # Protect bottom nibble
|
|
shr_rax, !4 # do high nibble first
|
|
call %hex4 # Store it
|
|
pop_rax # do low nibble
|
|
:hex4
|
|
and_rax, %0xF # isolate nibble
|
|
add_al, !0x30 # convert to ascii
|
|
cmp_al, !0x39 # valid digit?
|
|
jbe %hex1 # yes
|
|
add_al, !7 # use alpha range
|
|
:hex1
|
|
mov_[rcx],al # store result
|
|
add_rcx, %1 # next position
|
|
ret
|
|
|
|
|
|
# type_name function
|
|
# Receives nothing
|
|
# Returns type_size in RAX
|
|
# Uses RCX for STRUCT TYPE* RET
|
|
:type_name
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %struct # Using "struct"
|
|
call %match # IF global_token->S == "struct"
|
|
mov_rcx,rax # Protect structure
|
|
cmp_rax, %0 # need to skip over "struct"
|
|
jne %type_name_native # otherwise keep going
|
|
|
|
# Deal with possible STRUCTs
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx] # global_token->next
|
|
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
|
|
mov_rax,[rbx+BYTE] !16 # global_token->S
|
|
mov_rbx,[rip+DWORD] %global_types # get all known types
|
|
call %lookup_type # Find type if possible
|
|
mov_rcx,rax # Set ret
|
|
|
|
cmp_rax, %0 # IF NULL == ret
|
|
jne %type_name_common # We have to create struct
|
|
|
|
# Create a struct
|
|
call %create_struct # Create a new struct
|
|
mov_rcx, %0 # We wish to return NULL
|
|
jmp %type_name_done # be done
|
|
|
|
:type_name_native
|
|
# Deal only with native types
|
|
mov_rax,rbx # Put global_token->S in the right place
|
|
mov_rbx,[rip+DWORD] %global_types # get all known types
|
|
call %lookup_type # Find the type if possible
|
|
mov_rcx,rax # Set ret
|
|
|
|
cmp_rax, %0 # IF NULL == ret
|
|
jne %type_name_common # We need to abort hard
|
|
|
|
# Aborting hard
|
|
mov_r15, %2 # write to standard error
|
|
lea_rax,[rip+DWORD] %type_name_string_0 # Print header
|
|
call %File_Print # Print it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %File_Print # Print it
|
|
|
|
lea_rax,[rip+DWORD] %type_name_string_1 # Print footer
|
|
call %File_Print # Print it
|
|
|
|
# call %line_error # Give details
|
|
jmp %Exit_Failure # Abort
|
|
|
|
:type_name_common
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx] # global_token->next
|
|
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
|
|
|
|
:type_name_iter
|
|
mov_rax,[rbx+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # make it useful
|
|
cmp_rax, %42 # IF global_token->S[0] == '*'
|
|
jne %type_name_done # recurse
|
|
|
|
# Deal with char**
|
|
mov_rcx,[rcx+BYTE] !24 # ret = ret->indirect
|
|
mov_rbx,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rbx] # global_token->next
|
|
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
|
|
jmp %type_name_iter # keep looping
|
|
|
|
:type_name_done
|
|
mov_rax,rcx # put ret in the right place
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:type_name_string_0
|
|
"Unknown type "
|
|
|
|
:type_name_string_1
|
|
"
|
|
"
|
|
|
|
|
|
# lookup_type function
|
|
# Receives char* s in RAX and struct type* start in RBX
|
|
# Returns struct type* in RAX
|
|
# Uses RBX for S and RCX for I
|
|
:lookup_type
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
mov_rcx,rbx # I = Start
|
|
mov_rbx,rax # Put S in place
|
|
:lookup_type_iter
|
|
cmp_rcx, %0 # Check if I == NULL
|
|
je %lookup_type_done # return NULL
|
|
|
|
mov_rax,[rcx+BYTE] !48 # I->NAME
|
|
call %match # Check if matching
|
|
cmp_rax, %0 # IF I->NAME == S
|
|
je %lookup_type_done # return it
|
|
|
|
mov_rcx,[rcx] # Otherwise I = I->NEXT
|
|
jmp %lookup_type_iter # And keep looping
|
|
|
|
:lookup_type_done
|
|
mov_rax,rcx # return either I or NULL
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# create_struct function
|
|
# Receives nothing
|
|
# Returns nothing
|
|
# Uses global_token to malloc a struct's definition
|
|
# Uses RCX for int OFFSET, RDX for struct type* head, RBP for struct type* I,
|
|
# RDI for member_size (Which is passed) and RSI for LAST
|
|
# RAX and RBX are used for scratch
|
|
:create_struct
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
push_rbp # Protect RBP
|
|
push_rdi # Protect RDI
|
|
push_rsi # Protect RSI
|
|
mov_rcx, %0 # OFFSET = 0
|
|
mov_rdi, %0 # member_size = 0
|
|
|
|
mov_rax, %56 # sizeof(struct type)
|
|
call %malloc # malloc(sizeof(struct type))
|
|
mov_rdx,rax # Set HEAD
|
|
|
|
mov_rax, %56 # sizeof(struct type)
|
|
call %malloc # malloc(sizeof(struct type))
|
|
mov_rbp,rax # Set I
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_[rdx+BYTE],rax !48 # HEAD->NAME = global_token->S
|
|
mov_[rbp+BYTE],rax !48 # I->NAME = global_token->S
|
|
|
|
mov_[rdx+BYTE],rbp !24 # HEAD->INDIRECT = I
|
|
mov_[rbp+BYTE],rdx !24 # I->INDIRECT = HEAD
|
|
|
|
mov_rax,[rip+DWORD] %global_types # Using global_types
|
|
mov_[rdx],rax # HEAD->NEXT = global_types
|
|
mov_[rip+DWORD],rdx %global_types # global_types = HEAD
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rax, %8 # Using register size
|
|
mov_[rbp+BYTE],rax !8 # I->SIZE = register size
|
|
|
|
lea_rax,[rip+DWORD] %create_struct_string_0 # Using "ERROR in create_struct\n Missing {\n"
|
|
lea_rbx,[rip+DWORD] %open_curly_brace # Using "{"
|
|
call %require_match # Make sure we have it
|
|
|
|
mov_rsi, %0 # LAST = NULL
|
|
|
|
:create_struct_iter
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # Make it useful
|
|
cmp_rax, %125 # IF global_token->S[0] == "}"
|
|
je %create_struct_done # be done
|
|
|
|
# Looks like we are adding members
|
|
# Lets see if it is a union
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
lea_rbx,[rip+DWORD] %union # Using "union"
|
|
call %match # IF match(global_token->s, "union")
|
|
cmp_rax, %0 # Deal with union
|
|
jne %create_struct_single # Otherwise deal with singles
|
|
|
|
# Deal with union
|
|
mov_rax,rsi # Put last in right place
|
|
mov_rbx,rcx # put offset in right place
|
|
call %build_union # ASSEMBLE
|
|
mov_rsi,rax # last = build_union(last, offset)
|
|
add_rcx,rdi # offset = offset + member_size
|
|
|
|
lea_rax,[rip+DWORD] %create_struct_string_1 # Using "ERROR in create_struct\n Missing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
jmp %create_struct_iter # keep going
|
|
|
|
:create_struct_single
|
|
# deal with singles
|
|
mov_rax,rsi # Put last in right place
|
|
mov_rbx,rcx # put offset in right place
|
|
call %build_member # ASSEMBLE
|
|
mov_rsi,rax # last = build_union(last, offset)
|
|
add_rcx,rdi # offset = offset + member_size
|
|
|
|
lea_rax,[rip+DWORD] %create_struct_string_1 # Using "ERROR in create_struct\n Missing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
jmp %create_struct_iter # keep going
|
|
|
|
:create_struct_done
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %create_struct_string_1 # Using "ERROR in create_struct\n Missing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
|
|
mov_[rdx+BYTE],rcx !8 # HEAD->SIZE = OFFSET
|
|
mov_[rdx+BYTE],rsi !32 # HEAD->MEMBERS = LAST
|
|
mov_[rbp+BYTE],rsi !32 # I->MEMBERS = LAST
|
|
|
|
pop_rsi # Restore RSI
|
|
pop_rdi # Restore RDI
|
|
pop_rbp # Restore RBP
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:create_struct_string_0
|
|
"ERROR in create_struct
|
|
Missing {
|
|
"
|
|
|
|
:create_struct_string_1
|
|
"ERROR in create_struct
|
|
Missing ;
|
|
"
|
|
|
|
|
|
# lookup_member function
|
|
# Receives struct type* parent in RAX and char* name in RBX
|
|
# Returns struct type* I in RAX
|
|
# Uses char* NAME in RBX, RCX for struct type* I and RDX to hold parent for errors
|
|
# Aborts hard if not found
|
|
:lookup_member
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
mov_rdx,rax # Protect Parent
|
|
mov_rcx,[rax+BYTE] !32 # struct type* I = parent->MEMBERS
|
|
:lookup_member_iter
|
|
cmp_rcx, %0 # IF I == NULL
|
|
je %lookup_member_fail # Abort HARD
|
|
|
|
mov_rax,[rcx+BYTE] !48 # Using I->NAME
|
|
call %match # IF I->NAME == NAME
|
|
cmp_rax, %0 # Then we have found the member
|
|
mov_rax,rcx # Prepare for return
|
|
mov_rcx,[rcx+BYTE] !32 # Prepare for loop I = I->MEMBERS
|
|
jne %lookup_member_iter # Looks like we are looping
|
|
|
|
# I is already in RAX
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:lookup_member_fail
|
|
mov_r15, %2 # write to standard error
|
|
lea_rax,[rip+DWORD] %lookup_member_string_0 # Using "ERROR in lookup_member "
|
|
call %File_Print # print it
|
|
|
|
mov_rax,[rdx+BYTE] !48 # PARENT->NAME
|
|
call %File_Print # print it
|
|
|
|
lea_rax,[rip+DWORD] %arrow_string # Using "->"
|
|
call %File_Print # print it
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %File_Print # print it
|
|
|
|
lea_rax,[rip+DWORD] %lookup_member_string_1 # Using " does not exist\n"
|
|
call %File_Print # print it
|
|
|
|
# call %line_error # Write useful debug info
|
|
|
|
lea_rax,[rip+DWORD] %lookup_member_string_2 # Using "\n"
|
|
call %File_Print # print it
|
|
jmp %Exit_Failure # Abort Hard
|
|
|
|
:lookup_member_string_0
|
|
"ERROR in lookup_member "
|
|
|
|
:lookup_member_string_1
|
|
" does not exist
|
|
"
|
|
|
|
:lookup_member_string_2
|
|
"
|
|
"
|
|
|
|
|
|
# build_member function
|
|
# Receives struct type* last in RAX, int offset in RBX and global member_size in RDI
|
|
# Updates member_size in RDI and returns struct type* I in RAX
|
|
# Uses RCX for struct type* member_type and RDX for struct type* I
|
|
:build_member
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
mov_rdx,rax # Put last out of the way
|
|
mov_rax, %56 # Allocate type
|
|
call %malloc # Get I
|
|
mov_[rax+BYTE],rdx !32 # I->MEMBERS = LAST
|
|
mov_[rax+BYTE],rbx !16 # I->OFFSET = OFFSET
|
|
mov_rdx,rax # Put I in place
|
|
|
|
call %type_name # Get member_type
|
|
mov_rcx,rax # Put in place
|
|
mov_[rdx+BYTE],rcx !40 # I->TYPE = MEMBER_TYPE
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rbx,[rax+BYTE] !16 # global_token->S
|
|
mov_[rdx+BYTE],rbx !48 # I->NAME = global_token->S
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
# Check if we have an array
|
|
mov_rbx,[rax+BYTE] !16 # global_token->S
|
|
lea_rax,[rip+DWORD] %open_bracket # Using "["
|
|
call %match # IF global_token->S == "["
|
|
cmp_rax, %0 # Then we have to deal with arrays in our structs
|
|
je %build_member_array # So deal with that pain
|
|
|
|
# Deal with non-array case
|
|
mov_rax,[rcx+BYTE] !8 # member_type->SIZE
|
|
mov_[rdx+BYTE],rax !8 # I->SIZE = member_type->SIZE
|
|
jmp %build_member_done # Be done
|
|
|
|
:build_member_array
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
call %numerate_string # convert number
|
|
mov_rbx,[rcx+BYTE] !40 # member_type->TYPE
|
|
mov_rbx,[rbx+BYTE] !8 # member_type->TYPE->SIZE
|
|
imul_rax,rbx # member_type->type->size * numerate_string(global_token->s)
|
|
mov_[rdx+BYTE],rax !8 # I->SIZE = member_type->type->size * numerate_string(global_token->s)
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %build_member_string_0 # Using "Struct only supports [num] form\n"
|
|
lea_rbx,[rip+DWORD] %close_bracket # Using "]"
|
|
call %require_match # Make sure we have it
|
|
|
|
:build_member_done
|
|
mov_rdi,[rdx+BYTE] !8 # MEMBER_SIZE = I->SIZE
|
|
mov_[rdx+BYTE],rcx !40 # I->TYPE = MEMBER_TYPE
|
|
mov_rax,rdx # Return I
|
|
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:build_member_string_0
|
|
"Struct only supports [num] form
|
|
"
|
|
|
|
|
|
# build_union function
|
|
# Receives struct type* last in RAX, int offset in RBX and global member_size in RDI
|
|
# Updates member_size in RDI and returns struct type* LAST in RAX
|
|
# Uses RCX for struct type* last, RDX for int offset, RSI for int size and RDI for int member_size
|
|
:build_union
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
push_rsi # Protect RSI
|
|
mov_rcx,rax # Put LAST in right spot
|
|
mov_rdx,rbx # Put OFFSET in right spot
|
|
mov_rsi, %0 # SIZE = 0
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
lea_rax,[rip+DWORD] %build_union_string_0 # Using "ERROR in build_union\nMissing {\n"
|
|
lea_rbx,[rip+DWORD] %open_curly_brace # Using "{"
|
|
call %require_match # Make sure we have it
|
|
|
|
:build_union_iter
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax+BYTE] !16 # global_token->S
|
|
mov_al,[rax] # global_token->S[0]
|
|
movzx_rax,al # make it useful
|
|
cmp_rax, %125 # IF global_token->S[0] == "}"
|
|
je %build_union_done # Be done
|
|
|
|
# Collect union member
|
|
mov_rax,rcx # Passing LAST
|
|
mov_rbx,rdx # Passing offset
|
|
call %build_member # build_member(last, offset)
|
|
mov_rcx,rax # last = build_member(last, offset)
|
|
|
|
cmp_rsi,rdi # IF member_size > size
|
|
jg %build_union_size # Then update size
|
|
|
|
# deal with member_size > size
|
|
mov_rsi,rdi # SIZE = MEMBER_SIZE
|
|
|
|
:build_union_size
|
|
lea_rax,[rip+DWORD] %build_union_string_1 # Using "ERROR in build_union\nMissing ;\n"
|
|
lea_rbx,[rip+DWORD] %semicolon # Using ";"
|
|
call %require_match # Make sure we have it
|
|
jmp %build_union_iter # Keep going
|
|
|
|
:build_union_done
|
|
mov_rdi,rsi # MEMBER_SIZE = SIZE
|
|
|
|
mov_rax,[rip+DWORD] %global_token # Using global_token
|
|
mov_rax,[rax] # global_token->NEXT
|
|
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
|
|
|
|
mov_rax,rcx # Return last
|
|
|
|
pop_rsi # Restore RSI
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:build_union_string_0
|
|
"ERROR in build_union
|
|
Missing {
|
|
"
|
|
|
|
:build_union_string_1
|
|
"ERROR in build_union
|
|
Missing ;
|
|
"
|
|
|
|
|
|
# sym_declare function
|
|
# Receives char *s in RAX, struct type* t in RBX, and struct token_list* list in RCX
|
|
# Returns struct token_list* in RAX
|
|
# Uses RAX for A
|
|
:sym_declare
|
|
push_rdx # Protect RDX
|
|
mov_rdx,rax # Get char *S safely out of the way
|
|
mov_rax, %40 # Using sizeof(struct token_list)
|
|
call %malloc # Get pointer to A
|
|
mov_[rax],rcx # A->NEXT = LIST
|
|
mov_[rax+BYTE],rdx !16 # A->S = S
|
|
mov_[rax+BYTE],rbx !24 # A->TYPE = T
|
|
pop_rdx # Restore RDX
|
|
ret
|
|
|
|
|
|
# match function
|
|
# Receives CHAR* in RAX and CHAR* in RBX
|
|
# Returns 0 (TRUE) or 1 (FALSE) in RAX
|
|
:match
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
mov_rcx,rax # S1 in place
|
|
mov_rdx,rbx # S2 in place
|
|
:match_Loop
|
|
mov_al,[rcx] # S1[0]
|
|
movzx_rax,al # Make it useful
|
|
mov_bl,[rdx] # S2[0]
|
|
movzx_rbx,bl # Make it useful
|
|
cmp_rax,rbx # See if they match
|
|
jne %match_False # If not
|
|
|
|
add_rcx, %1 # S1 = S1 + 1
|
|
add_rdx, %1 # S2 = S2 + 1
|
|
cmp_rax, %0 # If reached end of string
|
|
je %match_Done # Perfect match
|
|
jmp %match_Loop # Otherwise keep looping
|
|
|
|
:match_False
|
|
mov_rax, %1 # Return false
|
|
:match_Done
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# numerate_number function
|
|
# Receives an INT A in RAX
|
|
# Returns char* result in RAX
|
|
# Allocates 16 bytes of memory
|
|
# Behaves badly when given a negative number too large
|
|
# Uses RAX for temp, RBX for DIVISOR, RDX for mod/0, RSI for result[i] and RBP for A
|
|
:numerate_number
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
push_rsi # Protect RSI
|
|
push_rbp # Protect RBP
|
|
mov_rbp,rax # Protect A
|
|
|
|
mov_rax, %16 # 16 bytes
|
|
call %malloc # Get our pointer
|
|
push_rax # Protect our pointer
|
|
mov_rsi,rax # put pointer in right place
|
|
mov_rbx, %1000000000 # Set divisor to largest positive number that fits in 32bits
|
|
|
|
cmp_rbp, %0 # Deal with 0 case
|
|
je %numerate_number_ZERO # If it is
|
|
jg %numerate_number_positive # If it is positive
|
|
|
|
# Deal with negative case
|
|
mov_rax, %45 # Using "-"
|
|
mov_[rsi],al # Write it
|
|
add_rsi, %1 # increment
|
|
imul_rbp, %-1 # A = A * -1
|
|
|
|
:numerate_number_positive
|
|
mov_rdx, %0 # Set top to 0
|
|
mov_rax,rbp # Using A as bottom
|
|
idiv_rbx # rdx:rax % rbx -> rdx + rdx:rax / rbx -> rax [Even if we don't want it]
|
|
cmp_rax, %0 # IF 0 == (a / divisor)
|
|
jne %numerate_number_iter # Clean up those leading Zeros
|
|
|
|
mov_rdx, %0 # Set top to 0
|
|
mov_rax,rbx # Using Divisor for bottom
|
|
mov_rbx, %10 # Make this shit work because idiv 10 doesn't work
|
|
idiv_rbx # rdx:rax % 10 -> rdx + rdx:rax / 10 -> rax [Even if we don't want it]
|
|
mov_rbx,rax # Update divisor
|
|
jmp %numerate_number_positive # Keep collecting
|
|
|
|
:numerate_number_iter
|
|
cmp_rbx, %0 # IF DIVISOR < 0
|
|
jle %numerate_number_done # Be done
|
|
|
|
mov_rdx, %0 # Set top to 0
|
|
mov_rax,rbp # Using A as bottom
|
|
idiv_rbx # rdx:rax % rbx -> rdx + rdx:rax / rbx -> rax [Even if we don't want it]
|
|
add_rax, %48 # ((a / divisor) + 48)
|
|
mov_[rsi],al # Write it
|
|
mov_rbp,rdx # a = a % divisor
|
|
|
|
mov_rdx, %0 # Set top to 0
|
|
mov_rax,rbx # Using Divisor for bottom
|
|
mov_rbx, %10 # Make this shit work because idiv 10 doesn't work
|
|
idiv_rbx # rdx:rax % 10 -> rdx + rdx:rax / 10 -> rax [Even if we don't want it]
|
|
mov_rbx,rax # Update divisor
|
|
|
|
add_rsi, %1 # increment
|
|
jmp %numerate_number_iter # Keep going
|
|
|
|
:numerate_number_done
|
|
pop_rax # Restore our result
|
|
pop_rbp # Restore RBP
|
|
pop_rsi # Restore RSI
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
:numerate_number_ZERO
|
|
mov_rax, %48 # Using '0'
|
|
mov_[rsi],al # Write it
|
|
add_rsi, %1 # increment
|
|
jmp %numerate_number_done # Be done
|
|
|
|
|
|
# numerate_string function
|
|
# Receives CHAR* in RAX
|
|
# Returns value of CHAR* in RAX
|
|
# Uses RAX for VALUE, RBX for S, RCX for CH and RSI for NEGATIVE?
|
|
:numerate_string
|
|
push_rbx # Protect RBX
|
|
push_rcx # Protect RCX
|
|
push_rdx # Protect RDX
|
|
push_rsi # Protect RSI
|
|
mov_rbx,rax # put S in correct place
|
|
mov_rax, %0 # Initialize to Zero
|
|
:numerate_string_loop
|
|
mov_cl,[rbx+BYTE] !1 # S[1]
|
|
movzx_rcx,cl # make it useful
|
|
cmp_rcx, %120 # IF 'x' == S[1]
|
|
je %numerate_hex # Deal with hex input
|
|
|
|
# Assume decimal input
|
|
mov_rsi, %0 # Assume no negation
|
|
mov_cl,[rbx] # S[0]
|
|
movzx_rcx,cl # make it useful
|
|
cmp_rcx, %45 # IF '-' == S[0]
|
|
jne %numerate_decimal # Skip negation
|
|
|
|
mov_rsi, %1 # Set FLAG
|
|
add_rbx, %1 # S = S + 1
|
|
|
|
:numerate_decimal
|
|
mov_cl,[rbx] # S[0]
|
|
movzx_rcx,cl # make it useful
|
|
cmp_rcx, %0 # IF NULL == S[0]
|
|
je %numerate_decimal_done # We are done
|
|
|
|
imul_rax, %10 # VALUE = VALUE * 10
|
|
sub_rcx, %48 # CH = CH - '0'
|
|
cmp_rcx, %9 # Check for illegal
|
|
jg %numerate_string_fail # If CH > '9'
|
|
cmp_rcx, %0 # Check for illegal
|
|
jl %numerate_string_fail # IF CH < 0
|
|
add_rax,rcx # VALUE = VALUE + CH
|
|
add_rbx, %1 # S = S + 1
|
|
jmp %numerate_decimal # Keep looping
|
|
|
|
:numerate_decimal_done
|
|
cmp_rsi, %1 # Check if need to negate
|
|
jne %numerate_string_done # Nope
|
|
|
|
imul_rax, %-1 # VALUE = VALUE * -1
|
|
jmp %numerate_string_done # Done
|
|
|
|
:numerate_hex
|
|
add_rbx, %2 # S = S + 2
|
|
:numerate_hex_loop
|
|
mov_cl,[rbx] # S[0]
|
|
movzx_rcx,cl # make it useful
|
|
cmp_rcx, %0 # IF NULL == S[0]
|
|
je %numerate_string_done # We are done
|
|
|
|
shl_rax, !4 # VALUE = VALUE << 4
|
|
sub_rcx, %48 # CH = CH - '0'
|
|
cmp_rcx, %10 # IF 10 >= CH
|
|
jl %numerate_hex_digit # NO
|
|
sub_rcx, %7 # Push A-F into range
|
|
:numerate_hex_digit
|
|
cmp_rcx, %15 # Check for illegal
|
|
jg %numerate_string_fail # If CH > 'F'
|
|
cmp_rcx, %0 # Check for illegal
|
|
jl %numerate_string_fail # IF CH < 0
|
|
add_rax,rcx # VALUE = VALUE + CH
|
|
add_rbx, %1 # S = S + 1
|
|
jmp %numerate_hex_loop # Keep looping
|
|
|
|
:numerate_string_fail
|
|
mov_rax, %0 # return ZERO
|
|
|
|
:numerate_string_done
|
|
pop_rsi # Restore RSI
|
|
pop_rdx # Restore RDX
|
|
pop_rcx # Restore RCX
|
|
pop_rbx # Restore RBX
|
|
ret
|
|
|
|
|
|
# Exit_Failure function
|
|
# Receives nothing
|
|
# And aborts hard
|
|
# Does NOT return
|
|
:Exit_Failure
|
|
mov_rax, %1 # All is wrong
|
|
jmp %Done_1 # Exit gracefully
|
|
|
|
# rcx: file handle
|
|
:close_file
|
|
push_rax # allocate shadow stack space for UEFI function
|
|
call_[rcx+BYTE] !16 # file_handle->close(file_handle)
|
|
pop_rax # deallocate stack
|
|
ret
|
|
|
|
# rcx: handle
|
|
# rdx: &guid
|
|
# r9: agent_handle
|
|
# returns interface
|
|
:open_protocol
|
|
push_rax # allocate stack for interface
|
|
mov_r8,rsp # arg3 = &interface
|
|
push !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
|
|
push !0 # arg5 = NULL
|
|
sub_rsp, %32 # allocate shadow stack space for UEFI function
|
|
call_[r14+DWORD] %280 # system->boot->open_protocol(handle, &guid, &interface, agent_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)
|
|
add_rsp, %48 # deallocate stack
|
|
pop_rax # get interface
|
|
ret
|
|
|
|
# rcx: handle
|
|
# rdx: &guid
|
|
# r8: agent_handle
|
|
:close_protocol
|
|
mov_r9, %0 # arg4 = NULL
|
|
sub_rsp, %32 # allocate shadow stack space for UEFI function
|
|
call_[r14+DWORD] %288 # system->boot->close_protocol(handle, &guid, agent_handle, 0)
|
|
add_rsp, %32 # deallocate stack
|
|
ret
|
|
|
|
# rdx: number of bytes to allocate
|
|
# r14: system->boot
|
|
# returns pointer in rax
|
|
:allocate_pool
|
|
push_rdx # allocate stack for pool pointer
|
|
mov_r8,rsp # arg3 = &pool
|
|
mov_rcx, %2 # arg1 = EFI_LOADER_DATA
|
|
sub_rsp, %24 # allocate shadow stack space for UEFI
|
|
call_[r14+DWORD] %64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool)
|
|
add_rsp, %24 # deallocate stack
|
|
pop_rax # get pool
|
|
ret
|
|
|
|
# rcx: memory pool
|
|
# r14: system->boot
|
|
:free_pool
|
|
push_rax # allocate shadow stack space for UEFI function
|
|
call_[r14+DWORD] %72 # system->boot->free_pool(pool)
|
|
pop_rax # deallocate stack
|
|
ret
|
|
|
|
# Switch to uefi stack
|
|
# does not change any other registers
|
|
:enter_uefi_stack
|
|
mov_[rip+DWORD],rax %temp_rax # save RAX
|
|
pop_rax # Save return address
|
|
mov_[rip+DWORD],rsp %user_stack # save user stack
|
|
mov_rsp,[rip+DWORD] %uefi_stack # restore system stack
|
|
push_rax # Restore return address
|
|
mov_rax,[rip+DWORD] %temp_rax # restore RAX
|
|
ret
|
|
|
|
# Switch to user stack
|
|
# does not change any other registers
|
|
:exit_uefi_stack
|
|
mov_[rip+DWORD],rax %temp_rax # save RAX
|
|
pop_rax # Save return address
|
|
mov_[rip+DWORD],rsp %uefi_stack # save system stack
|
|
mov_rsp,[rip+DWORD] %user_stack # restore user stack
|
|
push_rax # Restore return address
|
|
mov_rax,[rip+DWORD] %temp_rax # restore RAX
|
|
ret
|
|
|
|
# debug_list function
|
|
# Receives struct token_list* in RAX
|
|
# Prints contents of list and exits
|
|
# Does NOT return
|
|
:debug_list
|
|
mov_r12,rax # Protect the list pointer
|
|
mov_r15, %2 # write to standard error
|
|
|
|
:debug_list_iter
|
|
# Header
|
|
lea_rax,[rip+DWORD] %debug_list_string0 # Using our first string
|
|
call %File_Print # Print it
|
|
mov_rax,r12 # Use address of pointer
|
|
call %numerate_number # Convert it into string
|
|
call %File_Print # Print it
|
|
|
|
# NEXT
|
|
lea_rax,[rip+DWORD] %debug_list_string1 # Using our second string
|
|
call %File_Print # Print it
|
|
mov_rax,[r12] # Use address of pointer
|
|
call %numerate_number # Convert it into string
|
|
call %File_Print # Print it
|
|
|
|
# PREV
|
|
lea_rax,[rip+DWORD] %debug_list_string2 # Using our third string
|
|
call %File_Print # Print it
|
|
mov_rax,[r12+BYTE] !8 # Use address of pointer
|
|
call %numerate_number # Convert it into string
|
|
call %File_Print # Print it
|
|
|
|
# S
|
|
lea_rax,[rip+DWORD] %debug_list_string3 # Using our fourth string
|
|
call %File_Print # Print it
|
|
mov_rax,[r12+BYTE] !16 # Use address of pointer
|
|
call %numerate_number # Convert it into string
|
|
call %File_Print # Print it
|
|
|
|
# S Contents
|
|
lea_rax,[rip+DWORD] %debug_list_string4 # Using our fifth string
|
|
call %File_Print # Print it
|
|
mov_rax,[r12+BYTE] !16 # Use address of string
|
|
cmp_rax, %0 # IF NULL Pointer
|
|
jne %debug_list_null # otherwise display
|
|
lea_rax,[rip+DWORD] %debug_list_string_null # Give meaningful message instead
|
|
:debug_list_null
|
|
call %File_Print # Print it
|
|
|
|
# TYPE
|
|
lea_rax,[rip+DWORD] %debug_list_string5 # Using our sixth string
|
|
call %File_Print # Print it
|
|
mov_rax,[r12+BYTE] !24 # Use address of pointer
|
|
call %numerate_number # Convert it into string
|
|
call %File_Print # Print it
|
|
|
|
# ARGS/DEPTH
|
|
lea_rax,[rip+DWORD] %debug_list_string6 # Using our seventh string
|
|
call %File_Print # Print it
|
|
mov_rax,[r12+BYTE] !32 # Use address of pointer
|
|
call %numerate_number # Convert it into string
|
|
call %File_Print # Print it
|
|
|
|
mov_rax, %10 # Add "\n"
|
|
call %fputc # print it
|
|
call %fputc # print it
|
|
|
|
mov_r12,[r12] # TOKEN = TOKEN->NEXT
|
|
cmp_r12, %0 # Check if NULL
|
|
jne %debug_list_iter # iterate otherwise
|
|
|
|
mov_rax, %666 # All is HELL
|
|
jmp %abort # Call it a bad day
|
|
|
|
:debug_list_string0
|
|
"Token_list node at address: "
|
|
|
|
:debug_list_string1
|
|
"
|
|
NEXT address: "
|
|
|
|
:debug_list_string2
|
|
"
|
|
PREV address: "
|
|
|
|
:debug_list_string3
|
|
"
|
|
S address: "
|
|
|
|
:debug_list_string4
|
|
"
|
|
The contents of S are: "
|
|
|
|
:debug_list_string5
|
|
"
|
|
TYPE address: "
|
|
|
|
:debug_list_string6
|
|
"
|
|
ARGUMENTS address: "
|
|
|
|
:debug_list_string_null
|
|
">::<NULL>::<"
|
|
|
|
# Keywords
|
|
:union
|
|
"union"
|
|
|
|
:struct
|
|
"struct"
|
|
|
|
:constant
|
|
"CONSTANT"
|
|
|
|
:main_string
|
|
"main"
|
|
|
|
:argc_string
|
|
"argc"
|
|
|
|
:argv_string
|
|
"argv"
|
|
|
|
:if_string
|
|
"if"
|
|
|
|
:else_string
|
|
"else"
|
|
|
|
:do_string
|
|
"do"
|
|
|
|
:while_string
|
|
"while"
|
|
|
|
:for_string
|
|
"for"
|
|
|
|
:asm_string
|
|
"asm"
|
|
|
|
:goto_string
|
|
"goto"
|
|
|
|
:return_string
|
|
"return"
|
|
|
|
:break_string
|
|
"break"
|
|
|
|
:continue_string
|
|
"continue"
|
|
|
|
:sizeof_string
|
|
"sizeof"
|
|
|
|
:plus_string
|
|
"+"
|
|
|
|
:minus_string
|
|
"-"
|
|
|
|
:multiply_string
|
|
"*"
|
|
|
|
:divide_string
|
|
"/"
|
|
|
|
:modulus_string
|
|
"%"
|
|
|
|
:left_shift_string
|
|
"<<"
|
|
|
|
:right_shift_string
|
|
">>"
|
|
|
|
:less_than_string
|
|
"<"
|
|
|
|
:less_than_equal_string
|
|
"<="
|
|
|
|
:greater_than_equal_string
|
|
">="
|
|
|
|
:greater_than_string
|
|
">"
|
|
|
|
:equal_to_string
|
|
"=="
|
|
|
|
:not_equal_string
|
|
"!="
|
|
|
|
:bitwise_and
|
|
"&"
|
|
|
|
:logical_and
|
|
"&&"
|
|
|
|
:bitwise_or
|
|
"|"
|
|
|
|
:logical_or
|
|
"||"
|
|
|
|
:bitwise_xor
|
|
"^"
|
|
|
|
:arrow_string
|
|
"->"
|
|
|
|
|
|
# Frequently Used strings
|
|
# Generally used by require_match
|
|
:open_curly_brace
|
|
"{"
|
|
|
|
:close_curly_brace
|
|
"}"
|
|
|
|
:open_paren
|
|
"("
|
|
|
|
:close_paren
|
|
")"
|
|
|
|
:open_bracket
|
|
"["
|
|
|
|
:close_bracket
|
|
"]"
|
|
|
|
:comma
|
|
","
|
|
|
|
:semicolon
|
|
";"
|
|
|
|
:equal
|
|
"="
|
|
|
|
:percent
|
|
"%"
|
|
|
|
:underline
|
|
"_"
|
|
|
|
|
|
:prim_types
|
|
:type_void
|
|
%type_int>type_void %0 # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_void>type_void %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_void>type_void %0 # TYPE
|
|
%type_void_name>type_void %0 # NAME
|
|
|
|
:type_int
|
|
%type_char>type_int %0 # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_int>type_int %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_int>type_int %0 # TYPE
|
|
%type_int_name>type_int %0 # NAME
|
|
|
|
:type_char
|
|
%type_file>type_char %0 # NEXT
|
|
%1 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_char_indirect>type_char %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_char>type_char %0 # TYPE
|
|
%type_char_name>type_char %0 # NAME
|
|
|
|
:type_char_indirect
|
|
%type_file>type_char_indirect %0 # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_char_double_indirect>type_char_indirect %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_char_indirect>type_char_indirect %0 # TYPE
|
|
%type_char_indirect_name>type_char_indirect %0 # NAME
|
|
|
|
:type_char_double_indirect
|
|
%type_file>type_char_double_indirect %0 # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_char_double_indirect>type_char_double_indirect %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_char_indirect>type_char_double_indirect %0xFFFFFFFF # TYPE
|
|
%type_char_double_indirect_name>type_char_double_indirect %0 # NAME
|
|
|
|
:type_file
|
|
%type_function>type_file %0 # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_file>type_file %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_file>type_file %0 # TYPE
|
|
%type_file_name>type_file %0 # NAME
|
|
|
|
:type_function
|
|
%type_unsigned>type_function %0 # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_function>type_function %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_function>type_function %0 # TYPE
|
|
%type_function_name>type_function %0 # NAME
|
|
|
|
:type_unsigned
|
|
%type_long>type_unsigned %0 # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_unsigned>type_unsigned %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_unsigned>type_unsigned %0 # TYPE
|
|
%type_unsigned_name>type_unsigned %0 # NAME
|
|
|
|
:type_long
|
|
NULL # NEXT
|
|
%8 %0 # SIZE
|
|
NULL # OFFSET
|
|
%type_long>type_long %0 # INDIRECT
|
|
NULL # MEMBERS
|
|
%type_long>type_long %0 # TYPE
|
|
%type_long_name>type_long %0 # NAME
|
|
|
|
:type_void_name
|
|
"void"
|
|
:type_int_name
|
|
"int"
|
|
:type_char_name
|
|
"char"
|
|
:type_char_indirect_name
|
|
"char*"
|
|
:type_char_double_indirect_name
|
|
"char**"
|
|
:type_file_name
|
|
"FILE"
|
|
:type_function_name
|
|
"FUNCTION"
|
|
:type_unsigned_name
|
|
"unsigned"
|
|
:type_long_name
|
|
"long"
|
|
|
|
:Address_of
|
|
NULL
|
|
:C
|
|
NULL
|
|
:Token
|
|
NULL
|
|
:break_frame
|
|
NULL
|
|
:break_target_func
|
|
NULL
|
|
:break_target_head
|
|
NULL
|
|
:break_target_num
|
|
NULL
|
|
:current_count
|
|
NULL
|
|
:current_target
|
|
NULL
|
|
:function
|
|
NULL
|
|
:global_constant_list
|
|
NULL
|
|
:global_function_list
|
|
NULL
|
|
:global_symbol_list
|
|
NULL
|
|
:global_token
|
|
NULL
|
|
:global_types
|
|
# Needed to zero pad pointer to 64 bits
|
|
NULL
|
|
:globals_list
|
|
NULL
|
|
:output_list
|
|
NULL
|
|
:string_index
|
|
NULL
|
|
:strings_list
|
|
NULL
|
|
|
|
|
|
# Protocol GUIDs
|
|
:LOADED_IMAGE_PROTOCOL
|
|
%0x5B1B31A1
|
|
@0x9562
|
|
@0x11D2
|
|
:LOADED_IMAGE_PROTOCOL_8
|
|
!0x8E !0x3F !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B
|
|
|
|
:SIMPLE_FS_PROTOCOL
|
|
%0x0964E5B22
|
|
@0x6459
|
|
@0x11D2
|
|
:SIMPLE_FS_PROTOCOL_8
|
|
!0x8E !0x39 !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B
|
|
|
|
:malloc_pool
|
|
NULL
|
|
|
|
:malloc_pointer
|
|
NULL
|
|
|
|
:uefi_stack
|
|
NULL
|
|
|
|
:user_stack
|
|
NULL
|
|
|
|
:temp_rax
|
|
NULL
|
|
|
|
:fin
|
|
NULL
|
|
|
|
:fout
|
|
NULL
|
|
|
|
:rootdir
|
|
NULL
|
|
|
|
:system
|
|
NULL
|
|
|
|
:image_handle
|
|
NULL
|
|
|
|
:root_device
|
|
NULL
|
|
|
|
:WCHAR
|
|
%0 # WCHAR with null terminator
|
|
|
|
:PE32_end
|