From d647ffa3a65b5970b9a98a2f2a7c114d1e042f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20=C5=A0tikonas?= Date: Sun, 25 Sep 2022 23:00:52 +0100 Subject: [PATCH] Add M0.hex2. --- amd64/Development/M0.M1 | 1175 ++++++++++++++++++++++++++++++ amd64/Development/M0.S | 1035 ++++++++++++++++++++++++++ amd64/Development/Makefile | 2 +- amd64/Development/hex2.M1 | 4 +- amd64/M0.hex2 | 1034 ++++++++++++++++++++++++++ amd64/PE32-amd64.hex2 | 2 +- amd64/hex2.hex1 | 2 +- amd64/mescc-tools-mini-kaem.kaem | 8 + 8 files changed, 3257 insertions(+), 5 deletions(-) create mode 100644 amd64/Development/M0.M1 create mode 100644 amd64/Development/M0.S create mode 100644 amd64/M0.hex2 diff --git a/amd64/Development/M0.M1 b/amd64/Development/M0.M1 new file mode 100644 index 0000000..39341b6 --- /dev/null +++ b/amd64/Development/M0.M1 @@ -0,0 +1,1175 @@ +# SPDX-FileCopyrightText: 2022 Andrius Štikonas +# SPDX-FileCopyrightText: 2017 Jeremiah Orians +# +# SPDX-License-Identifier: GPL-3.0-or-later + +DEFINE add_al, 04 +DEFINE add_ebx, 83C3 +DEFINE add_rax, 4805 +DEFINE add_rbx, 4881C3 +DEFINE add_rcx, 4881C1 +DEFINE add_rdx, 4881C2 +DEFINE add_rsp, 4883C4 +DEFINE add_rax,rcx 4801C8 +DEFINE add_r12,rax 4901C4 +DEFINE add_rbx,[rdi+BYTE] 48035F +DEFINE and_rax, 4883E0 +DEFINE cmp_al, 3C +DEFINE cmp_rax, 483D +DEFINE cmp_rbx, 4881FB +DEFINE cmp_rcx, 4881F9 +DEFINE cmp_rdx, 4881FA +DEFINE cmp_rsi, 4881FE +DEFINE cmp_r8, 4983F8 +DEFINE cmp_rax,rbx 4839D8 +DEFINE cmp_rax,rcx 4839C8 +DEFINE cmp_rax,r12 4C39E0 +DEFINE cmp_rbx,rdx 4839D3 +DEFINE cmp_rcx,rbx 4839D9 +DEFINE call E8 +DEFINE call_[rcx+BYTE] FF51 +DEFINE call_[r14+BYTE] 41FF56 +DEFINE call_[r14+DWORD] 41FF96 +DEFINE dec_rax 48FFC8 +DEFINE imul_rax, 486BC0 +DEFINE jbe8 76 +DEFINE je8 74 +DEFINE jg8 7F +DEFINE jl8 7C +DEFINE jmp8 EB +DEFINE jne8 75 +DEFINE je 0F84 +DEFINE jl 0F8C +DEFINE jmp E9 +DEFINE jne 0F85 +DEFINE lea_rbx,[rip+DWORD] 488D1D +DEFINE lea_rdx,[rip+DWORD] 488D15 +DEFINE mov_rax, 48C7C0 +DEFINE mov_rcx, 48C7C1 +DEFINE mov_rdx, 48C7C2 +DEFINE mov_rsi, 48C7C6 +DEFINE mov_rax,rbx 4889D8 +DEFINE mov_rax,rcx 4889C8 +DEFINE mov_rax,rdx 4889D0 +DEFINE mov_rax,r13 4C89E8 +DEFINE mov_rbx,rax 4889C3 +DEFINE mov_rbx,rcx 4889CB +DEFINE mov_rbx,r13 4C89EB +DEFINE mov_rbp,rsp 4889E5 +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_rdx,rax 4889C2 +DEFINE mov_rdx,rbx 4889DA +DEFINE mov_rdx,rsp 4889E2 +DEFINE mov_rsp,rbp 4889EC +DEFINE mov_r8,rsp 4989E0 +DEFINE mov_r12,rax 4989C4 +DEFINE mov_r13,rax 4989C5 +DEFINE mov_r13,rdx 4989D5 +DEFINE mov_al,[rbx] 8A03 +DEFINE mov_al,[rbx+rcx] 8A040B +DEFINE mov_al,[rdx] 8A02 +DEFINE mov_al,[rcx] 8A01 +DEFINE mov_bl,[rax] 8A18 +DEFINE mov_bl,[rdx] 8A1A +DEFINE mov_cl,[rax] 8A08 +DEFINE mov_cl,[rbx] 8A0B +DEFINE mov_cl,[rbx+BYTE] 8A4B +DEFINE mov_rax,[rax] 488B00 +DEFINE mov_rax,[rcx] 488B01 +DEFINE mov_rbx,[rbx] 488B1B +DEFINE mov_rcx,[rbx] 488B0B +DEFINE mov_rcx,[rcx] 488B09 +DEFINE mov_rdx,[rdx] 488B12 +DEFINE mov_[ebx],al 678803 +DEFINE mov_[rbx], C603 +DEFINE mov_[rdx],cl 880A +DEFINE mov_[rbx],rax 488903 +DEFINE mov_[rcx],rax 488901 +DEFINE mov_[rdx],r13 4C892A +DEFINE mov_[rax],BYTE C600 +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,[rdi+BYTE] 488B4F +DEFINE mov_r14,[rdx+BYTE] 4C8B72 +DEFINE mov_rcx,[rip+DWORD] 488B0D +DEFINE mov_r8,[rip+DWORD] 4C8B05 +DEFINE mov_r9,[rip+DWORD] 4C8B0D +DEFINE mov_[rax+BYTE],rbx 488958 +DEFINE mov_[rcx+BYTE],rax 488941 +DEFINE mov_[rcx+BYTE],rbx 488959 +DEFINE mov_[rdx+BYTE],rax 488942 +DEFINE mov_[rdx+BYTE],rcx 48894A +DEFINE mov_[rip+DWORD],rax 488905 +DEFINE mov_[rip+DWORD],rcx 48890D +DEFINE movzx_rax,al 480FB6C0 +DEFINE movzx_rbx,bl 480FB6DB +DEFINE movzx_rcx,cl 480FB6C9 +DEFINE popf 9D +DEFINE pop_rax 58 +DEFINE pop_rbx 5B +DEFINE pop_rcx 59 +DEFINE pop_rdx 5A +DEFINE pop_r8 4158 +DEFINE pop_r9 4159 +DEFINE pop_rsi 5E +DEFINE push 6A +DEFINE pushf 9C +DEFINE push_rax 50 +DEFINE push_rbx 53 +DEFINE push_rcx 51 +DEFINE push_rdx 52 +DEFINE push_rsi 56 +DEFINE push_r12 4154 +DEFINE ret C3 +DEFINE ror_r9 49D1C9 +DEFINE shl_rax, 48C1E0 +DEFINE shr_rax, 48C1E8 +DEFINE sub_rbx, 4883EB +DEFINE sub_rcx, 4883E9 +DEFINE sub_rsp, 4883EC +DEFINE xchg_rax,rbx 4893 +DEFINE xor_eax,eax 31C0 +DEFINE xor_esi,esi 31F6 +DEFINE xor_r9,r9 4D31C9 +DEFINE xor_r13,r13 4D31ED + + # Register usage: + # RAX, RSI, RDI => Temps + # R12 => MALLOC + # R13 => HEAD + # R14 => system->boot + + # Struct format: (size 32) + # NEXT => 0 + # TYPE => 8 + # TEXT => 16 + # EXPRESSION => 24 + + # Types + # None => 0 + # MACRO => 1 + # STRING => 2 + +# 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_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 + push_rax # allocate shadow stack space for UEFI function + push_rax # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir) + pop_rax # deallocate stack + pop_rax # 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 + je8 !loop_options_done # We are done + sub_rbx, !2 # --options + mov_al,[rbx] # *options + cmp_al, !0x20 # if *options != ' ' + jne8 !loop_options # then continue looping + mov_[rbx], !0 # zero it + add_rbx, %2 # ++options + push_rbx # push another argument onto stack + jmp8 !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 + push !1 # prepare to set arg4 to EFI_FILE_MODE_READ + pop_r9 # 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 + push !7 # to get 0x8000000000000003 we set the rightmost 3 bits + pop_r9 # 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_r12,rax # 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],BYTE !0 # zero it + cmp_rax,r12 # if we are not done yet + jne8 !zero_loop # then continue looping + + xor_r13,r13 # Set HEAD = NULL + call %Tokenize_Line # Process it + mov_rax,r13 # prepare for Reverse_List + call %Reverse_List # Correct order + mov_r13,rax # Update HEAD + call %Identify_Macros # Find the DEFINEs + call %Line_Macro # Apply the DEFINEs + call %Process_String # Handle strings + call %Eval_Immediates # Handle Numbers + call %Preserve_Other # Collect the remaining + call %Print_Hex # Output our results + +:Done + xor_eax,eax # Set exit code 0 + + # Free pool + push_rax # save exit code + + 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 + + mov_rsp,rbp # restore stack + ret # return to UEFI + + +# Tokenize_Line Function +# Using input file R15 and Head R13 +# Creates a linked list of structs +# Uses RBX for in_set strings, RCX for Int C and RDX for Struct Token* p +:Tokenize_Line + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + +:restart + call %fgetc # Read a char + cmp_rax, %-4 # Check for EOF + je8 !done # File is collected + + movzx_rax,al # We have to zero extend it to use it + mov_rcx,rax # Protect C + + lea_rbx,[rip+DWORD] %comments # Get pointer to "#;" + call %In_Set # Check for comments + cmp_rax, %1 # If comments + je %Purge_LineComment # try again + + mov_rax,rcx # put C in place for check + lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t " + call %In_Set # Check for terminators + cmp_rax, %1 # If terminator + je8 !restart # try again + + mov_rax, %32 # Malloc the struct P + call %malloc # Get pointer to P + mov_rdx,rax # Protect P + mov_[rdx],r13 # P->NEXT = HEAD + mov_r13,rdx # HEAD = P + + mov_rax,rcx # put C in place for check + lea_rbx,[rip+DWORD] %string_char # Get pointer to "\"'" + call %In_Set # Check for string chars + cmp_rax, %1 # If string char + je %Store_String # Get string + + call %Store_Atom # Get whole token + jmp8 !restart + +:done + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + 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 + xor_esi,esi # zero rsi + push_rsi # allocate stack + mov_r8,rsp # arg3 = &input + push_rax # allocate shadow stack space for UEFI function + push_rax # allocate shadow stack space for UEFI function + push_rax # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !32 # fin->read() + pop_rax # deallocate stack + pop_rax # deallocate stack + pop_rax # 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 + jne8 !fgetc_1 + mov_rax, %-4 # Put EOF in rax + +:fgetc_1 + pop_rdx # Restore RDX + pop_rcx # Restore RCX + ret # return + + +# Malloc isn't actually reserving memory here. +# It just updates the pointer in our already reserved storage pool. +:malloc + push_r12 # Save current malloc pointer + add_r12,rax # Request number of desired bytes + pop_rax # Return pointer + ret + + +# Purge_LineComment function +# Reads chars until LF and jumps to restart +:Purge_LineComment + call %fgetc # Get a char + cmp_rax, %10 # While not LF + jne8 !Purge_LineComment # Keep reading + jmp %restart + + +# Store_String Function +# Receives C in RCX, HEAD in RDX and Input file in R15 +# Uses RBX for terminator, RCX for C and RDX for string +:Store_String + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + + mov_rax, %2 # Using TYPE STRING + mov_[rdx+BYTE],rax !8 # HEAD->TYPE = STRING + mov_rax, %256 # Malloc the string + call %malloc # Get pointer to P + mov_[rdx+BYTE],rax !16 # HEAD->TEXT = STRING + mov_rbx,rcx # Protect terminator + mov_rdx,rax # Protect string pointer +:Store_String_Loop + mov_[rdx],cl # write byte + call %fgetc # read next char + mov_rcx,rax # Update C + add_rdx, %1 # STRING = STRING + 1 + cmp_rcx,rbx # See if we hit terminator + jne8 !Store_String_Loop # Otherwise keep looping + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + mov_rax,rdx # return HEAD + jmp %restart + + +# Store_Atom Function +# Receives C in RCX, HEAD in RDX and Input file in R15 +# Uses RBX for in_set strings, RCX for C and RDX for string +:Store_Atom + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + + mov_rax, %256 # Malloc the string + call %malloc # Get pointer to P + mov_[rdx+BYTE],rax !16 # HEAD->TEXT = STRING + lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t " + mov_rdx,rax # Protect string pointer +:Store_Atom_loop + mov_[rdx],cl # write byte + call %fgetc # read next char + mov_rcx,rax # Update C + add_rdx, %1 # STRING = STRING + 1 + call %In_Set # Check for terminators + cmp_rax, %0 # Check for "\n\t " + je8 !Store_Atom_loop # Loop otherwise + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + mov_rax,rdx # return HEAD + ret + + +# In_Set function +# Receives Char C in AL 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 + je8 !In_Set_True # return true + + cmp_rcx, %0 # Check for NULL + je8 !In_Set_False # return false + + add_rbx, %1 # s = s + 1 + jmp8 !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 + +# Char sets +:terminators + !10 !9 !32 !0 + +:comments + !35 !59 !0 + +:string_char + !34 !39 !0 + + +# 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 + je8 !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 + jmp8 !Reverse_List_Loop # Keep Going + +:Reverse_List_Done + pop_rcx # Restore RCX + pop_rbx # Restore RBX + ret + + +# Identify_Macros function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RBX for DEFINE, RCX for I +:Identify_Macros + push_rax # Protect RAX + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + lea_rbx,[rip+DWORD] %DEFINE_str # Setup define string + mov_rcx,rax # I = HEAD +:Identify_Macros_Loop + mov_rax,[rcx+BYTE] !16 # I->TEXT + call %match # IF "DEFINE" == I->TEXT + cmp_rax, %0 # Check if match + jne8 !Identify_Macros_Next # Skip the work + + # Deal with MACRO + mov_rax, %1 # Using MACRO + mov_[rcx+BYTE],rax !8 # I->TYPE = MACRO + + mov_rax,[rcx] # I->NEXT + mov_rax,[rax+BYTE] !16 # I->NEXT->TEXT + mov_[rcx+BYTE],rax !16 # I->TEXT = I->NEXT->TEXT + + mov_rax,[rcx] # I->NEXT + mov_rax,[rax] # I->NEXT->NEXT + mov_rax,[rax+BYTE] !16 # I->NEXT->NEXT->TEXT + mov_[rcx+BYTE],rax !24 # I->EXPRESSION = I->NEXT->NEXT->TEXT + + mov_rax,[rcx] # I->NEXT + mov_rax,[rax] # I->NEXT->NEXT + mov_rax,[rax] # I->NEXT->NEXT->NEXT + mov_[rcx],rax # I->NEXT = I->NEXT->NEXT->NEXT + +:Identify_Macros_Next + mov_rcx,[rcx] # I = I->NEXT + cmp_rcx, %0 # Check for NULL + jne8 !Identify_Macros_Loop # Keep looping otherwise + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + pop_rax # Restore RAX + ret + +:DEFINE_str + !68 !69 !70 !73 !78 !69 !0 + + +# 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 + jne8 !match_False # If not + + add_rcx, %1 # S1 = S1 + 1 + add_rdx, %1 # S2 = S2 + 1 + cmp_rax, %0 # If reached end of string + je8 !match_Done # Perfect match + jmp8 !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 + + +# Line_Macro function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RAX for I, RBX for I->TEXT, RCX for I->EXPRESSION +:Line_Macro + push_rax # Protect RAX + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX +:Line_Macro_Loop + mov_rbx,[rax+BYTE] !8 # I->TYPE + cmp_rbx, %1 # IF MACRO == I->TYPE + jne8 !Line_Macro_Next # Otherwise move on + + # Is a macro apply + mov_rbx,[rax+BYTE] !16 # I->TEXT + mov_rcx,[rax+BYTE] !24 # I->EXPRESSION + mov_rax,[rax] # I->NEXT + call %Set_Expression # Apply it + jmp8 !Line_Macro_Loop # Move on to next + +:Line_Macro_Next + mov_rax,[rax] # I->NEXT + cmp_rax, %0 # Check for NULL + jne8 !Line_Macro_Loop # Keep going + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + pop_rax # Restore RAX + ret + + +# Set_Expression function +# Receives List in RAX, CHAR* in RBX and CHAR* in RCX +# Updates the list in place; does not modify registers +# Uses RBX for C, RCX for EXP and RDX for I +:Set_Expression + push_rax # Protect RAX + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + mov_rdx,rax # Set I +:Set_Expression_Loop + mov_rax,[rdx+BYTE] !8 # I->TYPE + cmp_rax, %1 # IF MACRO == I->TYPE + je8 !Set_Expression_Next # Ignore and move on + + mov_rax,[rdx+BYTE] !16 # I->TEXT + call %match # Check for match + cmp_rax, %0 # If match + jne8 !Set_Expression_Next # Otherwise next + + # We have a non-macro match + mov_[rdx+BYTE],rcx !24 # I->EXPRESSION = EXP + +:Set_Expression_Next + mov_rdx,[rdx] # I = I->NEXT + cmp_rdx, %0 # IF NULL == I + jne8 !Set_Expression_Loop # Otherwise keep looping + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + pop_rax # Restore RAX + ret + + +# Process_String function +# Receives List in RAX +# Update the list in place; does not modify registers +# Uses RBX for I->TEXT, RCX for I and RDX for S +:Process_String + push_rax # Protect RAX + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + mov_rcx,rax # I = HEAD +:Process_String_loop + mov_rax,[rcx+BYTE] !8 # I->TYPE + cmp_rax, %2 # IF STRING == I->TYPE + jne8 !Process_String_Next # Skip to next + + mov_rbx,[rcx+BYTE] !16 # I->TEXT + mov_al,[rbx] # I->TEXT[0] + movzx_rax,al # make it useful + cmp_rax, %39 # IF '\'' == I->TEXT[0] + jne8 !Process_String_Raw # Deal with '"' + + # Deal with '\'' + add_rbx, %1 # I->TEXT + 1 + mov_[rcx+BYTE],rbx !24 # I->EXPRESSION = I->TEXT + 1 + jmp8 !Process_String_Next # Move on to next + +:Process_String_Raw + mov_rax,rbx # Get length of I->TEXT + call %string_length # Do it + shr_rax, !2 # LENGTH = LENGTH >> 2 + add_rax, %1 # LENGTH = LENGTH + 1 + shl_rax, !3 # LENGTH = LENGTH << 3 + call %malloc # Get string + mov_rdx,rbx # S = I->TEXT + add_rdx, %1 # S = S + 1 + mov_[rcx+BYTE],rax !24 # I->EXPRESSION = hexify + mov_rbx,rax # Put hexify buffer in rbx + +:Process_String_Raw_Loop + mov_al,[rdx] # Read 1 chars + movzx_rax,al # Make it useful + add_rdx, %1 # S = S + 1 + cmp_al, !0 # Check for NULL + pushf # Protect condition + call %hex8 # write them all + popf # restore condition + jne8 !Process_String_Raw_Loop # Keep looping + +:Process_String_Next + mov_rcx,[rcx] # I = I->NEXT + cmp_rcx, %0 # IF NULL == I + jne8 !Process_String_loop # Otherwise keep looping + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + pop_rax # Restore RAX + ret + + +# string_length function +# Receives CHAR* in RAX +# Returns INT in RAX +# Uses RAX for CH, RBX for S and RCX for INDEX +:string_length + push_rbx # Protect RBX + push_rcx # Protect RCX + mov_rbx,rax # Set S + mov_rcx, %0 # INDEX = 0 +:string_length_loop + mov_al,[rbx+rcx] # S[0] + movzx_rax,al # make it useful + cmp_rax, %0 # IF NULL == S[0] + je8 !string_length_done # Stop + + add_rcx, %1 # INDEX = INDEX + 1 + jmp8 !string_length_loop # Keep going + +:string_length_done + mov_rax,rcx # RETURN INDEX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + ret + + +# Eval_Immediates function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RBX for I->TEXT[0], RCX for I->TEXT[1] and RDX for I +:Eval_Immediates + push_rax # Protect RAX + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + mov_rdx,rax # I = HEAD +:Eval_Immediates_Loop + # Check for MACRO + mov_rax,[rdx+BYTE] !8 # I->TYPE + cmp_rax, %1 # IF MACRO == I->TYPE + je8 !Eval_Immediates_Next # Skip to next + + # Check for NULL EXPRESSION + mov_rax,[rdx+BYTE] !24 # I->EXPRESSION + cmp_rax, %0 # IF NULL == I->EXPRESSION + jne8 !Eval_Immediates_Next # Skip to next + + # Check if number + mov_rax,[rdx+BYTE] !16 # I->TEXT + mov_bl,[rax] # I->TEXT[0] + movzx_rbx,bl # Extend to use + add_rax, %1 # I->TEXT + 1 + mov_cl,[rax] # I->TEXT[1] + movzx_rcx,cl # Extend to use + call %numerate_string # Convert string to INT + cmp_rax, %0 # IF 0 == numerate_string(I->TEXT + 1) + jne8 !Eval_Immediates_value # Has a value + + # Last chance for Immediate + cmp_rcx, %48 # If '0' == I->TEXT[1] + jne8 !Eval_Immediates_Next # Skip to next + +:Eval_Immediates_value + call %express_number # Convert value to hex string + mov_[rdx+BYTE],rax !24 # I->EXPRESSION = express_number(value, I-TEXT[0]) + +:Eval_Immediates_Next + mov_rdx,[rdx] # I = I->NEXT + cmp_rdx, %0 # IF NULL == I + jne8 !Eval_Immediates_Loop # Otherwise keep looping + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + pop_rax # Restore RAX + ret + + +# 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] + je8 !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] + jne8 !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] + je8 !numerate_decimal_done # We are done + + imul_rax, !10 # VALUE = VALUE * 10 + sub_rcx, !48 # CH = CH - '0' + cmp_rcx, %9 # Check for illegal + jg8 !numerate_string_fail # If CH > '9' + cmp_rcx, %0 # Check for illegal + jl8 !numerate_string_fail # IF CH < 0 + add_rax,rcx # VALUE = VALUE + CH + add_rbx, %1 # S = S + 1 + jmp8 !numerate_decimal # Keep looping + +:numerate_decimal_done + cmp_rsi, %1 # Check if need to negate + jne8 !numerate_string_done # Nope + + imul_rax, !-1 # VALUE = VALUE * -1 + jmp8 !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] + je8 !numerate_string_done # We are done + + shl_rax, !4 # VALUE = VALUE << 4 + sub_rcx, !48 # CH = CH - '0' + cmp_rcx, %10 # IF 10 >= CH + jl8 !numerate_hex_digit # NO + sub_rcx, !7 # Push A-F into range +:numerate_hex_digit + cmp_rcx, %15 # Check for illegal + jg8 !numerate_string_fail # If CH > 'F' + cmp_rcx, %0 # Check for illegal + jl8 !numerate_string_fail # IF CH < 0 + add_rax,rcx # VALUE = VALUE + CH + add_rbx, %1 # S = S + 1 + jmp8 !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 + + +# express_number function +# Receives INT in RAX and CHAR in RBX +# Allocates a string and expresses the value in hex +# Returns string in RAX +# Uses RAX for VALUE, RBX for S and RCX for CH +:express_number + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX + mov_rcx,rbx # Put CH in right place + mov_rbx,rax # Protect VALUE + cmp_rcx, %37 # IF '%' == CH + jne8 !express_number2 # Otherwise try @ + + mov_rax, %9 # We need 9 bytes + call %malloc # Get S pointer + xchg_rax,rbx # Put S and VALUE in place + push_rbx # Protect S + call %hex32l # Store 32bits + jmp8 !express_number_done # done + +:express_number2 + cmp_rcx, %64 # IF '@' == CH + jne8 !express_number1 # Othrewise try ! + + mov_rax, %5 # We need 5 bytes + call %malloc # Get S pointer + xchg_rax,rbx # Put S and VALUE in place + push_rbx # Protect S + call %hex16l # Store 16bits + jmp8 !express_number_done # done + +:express_number1 + mov_rax, %3 # We need 3 bytes + call %malloc # Get S pointer + xchg_rax,rbx # Put S and VALUE in place + push_rbx # Protect S + call %hex8 # Store 8bit + +:express_number_done + pop_rax # Restore S + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + ret + + +# HEX to ascii routine +# Receives INT in RAX and CHAR* in RBX +# Stores ascii of INT in CHAR* +# Returns only modifying RAX +:hex64l + push_rax # Protect top 32 + call %hex32l # Store it + pop_rax # do top 32 + shr_rax, !32 # do bottom 32 first +:hex32l + push_rax # Protect top 16 + call %hex16l # Store it + pop_rax # do top 16 + shr_rax, !16 # do bottom 16 first +:hex16l + push_rax # Protect top byte + call %hex8 # Store it + pop_rax # do high byte + shr_rax, !8 # do bottom byte first +: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 (add '0') + cmp_al, !0x39 # valid digit? (compare to '9') + jbe8 !hex1 # yes + add_al, !7 # use alpha range +:hex1 + mov_[ebx],al # store result + add_ebx, !1 # next position + ret + + +# Preserve_Other function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RAX for I, RBX for I->TEXT +:Preserve_Other + push_rax # Protect RAX + push_rbx # Protect RBX + push_rcx # Protect RCX + push_rdx # Protect RDX +:Preserve_Other_Loop + mov_rbx,[rax+BYTE] !24 # I->EXPRESSION + cmp_rbx, %0 # IF NULL == I->EXPRESSION + jne8 !Preserve_Other_Next # Otherwise next + + # Needs preserving + mov_rbx,[rax+BYTE] !16 # I->TEXT + mov_[rax+BYTE],rbx !24 # I->EXPRESSION = I->TEXT + +:Preserve_Other_Next + mov_rax,[rax] # I = I->NEXT + cmp_rax, %0 # IF NULL == I + jne8 !Preserve_Other_Loop # Otherwise keep looping + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + pop_rbx # Restore RBX + pop_rax # Restore RAX + ret + + +# Print_Hex function +# Receives list in RAX +# walks the list and prints the I->EXPRESSION for all nodes followed by newline +# Uses RBX for I +:Print_Hex + push_rbx # Protect RBX + mov_rbx,r13 # I = Head +:Print_Hex_Loop + mov_rax,[rbx+BYTE] !8 # I->TYPE + cmp_rax, %1 # IF MACRO == I->TYPE + je8 !Print_Hex_Next # Skip + + mov_rax,[rbx+BYTE] !24 # Using EXPRESSION + call %File_Print # Print it + mov_rax, %10 # NEWLINE + call %fputc # Append it + +:Print_Hex_Next + mov_rbx,[rbx] # Iterate to next Token + cmp_rbx, %0 # Check for NULL + jne8 !Print_Hex_Loop # Otherwise keep looping + + 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 + mov_rbx,rax # Protect S + cmp_rax, %0 # Protect against nulls + je8 !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 + je8 !File_Print_Done # Stop at NULL + + call %fputc # write it + add_rbx, %1 # S = S + 1 + jmp8 !File_Print_Loop # Keep going + +:File_Print_Done + pop_rbx # Restore RBX + ret + + +# fputc function +# receives CHAR in RAX and FILE* in R14 +# writes char and returns +:fputc + push_rcx # Protect RCX + push_rdx # Protect RDX + 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 + push_rax # allocate shadow stack space for UEFI function + push_rax # allocate shadow stack space for UEFI function + push_rax # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !40 # fout->write() + add_rsp, !40 # deallocate stack + + pop_rdx # Restore RDX + pop_rcx # Restore RCX + ret # return + + +# 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 + xor_r9,r9 # 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 + push !2 + pop_rcx # arg1 = EFI_LOADER_DATA + sub_rsp, !24 # allocate shadow stack space for UEFI + call_[r14+BYTE] !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+BYTE] !72 # system->boot->free_pool(pool) + pop_rax # deallocate stack + ret + + +# 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 + %0 %0 + +:fin + %0 %0 + +:fout + %0 %0 + +:rootdir + %0 %0 + +:SystemBoot + %0 %0 + +:image_handle + %0 %0 + +:root_device + %0 %0 + +:PE32_end diff --git a/amd64/Development/M0.S b/amd64/Development/M0.S new file mode 100644 index 0000000..f4c706f --- /dev/null +++ b/amd64/Development/M0.S @@ -0,0 +1,1035 @@ +# SPDX-FileCopyrightText: 2022 Andrius Štikonas +# SPDX-FileCopyrightText: 2017 Jeremiah Orians +# +# SPDX-License-Identifier: GPL-3.0-or-later + +.global _start +.text + + # Register usage: + # RAX, RSI, RDI => Temps + # R12 => MALLOC + # R13 => HEAD + # R14 => system->boot + + # Struct format: (size 32) + # NEXT => 0 + # TYPE => 8 + # TEXT => 16 + # EXPRESSION => 24 + + # Types + # None => 0 + # MACRO => 1 + # STRING => 2 + +# efi_main(void *image_handle, struct efi_system_table *system) +_start: + mov rbp, rsp # save stack pointer + mov [rip+image_handle], rcx # save image_handle + mov r14, [rdx+96] # system->boot + + # Open Loaded Image protocol + mov r9, [rip+image_handle] # arg4 = image_handle + lea rdx, [rip+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+image_handle] # arg4 = image_handle + lea rdx, [rip+SIMPLE_FS_PROTOCOL] # guid = &SIMPLE_FS_PROTOCOL + mov rcx, [rdi+24] # arg1 = root_device = image->device + mov [rip+root_device], rcx # save root_device + call open_protocol # open protocol + mov rcx, rax # get rootfs + + # Get root directory + lea rdx, [rip+rootdir] # arg2 = &rootdir + push rax # allocate shadow stack space for UEFI function + push rax # allocate shadow stack space for UEFI function + call [rcx+8] # rootfs->open_volume(rootfs, &rootdir) + pop rax # deallocate stack + pop rax # deallocate stack + + # Push command line arguments onto stack + mov rbx, [rdi+56] # options = image->load_options + mov rdx, rbx # save beginning of load_options + add rbx, [rdi+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 BYTE PTR [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+fin] # arg2 = &fin + push 1 # arg5 = EFI_FILE_READ_ONLY + push 1 # prepare to set arg4 to EFI_FILE_MODE_READ + pop r9 # arg4 = EFI_FILE_MODE_READ + mov rcx, [rip+rootdir] # arg1 = rootdir + sub rsp, 32 # allocate shadow stack space for UEFI function + call [rcx+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+fout] # arg2 = &fout + push 0 # arg5 = 0 + push 7 # to get 0x8000000000000003 we set the rightmost 3 bits + pop r9 # 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+rootdir] # arg1 = rootdir + sub rsp, 32 # allocate shadow stack space for UEFI function + call [rcx+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 r12, rax # save malloc pointer + mov [rip+malloc_pool], rax # save the beginning of malloc pool + + # Zero allocated memory buffer + add rax, 0x1000000 # end of malloc area +zero_loop: + dec rax # next byte + mov BYTE PTR [rax], 0 # zero it + cmp rax, r12 # if we are not done yet + jne zero_loop # then continue looping + + xor r13, r13 # Set HEAD = NULL + call Tokenize_Line # Process it + mov rax, r13 # prepare for Reverse_List + call Reverse_List # Correct order + mov r13, rax # Update HEAD + call Identify_Macros # Find the DEFINEs + call Line_Macro # Apply the DEFINEs + call Process_String # Handle strings + call Eval_Immediates # Handle Numbers + call Preserve_Other # Collect the remaining + call Print_Hex # Output our results + +Done: + xor eax, eax # Set exit code 0 + + # Free pool + push rax # save exit code + + mov rcx, [rip+malloc_pool] # arg1 = malloc_pool + call free_pool # system->boot->free_pool(malloc_pool) + + mov rcx, [rip+fout] # get fout + call close_file # close fout + +failed_output: + mov rcx, [rip+fin] # get fin + call close_file # close fin + +failed_input: + mov rcx, [rip+rootdir] # get rootdir + call close_file # close rootdir + + mov r8, [rip+image_handle] # arg3 = image_handle + lea rdx, [rip+SIMPLE_FS_PROTOCOL] # guid = &SIMPLE_FS_PROTOCOL + mov rcx, [rip+root_device] # arg1 = root_device + call close_protocol # close protocol + + mov r8, [rip+image_handle] # arg3 = image_handle + lea rdx, [rip+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 + + +# Tokenize_Line Function +# Using input file R15 and Head R13 +# Creates a linked list of structs +# Uses RBX for in_set strings, RCX for Int C and RDX for Struct Token* p +Tokenize_Line: + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + +restart: + call fgetc # Read a char + cmp rax, -4 # Check for EOF + je done # File is collected + + movzx rax, al # We have to zero extend it to use it + mov rcx, rax # Protect C + + lea rbx, [rip+comments] # Get pointer to "#;" + call In_Set # Check for comments + cmp rax, 1 # If comments + je Purge_LineComment # try again + + mov rax, rcx # put C in place for check + lea rbx, [rip+terminators] # Get pointer to "\n\t " + call In_Set # Check for terminators + cmp rax, 1 # If terminator + je restart # try again + + mov rax, 32 # Malloc the struct P + call malloc # Get pointer to P + mov rdx, rax # Protect P + mov [rdx], r13 # P->NEXT = HEAD + mov r13, rdx # HEAD = P + + mov rax, rcx # put C in place for check + lea rbx, [rip+string_char] # Get pointer to "\"'" + call In_Set # Check for string chars + cmp rax, 1 # If string char + je Store_String # Get string + + call Store_Atom # Get whole token + jmp restart + +done: + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + ret + + +# fgetc function +# Returns -4 (EOF) or char in RAX +fgetc: + push rcx # Protect RCX + push rdx # Protect RDX + + mov rcx, [rip+fin] # arg1 = fin + push 1 # size = 1 + mov rdx, rsp # arg2 = &size + xor esi, esi # zero rsi + push rsi # allocate stack + mov r8, rsp # arg3 = &input + push rax # allocate shadow stack space for UEFI function + push rax # allocate shadow stack space for UEFI function + push rax # allocate shadow stack space for UEFI function + call [rcx+32] # fin->read() + pop rax # deallocate stack + pop rax # deallocate stack + pop rax # 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 + + +# Malloc isn't actually reserving memory here. +# It just updates the pointer in our already reserved storage pool. +malloc: + push r12 # Save current malloc pointer + add r12, rax # Request number of desired bytes + pop rax # Return pointer + ret + + +# Purge_LineComment function +# Reads chars until LF and jumps to restart +Purge_LineComment: + call fgetc # Get a char + cmp rax, 10 # While not LF + jne Purge_LineComment # Keep reading + jmp restart + + +# Store_String Function +# Receives C in RCX, HEAD in RDX and Input file in R15 +# Uses RBX for terminator, RCX for C and RDX for string +Store_String: + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + + mov rax, 2 # Using TYPE STRING + mov [rdx+8], rax # HEAD->TYPE = STRING + mov rax, 256 # Malloc the string + call malloc # Get pointer to P + mov [rdx+16], rax # HEAD->TEXT = STRING + mov rbx, rcx # Protect terminator + mov rdx, rax # Protect string pointer +Store_String_Loop: + mov [rdx], cl # write byte + call fgetc # read next char + mov rcx, rax # Update C + add rdx, 1 # STRING = STRING + 1 + cmp rcx, rbx # See if we hit terminator + jne Store_String_Loop # Otherwise keep looping + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + mov rax, rdx # return HEAD + jmp restart + + +# Store_Atom Function +# Receives C in RCX, HEAD in RDX and Input file in R15 +# Uses RBX for in_set strings, RCX for C and RDX for string +Store_Atom: + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + + mov rax, 256 # Malloc the string + call malloc # Get pointer to P + mov [rdx+16], rax # HEAD->TEXT = STRING + lea rbx, [rip+terminators] # Get pointer to "\n\t " + mov rdx, rax # Protect string pointer +Store_Atom_loop: + mov [rdx], cl # write byte + call fgetc # read next char + mov rcx, rax # Update C + add rdx, 1 # STRING = STRING + 1 + call In_Set # Check for terminators + cmp rax, 0 # Check for "\n\t " + je Store_Atom_loop # Loop otherwise + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + mov rax, rdx # return HEAD + ret + + +# In_Set function +# Receives Char C in AL 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 + +# Char sets +terminators: + .byte 10, 9, 32, 0 # "\n\t \0" + +comments: + .byte 35, 59, 0 # "#;\0" + +string_char: + .byte 34, 39, 0 # "\"'\0" + + +# 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 + + +# Identify_Macros function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RBX for DEFINE, RCX for I +Identify_Macros: + push rax # Protect RAX + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + lea rbx, [rip+DEFINE_str] # Setup define string + mov rcx, rax # I = HEAD +Identify_Macros_Loop: + mov rax, [rcx+16] # I->TEXT + call match # IF "DEFINE" == I->TEXT + cmp rax, 0 # Check if match + jne Identify_Macros_Next # Skip the work + + # Deal with MACRO + mov rax, 1 # Using MACRO + mov [rcx+8], rax # I->TYPE = MACRO + + mov rax, [rcx] # I->NEXT + mov rax, [rax+16] # I->NEXT->TEXT + mov [rcx+16], rax # I->TEXT = I->NEXT->TEXT + + mov rax, [rcx] # I->NEXT + mov rax, [rax] # I->NEXT->NEXT + mov rax, [rax+16] # I->NEXT->NEXT->TEXT + mov [rcx+24], rax # I->EXPRESSION = I->NEXT->NEXT->TEXT + + mov rax, [rcx] # I->NEXT + mov rax, [rax] # I->NEXT->NEXT + mov rax, [rax] # I->NEXT->NEXT->NEXT + mov [rcx], rax # I->NEXT = I->NEXT->NEXT->NEXT + +Identify_Macros_Next: + mov rcx, [rcx] # I = I->NEXT + cmp rcx, 0 # Check for NULL + jne Identify_Macros_Loop # Keep looping otherwise + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + pop rax # Restore RAX + ret + +DEFINE_str: + .byte 68, 69, 70, 73, 78, 69, 0 # "DEFINE" + + +# 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 + + +# Line_Macro function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RAX for I, RBX for I->TEXT, RCX for I->EXPRESSION +Line_Macro: + push rax # Protect RAX + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX +Line_Macro_Loop: + mov rbx, [rax+8] # I->TYPE + cmp rbx, 1 # IF MACRO == I->TYPE + jne Line_Macro_Next # Otherwise move on + + # Is a macro apply + mov rbx, [rax+16] # I->TEXT + mov rcx, [rax+24] # I->EXPRESSION + mov rax, [rax] # I->NEXT + call Set_Expression # Apply it + jmp Line_Macro_Loop # Move on to next + +Line_Macro_Next: + mov rax, [rax] # I->NEXT + cmp rax, 0 # Check for NULL + jne Line_Macro_Loop # Keep going + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + pop rax # Restore RAX + ret + + +# Set_Expression function +# Receives List in RAX, CHAR* in RBX and CHAR* in RCX +# Updates the list in place; does not modify registers +# Uses RBX for C, RCX for EXP and RDX for I +Set_Expression: + push rax # Protect RAX + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + mov rdx, rax # Set I +Set_Expression_Loop: + mov rax, [rdx+8] # I->TYPE + cmp rax, 1 # IF MACRO == I->TYPE + je Set_Expression_Next # Ignore and move on + + mov rax, [rdx+16] # I->TEXT + call match # Check for match + cmp rax, 0 # If match + jne Set_Expression_Next # Otherwise next + + # We have a non-macro match + mov [rdx+24], rcx # I->EXPRESSION = EXP + +Set_Expression_Next: + mov rdx, [rdx] # I = I->NEXT + cmp rdx, 0 # IF NULL == I + jne Set_Expression_Loop # Otherwise keep looping + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + pop rax # Restore RAX + ret + + +# Process_String function +# Receives List in RAX +# Update the list in place; does not modify registers +# Uses RBX for I->TEXT, RCX for I and RDX for S +Process_String: + push rax # Protect RAX + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + mov rcx, rax # I = HEAD +Process_String_loop: + mov rax, [rcx+8] # I->TYPE + cmp rax, 2 # IF STRING == I->TYPE + jne Process_String_Next # Skip to next + + mov rbx, [rcx+16] # I->TEXT + mov al, [rbx] # I->TEXT[0] + movzx rax, al # make it useful + cmp rax, 39 # IF '\'' == I->TEXT[0] + jne Process_String_Raw # Deal with '"' + + # Deal with '\'' + add rbx, 1 # I->TEXT + 1 + mov [rcx+24], rbx # I->EXPRESSION = I->TEXT + 1 + jmp Process_String_Next # Move on to next + +Process_String_Raw: + mov rax, rbx # Get length of I->TEXT + call string_length # Do it + shr rax, 2 # LENGTH = LENGTH >> 2 + add rax, 1 # LENGTH = LENGTH + 1 + shl rax, 3 # LENGTH = LENGTH << 3 + call malloc # Get string + mov rdx, rbx # S = I->TEXT + add rdx, 1 # S = S + 1 + mov [rcx+24], rax # I->EXPRESSION = hexify + mov rbx, rax # Put hexify buffer in rbx + +Process_String_Raw_Loop: + mov al, [rdx] # Read 1 chars + movzx rax, al # Make it useful + add rdx, 1 # S = S + 1 + cmp al, 0 # Check for NULL + pushf # Protect condition + call hex8 # write them all + popf # restore condition + jne Process_String_Raw_Loop # Keep looping + +Process_String_Next: + mov rcx, [rcx] # I = I->NEXT + cmp rcx, 0 # IF NULL == I + jne Process_String_loop # Otherwise keep looping + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + pop rax # Restore RAX + ret + + +# string_length function +# Receives CHAR* in RAX +# Returns INT in RAX +# Uses RAX for CH, RBX for S and RCX for INDEX +string_length: + push rbx # Protect RBX + push rcx # Protect RCX + mov rbx, rax # Set S + mov rcx, 0 # INDEX = 0 +string_length_loop: + mov al, [rbx+rcx] # S[0] + movzx rax, al # make it useful + cmp rax, 0 # IF NULL == S[0] + je string_length_done # Stop + + add rcx, 1 # INDEX = INDEX + 1 + jmp string_length_loop # Keep going + +string_length_done: + mov rax, rcx # RETURN INDEX + pop rcx # Restore RCX + pop rbx # Restore RBX + ret + + +# Eval_Immediates function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RBX for I->TEXT[0], RCX for I->TEXT[1] and RDX for I +Eval_Immediates: + push rax # Protect RAX + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + mov rdx, rax # I = HEAD +Eval_Immediates_Loop: + # Check for MACRO + mov rax, [rdx+8] # I->TYPE + cmp rax, 1 # IF MACRO == I->TYPE + je Eval_Immediates_Next # Skip to next + + # Check for NULL EXPRESSION + mov rax, [rdx+24] # I->EXPRESSION + cmp rax, 0 # IF NULL == I->EXPRESSION + jne Eval_Immediates_Next # Skip to next + + # Check if number + mov rax, [rdx+16] # I->TEXT + mov bl, [rax] # I->TEXT[0] + movzx rbx, bl # Extend to use + add rax, 1 # I->TEXT + 1 + mov cl, [rax] # I->TEXT[1] + movzx rcx, cl # Extend to use + call numerate_string # Convert string to INT + cmp rax, 0 # IF 0 == numerate_string(I->TEXT + 1) + jne Eval_Immediates_value # Has a value + + # Last chance for Immediate + cmp rcx, 48 # If '0' == I->TEXT[1] + jne Eval_Immediates_Next # Skip to next + +Eval_Immediates_value: + call express_number # Convert value to hex string + mov [rdx+24], rax # I->EXPRESSION = express_number(value, I-TEXT[0]) + +Eval_Immediates_Next: + mov rdx, [rdx] # I = I->NEXT + cmp rdx, 0 # IF NULL == I + jne Eval_Immediates_Loop # Otherwise keep looping + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + pop rax # Restore RAX + ret + + +# 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+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 + + +# express_number function +# Receives INT in RAX and CHAR in RBX +# Allocates a string and expresses the value in hex +# Returns string in RAX +# Uses RAX for VALUE, RBX for S and RCX for CH +express_number: + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX + mov rcx, rbx # Put CH in right place + mov rbx, rax # Protect VALUE + cmp rcx, 37 # IF '%' == CH + jne express_number2 # Otherwise try @ + + mov rax, 9 # We need 9 bytes + call malloc # Get S pointer + xchg rax, rbx # Put S and VALUE in place + push rbx # Protect S + call hex32l # Store 32bits + jmp express_number_done # done + +express_number2: + cmp rcx, 64 # IF '@' == CH + jne express_number1 # Othrewise try ! + + mov rax, 5 # We need 5 bytes + call malloc # Get S pointer + xchg rax, rbx # Put S and VALUE in place + push rbx # Protect S + call hex16l # Store 16bits + jmp express_number_done # done + +express_number1: + mov rax, 3 # We need 3 bytes + call malloc # Get S pointer + xchg rax, rbx # Put S and VALUE in place + push rbx # Protect S + call hex8 # Store 8bit + +express_number_done: + pop rax # Restore S + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + ret + + +# HEX to ascii routine +# Receives INT in RAX and CHAR* in RBX +# Stores ascii of INT in CHAR* +# Returns only modifying RAX +hex64l: + push rax # Protect top 32 + call hex32l # Store it + pop rax # do top 32 + shr rax, 32 # do bottom 32 first +hex32l: + push rax # Protect top 16 + call hex16l # Store it + pop rax # do top 16 + shr rax, 16 # do bottom 16 first +hex16l: + push rax # Protect top byte + call hex8 # Store it + pop rax # do high byte + shr rax, 8 # do bottom byte first +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, '0' # convert to ascii + cmp al, '9' # valid digit? + jbe hex1 # yes + add al, 7 # use alpha range +hex1: + mov [ebx], al # store result + add ebx, 1 # next position + ret + + +# Preserve_Other function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RAX for I, RBX for I->TEXT +Preserve_Other: + push rax # Protect RAX + push rbx # Protect RBX + push rcx # Protect RCX + push rdx # Protect RDX +Preserve_Other_Loop: + mov rbx, [rax+24] # I->EXPRESSION + cmp rbx, 0 # IF NULL == I->EXPRESSION + jne Preserve_Other_Next # Otherwise next + + # Needs preserving + mov rbx, [rax+16] # I->TEXT + mov [rax+24], rbx # I->EXPRESSION = I->TEXT + +Preserve_Other_Next: + mov rax, [rax] # I = I->NEXT + cmp rax, 0 # IF NULL == I + jne Preserve_Other_Loop # Otherwise keep looping + + pop rdx # Restore RDX + pop rcx # Restore RCX + pop rbx # Restore RBX + pop rax # Restore RAX + ret + + +# Print_Hex function +# Receives list in RAX +# walks the list and prints the I->EXPRESSION for all nodes followed by newline +# Uses RBX for I +Print_Hex: + push rbx # Protect RBX + mov rbx, r13 # I = Head +Print_Hex_Loop: + mov rax, [rbx+8] # I->TYPE + cmp rax, 1 # IF MACRO == I->TYPE + je Print_Hex_Next # Skip + + mov rax, [rbx+24] # Using EXPRESSION + call File_Print # Print it + mov rax, 10 # NEWLINE + call fputc # Append it + +Print_Hex_Next: + mov rbx, [rbx] # Iterate to next Token + cmp rbx, 0 # Check for NULL + jne Print_Hex_Loop # Otherwise keep looping + + 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 + 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 rbx # Restore RBX + ret + + +# fputc function +# receives CHAR in RAX and FILE* in R14 +# writes char and returns +fputc: + push rcx # Protect RCX + push rdx # Protect RDX + mov rcx, [rip+fout] # arg1 = fout + push 1 # set size + mov rdx, rsp # arg2 = &size + push rax # allocate stack + mov r8, rsp # arg3 = &output + push rax # allocate shadow stack space for UEFI function + push rax # allocate shadow stack space for UEFI function + push rax # allocate shadow stack space for UEFI function + call [rcx+40] # fout->write() + add rsp, 40 # deallocate stack + + pop rdx # Restore RDX + pop rcx # Restore RCX + ret # return + + +# rcx: file handle +close_file: + push rax # allocate shadow stack space for UEFI function + call [rcx+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+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: + xor r9, r9 # arg4 = NULL + sub rsp, 32 # allocate shadow stack space for UEFI function + call [r14+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 + push 2 + pop rcx # arg1 = EFI_LOADER_DATA + sub rsp, 24 # allocate shadow stack space for UEFI + call [r14+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+72] # system->boot->free_pool(pool) + pop rax # deallocate stack + ret + + +# Protocol GUIDs +LOADED_IMAGE_PROTOCOL: +.long 0x5b1b31a1 +.short 0x9562 +.short 0x11d2 +.byte 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b + +SIMPLE_FS_PROTOCOL: +.long 0x0964e5b22 +.short 0x6459 +.short 0x11d2 +.byte 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b + +malloc_pool: +.long 0, 0 + +fin: +.long 0, 0 + +fout: +.long 0, 0 + +rootdir: +.long 0, 0 + +SystemBoot: +.long 0, 0 + +image_handle: +.long 0, 0 + +root_device: +.long 0, 0 diff --git a/amd64/Development/Makefile b/amd64/Development/Makefile index 1693eeb..2440fba 100644 --- a/amd64/Development/Makefile +++ b/amd64/Development/Makefile @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -targets = kaem-optional hex0 hex1 hex2 catm +targets = kaem-optional hex0 hex1 hex2 catm M0 cc = clang cflags = -ffreestanding -MMD -mno-red-zone -std=c11 -target x86_64-unknown-windows -masm=intel diff --git a/amd64/Development/hex2.M1 b/amd64/Development/hex2.M1 index 42c8028..2a1b0d8 100644 --- a/amd64/Development/hex2.M1 +++ b/amd64/Development/hex2.M1 @@ -109,7 +109,7 @@ DEFINE sub_rax, 83E8 DEFINE sub_rbx, 4883EB DEFINE sub_rsp, 4883EC DEFINE sub_rax,rdx 4829D0 -DEFINE test_esi_esi 85F6 +DEFINE test_esi,esi 85F6 DEFINE xor_eax,eax 31C0 DEFINE xor_edx,edx 31D2 DEFINE xor_esi,esi 31F6 @@ -496,7 +496,7 @@ DEFINE xor_r9,r9 4D31C9 pop_r11 # restore r11 # If the file ended (0 bytes read) return EOF - test_esi_esi + test_esi,esi jne %Read_byte_1 mov_rax, %-4 # Put EOF in rax diff --git a/amd64/M0.hex2 b/amd64/M0.hex2 new file mode 100644 index 0000000..297044c --- /dev/null +++ b/amd64/M0.hex2 @@ -0,0 +1,1034 @@ +# SPDX-FileCopyrightText: 2022 Andrius Štikonas +# SPDX-FileCopyrightText: 2017 Jeremiah Orians +# +# SPDX-License-Identifier: GPL-3.0-or-later + + + # Register usage: + # RAX, RSI, RDI => Temps + # R12 => MALLOC + # R13 => HEAD + # R14 => system->boot + + # Struct format: (size 32) + # NEXT => 0 + # TYPE => 8 + # TEXT => 16 + # EXPRESSION => 24 + + # Types + # None => 0 + # MACRO => 1 + # STRING => 2 + +# efi_main(void *image_handle, struct efi_system_table *system) +:_start + 4889E5 ; mov_rbp,rsp # save stack pointer + 48890D %image_handle ; mov_[rip+DWORD],rcx %image_handle # save image_handle + 4C8B72 60 ; mov_r14,[rdx+BYTE] !96 # system->boot + + # Open Loaded Image protocol + 4C8B0D %image_handle ; mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle + 488D15 %LOADED_IMAGE_PROTOCOL ; lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL + 4C89C9 ; mov_rcx,r9 # arg1 = image_handle + E8 %open_protocol ; call %open_protocol # open protocol + 4889C7 ; mov_rdi,rax # save image + + # Get root file system + 4C8B0D %image_handle ; mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle + 488D15 %SIMPLE_FS_PROTOCOL ; lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL + 488B4F 18 ; mov_rcx,[rdi+BYTE] !24 # arg1 = root_device = image->device + 48890D %root_device ; mov_[rip+DWORD],rcx %root_device # save root_device + E8 %open_protocol ; call %open_protocol # open protocol + 4889C1 ; mov_rcx,rax # get rootfs + + # Get root directory + 488D15 %rootdir ; lea_rdx,[rip+DWORD] %rootdir # arg2 = &rootdir + 50 ; push_rax # allocate shadow stack space for UEFI function + 50 ; push_rax # allocate shadow stack space for UEFI function + FF51 08 ; call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir) + 58 ; pop_rax # deallocate stack + 58 ; pop_rax # deallocate stack + + # Push command line arguments onto stack + 488B5F 38 ; mov_rbx,[rdi+BYTE] !56 # options = image->load_options + 4889DA ; mov_rdx,rbx # save beginning of load_options + 48035F 30 ; add_rbx,[rdi+BYTE] !48 # go to the end of load_options + 6A 00 ; push !0 # Save end of arguments (NULL) onto stack +:loop_options + 4839D3 ; cmp_rbx,rdx # Check if we are done + 74 !loop_options_done ; je8 !loop_options_done # We are done + 4883EB 02 ; sub_rbx, !2 # --options + 8A03 ; mov_al,[rbx] # *options + 3C 20 ; cmp_al, !0x20 # if *options != ' ' + 75 !loop_options ; jne8 !loop_options # then continue looping + C603 00 ; mov_[rbx], !0 # zero it + 4881C3 02000000 ; add_rbx, %2 # ++options + 53 ; push_rbx # push another argument onto stack + EB !loop_options ; jmp8 !loop_options # next argument +:loop_options_done + + # Open file for reading + 4158 ; pop_r8 # arg3 = in + 6A 01 ; push !1 # Set exit code in case of failure + 4983F8 00 ; cmp_r8, !0 # If NULL + 0F84 %failed_input ; je %failed_input # then exit + 488D15 %fin ; lea_rdx,[rip+DWORD] %fin # arg2 = &fin + 6A 01 ; push !1 # arg5 = EFI_FILE_READ_ONLY + 6A 01 ; push !1 # prepare to set arg4 to EFI_FILE_MODE_READ + 4159 ; pop_r9 # arg4 = EFI_FILE_MODE_READ + 488B0D %rootdir ; mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir + 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function + FF51 08 ; call_[rcx+BYTE] !8 # rootdir->open() + 483D 00000000 ; cmp_rax, %0 # If failed to open + 0F85 %failed_input ; jne %failed_input # then exit + 4883C4 30 ; add_rsp, !48 # deallocate stack + + # Open file for writing + 4158 ; pop_r8 # arg3 = out + 6A 01 ; push !1 # Set exit code in case of failure + 4983F8 00 ; cmp_r8, !0 # If NULL + 0F84 %failed_output ; je %failed_output # then exit + 488D15 %fout ; lea_rdx,[rip+DWORD] %fout # arg2 = &fout + 6A 00 ; push !0 # arg5 = 0 + 6A 07 ; push !7 # to get 0x8000000000000003 we set the rightmost 3 bits + 4159 ; pop_r9 # and then do right rotation by 1 + 49D1C9 ; ror_r9 # arg4 = EFI_FILE_MODE_CREATE| EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ + 488B0D %rootdir ; mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir + 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function + FF51 08 ; call_[rcx+BYTE] !8 # rootdir->open() + 4883C4 30 ; add_rsp, !48 # deallocate stack + + # Allocate ourselves 16 MiB of memory + 48C7C2 00000001 ; mov_rdx, %0x1000000 # allocate 16 MiB of memory for malloc pool + E8 %allocate_pool ; call %allocate_pool # allocate memory + + 4989C4 ; mov_r12,rax # save malloc pointer + 488905 %malloc_pool ; mov_[rip+DWORD],rax %malloc_pool # save the beginning of malloc pool + + # Zero allocated memory buffer + 4805 00000001 ; add_rax, %0x1000000 # end of malloc area +:zero_loop + 48FFC8 ; dec_rax # next byte + C600 00 ; mov_[rax],BYTE !0 # zero it + 4C39E0 ; cmp_rax,r12 # if we are not done yet + 75 !zero_loop ; jne8 !zero_loop # then continue looping + + 4D31ED ; xor_r13,r13 # Set HEAD = NULL + E8 %Tokenize_Line ; call %Tokenize_Line # Process it + 4C89E8 ; mov_rax,r13 # prepare for Reverse_List + E8 %Reverse_List ; call %Reverse_List # Correct order + 4989C5 ; mov_r13,rax # Update HEAD + E8 %Identify_Macros ; call %Identify_Macros # Find the DEFINEs + E8 %Line_Macro ; call %Line_Macro # Apply the DEFINEs + E8 %Process_String ; call %Process_String # Handle strings + E8 %Eval_Immediates ; call %Eval_Immediates # Handle Numbers + E8 %Preserve_Other ; call %Preserve_Other # Collect the remaining + E8 %Print_Hex ; call %Print_Hex # Output our results + +:Done + 31C0 ; xor_eax,eax # Set exit code 0 + + # Free pool + 50 ; push_rax # save exit code + + 488B0D %malloc_pool ; mov_rcx,[rip+DWORD] %malloc_pool # arg1 = malloc_pool + E8 %free_pool ; call %free_pool # system->boot->free_pool(malloc_pool) + + 488B0D %fout ; mov_rcx,[rip+DWORD] %fout # get fout + E8 %close_file ; call %close_file # close fout + +:failed_output + 488B0D %fin ; mov_rcx,[rip+DWORD] %fin # get fin + E8 %close_file ; call %close_file # close fin + +:failed_input + 488B0D %rootdir ; mov_rcx,[rip+DWORD] %rootdir # get rootdir + E8 %close_file ; call %close_file # close rootdir + + 4C8B05 %image_handle ; mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle + 488D15 %SIMPLE_FS_PROTOCOL ; lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL + 488B0D %root_device ; mov_rcx,[rip+DWORD] %root_device # arg1 = root_device + E8 %close_protocol ; call %close_protocol # close protocol + + 4C8B05 %image_handle ; mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle + 488D15 %LOADED_IMAGE_PROTOCOL ; lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL + 4C89C1 ; mov_rcx,r8 # arg1 = image_handle + E8 %close_protocol ; call %close_protocol # close protocol + + 58 ; pop_rax # restore exit code + + 4889EC ; mov_rsp,rbp # restore stack + C3 ; ret # return to UEFI + + +# Tokenize_Line Function +# Using input file R15 and Head R13 +# Creates a linked list of structs +# Uses RBX for in_set strings, RCX for Int C and RDX for Struct Token* p +:Tokenize_Line + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + +:restart + E8 %fgetc ; call %fgetc # Read a char + 483D FCFFFFFF ; cmp_rax, %-4 # Check for EOF + 74 !done ; je8 !done # File is collected + + 480FB6C0 ; movzx_rax,al # We have to zero extend it to use it + 4889C1 ; mov_rcx,rax # Protect C + + 488D1D %comments ; lea_rbx,[rip+DWORD] %comments # Get pointer to "#;" + E8 %In_Set ; call %In_Set # Check for comments + 483D 01000000 ; cmp_rax, %1 # If comments + 0F84 %Purge_LineComment ; je %Purge_LineComment # try again + + 4889C8 ; mov_rax,rcx # put C in place for check + 488D1D %terminators ; lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t " + E8 %In_Set ; call %In_Set # Check for terminators + 483D 01000000 ; cmp_rax, %1 # If terminator + 74 !restart ; je8 !restart # try again + + 48C7C0 20000000 ; mov_rax, %32 # Malloc the struct P + E8 %malloc ; call %malloc # Get pointer to P + 4889C2 ; mov_rdx,rax # Protect P + 4C892A ; mov_[rdx],r13 # P->NEXT = HEAD + 4989D5 ; mov_r13,rdx # HEAD = P + + 4889C8 ; mov_rax,rcx # put C in place for check + 488D1D %string_char ; lea_rbx,[rip+DWORD] %string_char # Get pointer to "\"'" + E8 %In_Set ; call %In_Set # Check for string chars + 483D 01000000 ; cmp_rax, %1 # If string char + 0F84 %Store_String ; je %Store_String # Get string + + E8 %Store_Atom ; call %Store_Atom # Get whole token + EB !restart ; jmp8 !restart + +:done + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# fgetc function +# Returns -4 (EOF) or char in RAX +:fgetc + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + + 488B0D %fin ; mov_rcx,[rip+DWORD] %fin # arg1 = fin + 6A 01 ; push !1 # size = 1 + 4889E2 ; mov_rdx,rsp # arg2 = &size + 31F6 ; xor_esi,esi # zero rsi + 56 ; push_rsi # allocate stack + 4989E0 ; mov_r8,rsp # arg3 = &input + 50 ; push_rax # allocate shadow stack space for UEFI function + 50 ; push_rax # allocate shadow stack space for UEFI function + 50 ; push_rax # allocate shadow stack space for UEFI function + FF51 20 ; call_[rcx+BYTE] !32 # fin->read() + 58 ; pop_rax # deallocate stack + 58 ; pop_rax # deallocate stack + 58 ; pop_rax # deallocate stack + 58 ; pop_rax # save input to rax + 5E ; pop_rsi # save size to rsi + + # If the file ended (0 bytes read) return EOF + 4881FE 00000000 ; cmp_rsi, %0 # if size == 0 + 75 !fgetc_1 ; jne8 !fgetc_1 + 48C7C0 FCFFFFFF ; mov_rax, %-4 # Put EOF in rax + +:fgetc_1 + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + C3 ; ret # return + + +# Malloc isn't actually reserving memory here. +# It just updates the pointer in our already reserved storage pool. +:malloc + 4154 ; push_r12 # Save current malloc pointer + 4901C4 ; add_r12,rax # Request number of desired bytes + 58 ; pop_rax # Return pointer + C3 ; ret + + +# Purge_LineComment function +# Reads chars until LF and jumps to restart +:Purge_LineComment + E8 %fgetc ; call %fgetc # Get a char + 483D 0A000000 ; cmp_rax, %10 # While not LF + 75 !Purge_LineComment ; jne8 !Purge_LineComment # Keep reading + E9 %restart ; jmp %restart + + +# Store_String Function +# Receives C in RCX, HEAD in RDX and Input file in R15 +# Uses RBX for terminator, RCX for C and RDX for string +:Store_String + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + + 48C7C0 02000000 ; mov_rax, %2 # Using TYPE STRING + 488942 08 ; mov_[rdx+BYTE],rax !8 # HEAD->TYPE = STRING + 48C7C0 00010000 ; mov_rax, %256 # Malloc the string + E8 %malloc ; call %malloc # Get pointer to P + 488942 10 ; mov_[rdx+BYTE],rax !16 # HEAD->TEXT = STRING + 4889CB ; mov_rbx,rcx # Protect terminator + 4889C2 ; mov_rdx,rax # Protect string pointer +:Store_String_Loop + 880A ; mov_[rdx],cl # write byte + E8 %fgetc ; call %fgetc # read next char + 4889C1 ; mov_rcx,rax # Update C + 4881C2 01000000 ; add_rdx, %1 # STRING = STRING + 1 + 4839D9 ; cmp_rcx,rbx # See if we hit terminator + 75 !Store_String_Loop ; jne8 !Store_String_Loop # Otherwise keep looping + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 4889D0 ; mov_rax,rdx # return HEAD + E9 %restart ; jmp %restart + + +# Store_Atom Function +# Receives C in RCX, HEAD in RDX and Input file in R15 +# Uses RBX for in_set strings, RCX for C and RDX for string +:Store_Atom + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + + 48C7C0 00010000 ; mov_rax, %256 # Malloc the string + E8 %malloc ; call %malloc # Get pointer to P + 488942 10 ; mov_[rdx+BYTE],rax !16 # HEAD->TEXT = STRING + 488D1D %terminators ; lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t " + 4889C2 ; mov_rdx,rax # Protect string pointer +:Store_Atom_loop + 880A ; mov_[rdx],cl # write byte + E8 %fgetc ; call %fgetc # read next char + 4889C1 ; mov_rcx,rax # Update C + 4881C2 01000000 ; add_rdx, %1 # STRING = STRING + 1 + E8 %In_Set ; call %In_Set # Check for terminators + 483D 00000000 ; cmp_rax, %0 # Check for "\n\t " + 74 !Store_Atom_loop ; je8 !Store_Atom_loop # Loop otherwise + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 4889D0 ; mov_rax,rdx # return HEAD + C3 ; ret + + +# In_Set function +# Receives Char C in AL and CHAR* in RBX +# Returns 1 if true, zero if false in RAX +:In_Set + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX +:In_Set_loop + 8A0B ; mov_cl,[rbx] # Read char + 480FB6C9 ; movzx_rcx,cl # Zero extend it + + 4839C8 ; cmp_rax,rcx # See if they match + 74 !In_Set_True ; je8 !In_Set_True # return true + + 4881F9 00000000 ; cmp_rcx, %0 # Check for NULL + 74 !In_Set_False ; je8 !In_Set_False # return false + + 4881C3 01000000 ; add_rbx, %1 # s = s + 1 + EB !In_Set_loop ; jmp8 !In_Set_loop # Keep looping + +:In_Set_True + 48C7C0 01000000 ; mov_rax, %1 # Set True + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + +:In_Set_False + 48C7C0 00000000 ; mov_rax, %0 # Set FALSE + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + +# Char sets +:terminators + 0A 09 20 00 ; "\n\t \0" + +:comments + 23 3B 00 ; "#;\0" + +:string_char + 22 27 00 ; "\"'\0" + + +# Reverse_List function +# Receives List in RAX +# Returns the list reversed in RAX +:Reverse_List + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 4889C3 ; mov_rbx,rax # Set HEAD + 48C7C0 00000000 ; mov_rax, %0 # ROOT = NULL +:Reverse_List_Loop + 4881FB 00000000 ; cmp_rbx, %0 # WHILE HEAD != NULL + 74 !Reverse_List_Done ; je8 !Reverse_List_Done # Stop otherwise + + 488B0B ; mov_rcx,[rbx] # NEXT = HEAD->NEXT + 488903 ; mov_[rbx],rax # HEAD->NEXT = ROOT + 4889D8 ; mov_rax,rbx # ROOT = HEAD + 4889CB ; mov_rbx,rcx # HEAD = NEXT + EB !Reverse_List_Loop ; jmp8 !Reverse_List_Loop # Keep Going + +:Reverse_List_Done + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# Identify_Macros function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RBX for DEFINE, RCX for I +:Identify_Macros + 50 ; push_rax # Protect RAX + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 488D1D %DEFINE_str ; lea_rbx,[rip+DWORD] %DEFINE_str # Setup define string + 4889C1 ; mov_rcx,rax # I = HEAD +:Identify_Macros_Loop + 488B41 10 ; mov_rax,[rcx+BYTE] !16 # I->TEXT + E8 %match ; call %match # IF "DEFINE" == I->TEXT + 483D 00000000 ; cmp_rax, %0 # Check if match + 75 !Identify_Macros_Next ; jne8 !Identify_Macros_Next # Skip the work + + # Deal with MACRO + 48C7C0 01000000 ; mov_rax, %1 # Using MACRO + 488941 08 ; mov_[rcx+BYTE],rax !8 # I->TYPE = MACRO + + 488B01 ; mov_rax,[rcx] # I->NEXT + 488B40 10 ; mov_rax,[rax+BYTE] !16 # I->NEXT->TEXT + 488941 10 ; mov_[rcx+BYTE],rax !16 # I->TEXT = I->NEXT->TEXT + + 488B01 ; mov_rax,[rcx] # I->NEXT + 488B00 ; mov_rax,[rax] # I->NEXT->NEXT + 488B40 10 ; mov_rax,[rax+BYTE] !16 # I->NEXT->NEXT->TEXT + 488941 18 ; mov_[rcx+BYTE],rax !24 # I->EXPRESSION = I->NEXT->NEXT->TEXT + + 488B01 ; mov_rax,[rcx] # I->NEXT + 488B00 ; mov_rax,[rax] # I->NEXT->NEXT + 488B00 ; mov_rax,[rax] # I->NEXT->NEXT->NEXT + 488901 ; mov_[rcx],rax # I->NEXT = I->NEXT->NEXT->NEXT + +:Identify_Macros_Next + 488B09 ; mov_rcx,[rcx] # I = I->NEXT + 4881F9 00000000 ; cmp_rcx, %0 # Check for NULL + 75 !Identify_Macros_Loop ; jne8 !Identify_Macros_Loop # Keep looping otherwise + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 58 ; pop_rax # Restore RAX + C3 ; ret + +:DEFINE_str + 44 45 46 49 4E 45 00 ; "DEFINE" + + +# match function +# Receives CHAR* in RAX and CHAR* in RBX +# Returns 0 (TRUE) or 1 (FALSE) in RAX +:match + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 4889C1 ; mov_rcx,rax # S1 in place + 4889DA ; mov_rdx,rbx # S2 in place +:match_Loop + 8A01 ; mov_al,[rcx] # S1[0] + 480FB6C0 ; movzx_rax,al # Make it useful + 8A1A ; mov_bl,[rdx] # S2[0] + 480FB6DB ; movzx_rbx,bl # Make it useful + 4839D8 ; cmp_rax,rbx # See if they match + 75 !match_False ; jne8 !match_False # If not + + 4881C1 01000000 ; add_rcx, %1 # S1 = S1 + 1 + 4881C2 01000000 ; add_rdx, %1 # S2 = S2 + 1 + 483D 00000000 ; cmp_rax, %0 # If reached end of string + 74 !match_Done ; je8 !match_Done # Perfect match + EB !match_Loop ; jmp8 !match_Loop # Otherwise keep looping + +:match_False + 48C7C0 01000000 ; mov_rax, %1 # Return false +:match_Done + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# Line_Macro function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RAX for I, RBX for I->TEXT, RCX for I->EXPRESSION +:Line_Macro + 50 ; push_rax # Protect RAX + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX +:Line_Macro_Loop + 488B58 08 ; mov_rbx,[rax+BYTE] !8 # I->TYPE + 4881FB 01000000 ; cmp_rbx, %1 # IF MACRO == I->TYPE + 75 !Line_Macro_Next ; jne8 !Line_Macro_Next # Otherwise move on + + # Is a macro apply + 488B58 10 ; mov_rbx,[rax+BYTE] !16 # I->TEXT + 488B48 18 ; mov_rcx,[rax+BYTE] !24 # I->EXPRESSION + 488B00 ; mov_rax,[rax] # I->NEXT + E8 %Set_Expression ; call %Set_Expression # Apply it + EB !Line_Macro_Loop ; jmp8 !Line_Macro_Loop # Move on to next + +:Line_Macro_Next + 488B00 ; mov_rax,[rax] # I->NEXT + 483D 00000000 ; cmp_rax, %0 # Check for NULL + 75 !Line_Macro_Loop ; jne8 !Line_Macro_Loop # Keep going + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 58 ; pop_rax # Restore RAX + C3 ; ret + + +# Set_Expression function +# Receives List in RAX, CHAR* in RBX and CHAR* in RCX +# Updates the list in place; does not modify registers +# Uses RBX for C, RCX for EXP and RDX for I +:Set_Expression + 50 ; push_rax # Protect RAX + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 4889C2 ; mov_rdx,rax # Set I +:Set_Expression_Loop + 488B42 08 ; mov_rax,[rdx+BYTE] !8 # I->TYPE + 483D 01000000 ; cmp_rax, %1 # IF MACRO == I->TYPE + 74 !Set_Expression_Next ; je8 !Set_Expression_Next # Ignore and move on + + 488B42 10 ; mov_rax,[rdx+BYTE] !16 # I->TEXT + E8 %match ; call %match # Check for match + 483D 00000000 ; cmp_rax, %0 # If match + 75 !Set_Expression_Next ; jne8 !Set_Expression_Next # Otherwise next + + # We have a non-macro match + 48894A 18 ; mov_[rdx+BYTE],rcx !24 # I->EXPRESSION = EXP + +:Set_Expression_Next + 488B12 ; mov_rdx,[rdx] # I = I->NEXT + 4881FA 00000000 ; cmp_rdx, %0 # IF NULL == I + 75 !Set_Expression_Loop ; jne8 !Set_Expression_Loop # Otherwise keep looping + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 58 ; pop_rax # Restore RAX + C3 ; ret + + +# Process_String function +# Receives List in RAX +# Update the list in place; does not modify registers +# Uses RBX for I->TEXT, RCX for I and RDX for S +:Process_String + 50 ; push_rax # Protect RAX + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 4889C1 ; mov_rcx,rax # I = HEAD +:Process_String_loop + 488B41 08 ; mov_rax,[rcx+BYTE] !8 # I->TYPE + 483D 02000000 ; cmp_rax, %2 # IF STRING == I->TYPE + 75 !Process_String_Next ; jne8 !Process_String_Next # Skip to next + + 488B59 10 ; mov_rbx,[rcx+BYTE] !16 # I->TEXT + 8A03 ; mov_al,[rbx] # I->TEXT[0] + 480FB6C0 ; movzx_rax,al # make it useful + 483D 27000000 ; cmp_rax, %39 # IF '\'' == I->TEXT[0] + 75 !Process_String_Raw ; jne8 !Process_String_Raw # Deal with '"' + + # Deal with '\'' + 4881C3 01000000 ; add_rbx, %1 # I->TEXT + 1 + 488959 18 ; mov_[rcx+BYTE],rbx !24 # I->EXPRESSION = I->TEXT + 1 + EB !Process_String_Next ; jmp8 !Process_String_Next # Move on to next + +:Process_String_Raw + 4889D8 ; mov_rax,rbx # Get length of I->TEXT + E8 %string_length ; call %string_length # Do it + 48C1E8 02 ; shr_rax, !2 # LENGTH = LENGTH >> 2 + 4805 01000000 ; add_rax, %1 # LENGTH = LENGTH + 1 + 48C1E0 03 ; shl_rax, !3 # LENGTH = LENGTH << 3 + E8 %malloc ; call %malloc # Get string + 4889DA ; mov_rdx,rbx # S = I->TEXT + 4881C2 01000000 ; add_rdx, %1 # S = S + 1 + 488941 18 ; mov_[rcx+BYTE],rax !24 # I->EXPRESSION = hexify + 4889C3 ; mov_rbx,rax # Put hexify buffer in rbx + +:Process_String_Raw_Loop + 8A02 ; mov_al,[rdx] # Read 1 chars + 480FB6C0 ; movzx_rax,al # Make it useful + 4881C2 01000000 ; add_rdx, %1 # S = S + 1 + 3C 00 ; cmp_al, !0 # Check for NULL + 9C ; pushf # Protect condition + E8 %hex8 ; call %hex8 # write them all + 9D ; popf # restore condition + 75 !Process_String_Raw_Loop ; jne8 !Process_String_Raw_Loop # Keep looping + +:Process_String_Next + 488B09 ; mov_rcx,[rcx] # I = I->NEXT + 4881F9 00000000 ; cmp_rcx, %0 # IF NULL == I + 75 !Process_String_loop ; jne8 !Process_String_loop # Otherwise keep looping + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 58 ; pop_rax # Restore RAX + C3 ; ret + + +# string_length function +# Receives CHAR* in RAX +# Returns INT in RAX +# Uses RAX for CH, RBX for S and RCX for INDEX +:string_length + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 4889C3 ; mov_rbx,rax # Set S + 48C7C1 00000000 ; mov_rcx, %0 # INDEX = 0 +:string_length_loop + 8A040B ; mov_al,[rbx+rcx] # S[0] + 480FB6C0 ; movzx_rax,al # make it useful + 483D 00000000 ; cmp_rax, %0 # IF NULL == S[0] + 74 !string_length_done ; je8 !string_length_done # Stop + + 4881C1 01000000 ; add_rcx, %1 # INDEX = INDEX + 1 + EB !string_length_loop ; jmp8 !string_length_loop # Keep going + +:string_length_done + 4889C8 ; mov_rax,rcx # RETURN INDEX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# Eval_Immediates function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RBX for I->TEXT[0], RCX for I->TEXT[1] and RDX for I +:Eval_Immediates + 50 ; push_rax # Protect RAX + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 4889C2 ; mov_rdx,rax # I = HEAD +:Eval_Immediates_Loop + # Check for MACRO + 488B42 08 ; mov_rax,[rdx+BYTE] !8 # I->TYPE + 483D 01000000 ; cmp_rax, %1 # IF MACRO == I->TYPE + 74 !Eval_Immediates_Next ; je8 !Eval_Immediates_Next # Skip to next + + # Check for NULL EXPRESSION + 488B42 18 ; mov_rax,[rdx+BYTE] !24 # I->EXPRESSION + 483D 00000000 ; cmp_rax, %0 # IF NULL == I->EXPRESSION + 75 !Eval_Immediates_Next ; jne8 !Eval_Immediates_Next # Skip to next + + # Check if number + 488B42 10 ; mov_rax,[rdx+BYTE] !16 # I->TEXT + 8A18 ; mov_bl,[rax] # I->TEXT[0] + 480FB6DB ; movzx_rbx,bl # Extend to use + 4805 01000000 ; add_rax, %1 # I->TEXT + 1 + 8A08 ; mov_cl,[rax] # I->TEXT[1] + 480FB6C9 ; movzx_rcx,cl # Extend to use + E8 %numerate_string ; call %numerate_string # Convert string to INT + 483D 00000000 ; cmp_rax, %0 # IF 0 == numerate_string(I->TEXT + 1) + 75 !Eval_Immediates_value ; jne8 !Eval_Immediates_value # Has a value + + # Last chance for Immediate + 4881F9 30000000 ; cmp_rcx, %48 # If '0' == I->TEXT[1] + 75 !Eval_Immediates_Next ; jne8 !Eval_Immediates_Next # Skip to next + +:Eval_Immediates_value + E8 %express_number ; call %express_number # Convert value to hex string + 488942 18 ; mov_[rdx+BYTE],rax !24 # I->EXPRESSION = express_number(value, I-TEXT[0]) + +:Eval_Immediates_Next + 488B12 ; mov_rdx,[rdx] # I = I->NEXT + 4881FA 00000000 ; cmp_rdx, %0 # IF NULL == I + 75 !Eval_Immediates_Loop ; jne8 !Eval_Immediates_Loop # Otherwise keep looping + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 58 ; pop_rax # Restore RAX + C3 ; ret + + +# 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 + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 56 ; push_rsi # Protect RSI + 4889C3 ; mov_rbx,rax # put S in correct place + 48C7C0 00000000 ; mov_rax, %0 # Initialize to Zero +:numerate_string_loop + 8A4B 01 ; mov_cl,[rbx+BYTE] !1 # S[1] + 480FB6C9 ; movzx_rcx,cl # make it useful + 4881F9 78000000 ; cmp_rcx, %120 # IF 'x' == S[1] + 74 !numerate_hex ; je8 !numerate_hex # Deal with hex input + + # Assume decimal input + 48C7C6 00000000 ; mov_rsi, %0 # Assume no negation + 8A0B ; mov_cl,[rbx] # S[0] + 480FB6C9 ; movzx_rcx,cl # make it useful + 4881F9 2D000000 ; cmp_rcx, %45 # IF '-' == S[0] + 75 !numerate_decimal ; jne8 !numerate_decimal # Skip negation + + 48C7C6 01000000 ; mov_rsi, %1 # Set FLAG + 4881C3 01000000 ; add_rbx, %1 # S = S + 1 + +:numerate_decimal + 8A0B ; mov_cl,[rbx] # S[0] + 480FB6C9 ; movzx_rcx,cl # make it useful + 4881F9 00000000 ; cmp_rcx, %0 # IF NULL == S[0] + 74 !numerate_decimal_done ; je8 !numerate_decimal_done # We are done + + 486BC0 0A ; imul_rax, !10 # VALUE = VALUE * 10 + 4883E9 30 ; sub_rcx, !48 # CH = CH - '0' + 4881F9 09000000 ; cmp_rcx, %9 # Check for illegal + 7F !numerate_string_fail ; jg8 !numerate_string_fail # If CH > '9' + 4881F9 00000000 ; cmp_rcx, %0 # Check for illegal + 7C !numerate_string_fail ; jl8 !numerate_string_fail # IF CH < 0 + 4801C8 ; add_rax,rcx # VALUE = VALUE + CH + 4881C3 01000000 ; add_rbx, %1 # S = S + 1 + EB !numerate_decimal ; jmp8 !numerate_decimal # Keep looping + +:numerate_decimal_done + 4881FE 01000000 ; cmp_rsi, %1 # Check if need to negate + 75 !numerate_string_done ; jne8 !numerate_string_done # Nope + + 486BC0 FF ; imul_rax, !-1 # VALUE = VALUE * -1 + EB !numerate_string_done ; jmp8 !numerate_string_done # Done + +:numerate_hex + 4881C3 02000000 ; add_rbx, %2 # S = S + 2 +:numerate_hex_loop + 8A0B ; mov_cl,[rbx] # S[0] + 480FB6C9 ; movzx_rcx,cl # make it useful + 4881F9 00000000 ; cmp_rcx, %0 # IF NULL == S[0] + 74 !numerate_string_done ; je8 !numerate_string_done # We are done + + 48C1E0 04 ; shl_rax, !4 # VALUE = VALUE << 4 + 4883E9 30 ; sub_rcx, !48 # CH = CH - '0' + 4881F9 0A000000 ; cmp_rcx, %10 # IF 10 >= CH + 7C !numerate_hex_digit ; jl8 !numerate_hex_digit # NO + 4883E9 07 ; sub_rcx, !7 # Push A-F into range +:numerate_hex_digit + 4881F9 0F000000 ; cmp_rcx, %15 # Check for illegal + 7F !numerate_string_fail ; jg8 !numerate_string_fail # If CH > 'F' + 4881F9 00000000 ; cmp_rcx, %0 # Check for illegal + 7C !numerate_string_fail ; jl8 !numerate_string_fail # IF CH < 0 + 4801C8 ; add_rax,rcx # VALUE = VALUE + CH + 4881C3 01000000 ; add_rbx, %1 # S = S + 1 + EB !numerate_hex_loop ; jmp8 !numerate_hex_loop # Keep looping + +:numerate_string_fail + 48C7C0 00000000 ; mov_rax, %0 # return ZERO + +:numerate_string_done + 5E ; pop_rsi # Restore RSI + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# express_number function +# Receives INT in RAX and CHAR in RBX +# Allocates a string and expresses the value in hex +# Returns string in RAX +# Uses RAX for VALUE, RBX for S and RCX for CH +:express_number + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 4889D9 ; mov_rcx,rbx # Put CH in right place + 4889C3 ; mov_rbx,rax # Protect VALUE + 4881F9 25000000 ; cmp_rcx, %37 # IF '%' == CH + 75 !express_number2 ; jne8 !express_number2 # Otherwise try @ + + 48C7C0 09000000 ; mov_rax, %9 # We need 9 bytes + E8 %malloc ; call %malloc # Get S pointer + 4893 ; xchg_rax,rbx # Put S and VALUE in place + 53 ; push_rbx # Protect S + E8 %hex32l ; call %hex32l # Store 32bits + EB !express_number_done ; jmp8 !express_number_done # done + +:express_number2 + 4881F9 40000000 ; cmp_rcx, %64 # IF '@' == CH + 75 !express_number1 ; jne8 !express_number1 # Othrewise try ! + + 48C7C0 05000000 ; mov_rax, %5 # We need 5 bytes + E8 %malloc ; call %malloc # Get S pointer + 4893 ; xchg_rax,rbx # Put S and VALUE in place + 53 ; push_rbx # Protect S + E8 %hex16l ; call %hex16l # Store 16bits + EB !express_number_done ; jmp8 !express_number_done # done + +:express_number1 + 48C7C0 03000000 ; mov_rax, %3 # We need 3 bytes + E8 %malloc ; call %malloc # Get S pointer + 4893 ; xchg_rax,rbx # Put S and VALUE in place + 53 ; push_rbx # Protect S + E8 %hex8 ; call %hex8 # Store 8bit + +:express_number_done + 58 ; pop_rax # Restore S + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# HEX to ascii routine +# Receives INT in RAX and CHAR* in RBX +# Stores ascii of INT in CHAR* +# Returns only modifying RAX +:hex64l + 50 ; push_rax # Protect top 32 + E8 %hex32l ; call %hex32l # Store it + 58 ; pop_rax # do top 32 + 48C1E8 20 ; shr_rax, !32 # do bottom 32 first +:hex32l + 50 ; push_rax # Protect top 16 + E8 %hex16l ; call %hex16l # Store it + 58 ; pop_rax # do top 16 + 48C1E8 10 ; shr_rax, !16 # do bottom 16 first +:hex16l + 50 ; push_rax # Protect top byte + E8 %hex8 ; call %hex8 # Store it + 58 ; pop_rax # do high byte + 48C1E8 08 ; shr_rax, !8 # do bottom byte first +:hex8 + 50 ; push_rax # Protect bottom nibble + 48C1E8 04 ; shr_rax, !4 # do high nibble first + E8 %hex4 ; call %hex4 # Store it + 58 ; pop_rax # do low nibble +:hex4 + 4883E0 0F ; and_rax, !0xF # isolate nibble + 04 30 ; add_al, !0x30 # convert to ascii (add '0') + 3C 39 ; cmp_al, !0x39 # valid digit? (compare to '9') + 76 !hex1 ; jbe8 !hex1 # yes + 04 07 ; add_al, !7 # use alpha range +:hex1 + 678803 ; mov_[ebx],al # store result + 83C3 01 ; add_ebx, !1 # next position + C3 ; ret + + +# Preserve_Other function +# Receives List in RAX +# Updates the list in place; does not modify registers +# Uses RAX for I, RBX for I->TEXT +:Preserve_Other + 50 ; push_rax # Protect RAX + 53 ; push_rbx # Protect RBX + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX +:Preserve_Other_Loop + 488B58 18 ; mov_rbx,[rax+BYTE] !24 # I->EXPRESSION + 4881FB 00000000 ; cmp_rbx, %0 # IF NULL == I->EXPRESSION + 75 !Preserve_Other_Next ; jne8 !Preserve_Other_Next # Otherwise next + + # Needs preserving + 488B58 10 ; mov_rbx,[rax+BYTE] !16 # I->TEXT + 488958 18 ; mov_[rax+BYTE],rbx !24 # I->EXPRESSION = I->TEXT + +:Preserve_Other_Next + 488B00 ; mov_rax,[rax] # I = I->NEXT + 483D 00000000 ; cmp_rax, %0 # IF NULL == I + 75 !Preserve_Other_Loop ; jne8 !Preserve_Other_Loop # Otherwise keep looping + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + 5B ; pop_rbx # Restore RBX + 58 ; pop_rax # Restore RAX + C3 ; ret + + +# Print_Hex function +# Receives list in RAX +# walks the list and prints the I->EXPRESSION for all nodes followed by newline +# Uses RBX for I +:Print_Hex + 53 ; push_rbx # Protect RBX + 4C89EB ; mov_rbx,r13 # I = Head +:Print_Hex_Loop + 488B43 08 ; mov_rax,[rbx+BYTE] !8 # I->TYPE + 483D 01000000 ; cmp_rax, %1 # IF MACRO == I->TYPE + 74 !Print_Hex_Next ; je8 !Print_Hex_Next # Skip + + 488B43 18 ; mov_rax,[rbx+BYTE] !24 # Using EXPRESSION + E8 %File_Print ; call %File_Print # Print it + 48C7C0 0A000000 ; mov_rax, %10 # NEWLINE + E8 %fputc ; call %fputc # Append it + +:Print_Hex_Next + 488B1B ; mov_rbx,[rbx] # Iterate to next Token + 4881FB 00000000 ; cmp_rbx, %0 # Check for NULL + 75 !Print_Hex_Loop ; jne8 !Print_Hex_Loop # Otherwise keep looping + + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# File_Print function +# Receives CHAR* in RAX +# calls fputc for every non-null char +:File_Print + 53 ; push_rbx # Protect RBX + 4889C3 ; mov_rbx,rax # Protect S + 483D 00000000 ; cmp_rax, %0 # Protect against nulls + 74 !File_Print_Done ; je8 !File_Print_Done # Simply don't try to print them +:File_Print_Loop + 8A03 ; mov_al,[rbx] # Read byte + 480FB6C0 ; movzx_rax,al # zero extend + 483D 00000000 ; cmp_rax, %0 # Check for NULL + 74 !File_Print_Done ; je8 !File_Print_Done # Stop at NULL + + E8 %fputc ; call %fputc # write it + 4881C3 01000000 ; add_rbx, %1 # S = S + 1 + EB !File_Print_Loop ; jmp8 !File_Print_Loop # Keep going + +:File_Print_Done + 5B ; pop_rbx # Restore RBX + C3 ; ret + + +# fputc function +# receives CHAR in RAX and FILE* in R14 +# writes char and returns +:fputc + 51 ; push_rcx # Protect RCX + 52 ; push_rdx # Protect RDX + 488B0D %fout ; mov_rcx,[rip+DWORD] %fout # arg1 = fout + 6A 01 ; push !1 # set size + 4889E2 ; mov_rdx,rsp # arg2 = &size + 50 ; push_rax # allocate stack + 4989E0 ; mov_r8,rsp # arg3 = &output + 50 ; push_rax # allocate shadow stack space for UEFI function + 50 ; push_rax # allocate shadow stack space for UEFI function + 50 ; push_rax # allocate shadow stack space for UEFI function + FF51 28 ; call_[rcx+BYTE] !40 # fout->write() + 4883C4 28 ; add_rsp, !40 # deallocate stack + + 5A ; pop_rdx # Restore RDX + 59 ; pop_rcx # Restore RCX + C3 ; ret # return + + +# rcx: file handle +:close_file + 50 ; push_rax # allocate shadow stack space for UEFI function + FF51 10 ; call_[rcx+BYTE] !16 # file_handle->close(file_handle) + 58 ; pop_rax # deallocate stack + C3 ; ret + +# rcx: handle +# rdx: &guid +# r9: agent_handle +# returns interface +:open_protocol + 50 ; push_rax # allocate stack for interface + 4989E0 ; mov_r8,rsp # arg3 = &interface + 6A 01 ; push !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + 6A 00 ; push !0 # arg5 = NULL + 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function + 41FF96 18010000 ; call_[r14+DWORD] %280 # system->boot->open_protocol(handle, &guid, &interface, agent_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL) + 4883C4 30 ; add_rsp, !48 # deallocate stack + 58 ; pop_rax # get image + C3 ; ret + +# rcx: handle +# rdx: &guid +# r8: agent_handle +:close_protocol + 4D31C9 ; xor_r9,r9 # arg4 = NULL + 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function + 41FF96 20010000 ; call_[r14+DWORD] %288 # system->boot->close_protocol(handle, &guid, agent_handle, 0) + 4883C4 20 ; add_rsp, !32 # deallocate stack + C3 ; ret + +# rdx: number of bytes to allocate +# r14: system->boot +# returns pointer in rax +:allocate_pool + 52 ; push_rdx # allocate stack for pool pointer + 4989E0 ; mov_r8,rsp # arg3 = &pool + 6A 02 ; push !2 + 59 ; pop_rcx # arg1 = EFI_LOADER_DATA + 4883EC 18 ; sub_rsp, !24 # allocate shadow stack space for UEFI + 41FF56 40 ; call_[r14+BYTE] !64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool) + 4883C4 18 ; add_rsp, !24 # deallocate stack + 58 ; pop_rax # get pool + C3 ; ret + +# rcx: memory pool +# r14: system->boot +:free_pool + 50 ; push_rax # allocate shadow stack space for UEFI function + 41FF56 48 ; call_[r14+BYTE] !72 # system->boot->free_pool(pool) + 58 ; pop_rax # deallocate stack + C3 ; ret + + +# Protocol GUIDs +:LOADED_IMAGE_PROTOCOL + A1 31 1B 5B ; %0x5B1B31A1 + 62 95 ; @0x9562 + D2 11 ; @0x11D2 + 8E 3F 00 A0 C9 69 72 3B ; !0x8E !0x3F !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B + +:SIMPLE_FS_PROTOCOL + 22 5B 4E 96 ; %0x0964E5B22 + 59 64 ; @0x6459 + D2 11 ; @0x11D2 + 8E 39 00 A0 C9 69 72 3B ; !0x8E !0x39 !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B + +:malloc_pool + 00000000 00000000 + +:fin + 00000000 00000000 + +:fout + 00000000 00000000 + +:rootdir + 00000000 00000000 + +:SystemBoot + 00000000 00000000 + +:image_handle + 00000000 00000000 + +:root_device + 00000000 00000000 + +:PE32_end diff --git a/amd64/PE32-amd64.hex2 b/amd64/PE32-amd64.hex2 index 8270401..aad4474 100644 --- a/amd64/PE32-amd64.hex2 +++ b/amd64/PE32-amd64.hex2 @@ -118,7 +118,7 @@ F0 00 # SizeOfOptionalHeader # [0x148] # Start of section headers -00 00 00 00 00 00 00 00 ; Name of the section (empty) but could set to ".text" +2E 74 65 78 74 00 00 00 ; Name of the section: ".text" %PE32_end>PE32_text ; VirtualSize 00 10 00 00 ; VirtualAddress %PE32_end>PE32_text ; SizeOfRawData diff --git a/amd64/hex2.hex1 b/amd64/hex2.hex1 index 7897275..9c26c1c 100644 --- a/amd64/hex2.hex1 +++ b/amd64/hex2.hex1 @@ -515,7 +515,7 @@ DD 06 00 00 ; SizeOfRawData 415B ; pop_r11 # restore r11 # If the file ended (0 bytes read) return EOF - 85F6 ; test_esi_esi + 85F6 ; test_esi,esi 0F85 %y ; jne %Read_byte_1 48C7C0 FCFFFFFF ; mov_rax, %-4 # Put EOF in rax diff --git a/amd64/mescc-tools-mini-kaem.kaem b/amd64/mescc-tools-mini-kaem.kaem index 9aa32d0..a7736ef 100644 --- a/amd64/mescc-tools-mini-kaem.kaem +++ b/amd64/mescc-tools-mini-kaem.kaem @@ -26,3 +26,11 @@ amd64\artifact\hex1.efi amd64\hex2.hex1 amd64\artifact\hex2-0.efi amd64\artifact\hex2-0.efi amd64\catm.hex2 amd64\artifact\catm.efi # catm removes the need for cat or shell support for redirection by providing # equivalent functionality via catm output_file input1 input2 ... inputN + +############################### +# Phase-3 Build M0 from hex2 # +############################### +amd64\artifact\catm.efi amd64\artifact\M0.hex2 amd64\PE32-amd64.hex2 amd64\M0.hex2 +amd64\artifact\hex2-0.efi amd64\artifact\M0.hex2 amd64\artifact\M0.efi +# M0 is the architecture specific version of M1 and is by design single +# architecture only and will be replaced by the C code version of M1