add flat assembler toolchain

This commit is contained in:
2024-11-24 23:13:28 -05:00
parent 99e8e4072b
commit dbfd94ea40
302 changed files with 145599 additions and 0 deletions

View File

@ -0,0 +1,254 @@
match ,{
include 'win32a.inc'
include 'localptr.inc'
} match -,{
else
include 'selfhost.inc'
end match
_ equ }
format PE large NX DLL
entry DllEntryPoint
include '../../version.inc'
struct MEMORY_REGION
address dd ?
size dd ?
ends
section '.text' code executable
include '../../assembler.inc'
include '../../symbols.inc'
include '../../expressions.inc'
include '../../conditions.inc'
include '../../floats.inc'
include '../../directives.inc'
include '../../calm.inc'
include '../../errors.inc'
include '../../map.inc'
include '../../reader.inc'
include '../../output.inc'
include '../../console.inc'
DllEntryPoint:
mov eax,1
retn 12
fasmg_GetVersion:
mov eax,version_string
retn
fasmg_Assemble:
virtual at ebp - LOCAL_VARIABLES_SIZE
LocalVariables:
include '../../variables.inc'
maximum_number_of_passes dd ?
timestamp dq ?
systemtime SYSTEMTIME
filetime FILETIME
memory dd ?
systmp dd ?
rb (LocalVariables - $) and 11b
LOCAL_VARIABLES_SIZE = $ - LocalVariables
assert $ - ebp = 0
previous_frame dd ?
stored_edi dd ?
stored_esi dd ?
stored_ebx dd ?
return_address dd ?
FunctionParameters:
source_string dd ?
source_path dd ?
output_region dd ?
output_path dd ?
stdout dd ?
stderr dd ?
FUNCTION_PARAMETERS_SIZE = $ - FunctionParameters
end virtual
push ebx esi edi
enter LOCAL_VARIABLES_SIZE,0
call system_init
mov [maximum_number_of_passes],100
mov [maximum_number_of_errors],1000
mov [maximum_depth_of_stack],10000
xor al,al
call assembly_init
assemble:
mov esi,[source_string]
mov edx,[source_path]
call assembly_pass
jc assembly_done
mov eax,[current_pass]
cmp eax,[maximum_number_of_passes]
jb assemble
call show_display_data
call assembly_shutdown
call system_shutdown
mov eax,-2
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
assembly_done:
call show_display_data
cmp [first_error],0
jne assembly_failed
mov esi,[output_region]
test esi,esi
jz output_copied
call get_output_length
test edx,edx
jnz out_of_memory
mov [value_length],eax
xchg eax,[esi+MEMORY_REGION.size]
cmp [esi+MEMORY_REGION.address],0
je new_region_for_output
cmp eax,[value_length]
jae copy_output
invoke VirtualAlloc,[esi+MEMORY_REGION.address],[esi+MEMORY_REGION.size],MEM_COMMIT,PAGE_READWRITE
test eax,eax
jnz copy_output
invoke VirtualFree,[esi+MEMORY_REGION.address],0,MEM_RELEASE
new_region_for_output:
invoke VirtualAlloc,0,[esi+MEMORY_REGION.size],MEM_COMMIT,PAGE_READWRITE
test eax,eax
jz out_of_memory
mov [esi+MEMORY_REGION.address],eax
copy_output:
mov edi,[esi+MEMORY_REGION.address]
xor eax,eax
mov dword [file_offset],eax
mov dword [file_offset+4],eax
call read_from_output
output_copied:
mov ebx,[source_path]
mov edi,[output_path]
mov eax,ebx
or eax,edi
jz output_written
call write_output_file
jc write_failed
output_written:
call assembly_shutdown
call system_shutdown
xor eax,eax
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
assembly_failed:
mov eax,[first_error]
xor ecx,ecx
count_errors:
inc ecx
mov eax,[eax+Error.next]
test eax,eax
jnz count_errors
push ecx
call show_errors
call assembly_shutdown
call system_shutdown
pop eax
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
write_failed:
call assembly_shutdown
call system_shutdown
mov eax,-3
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
out_of_memory:
call assembly_shutdown
call system_shutdown
mov eax,-1
leave
pop edi esi ebx
retn FUNCTION_PARAMETERS_SIZE
include 'system.inc'
section '.rdata' data readable
data import
library kernel32,'KERNEL32.DLL'
import kernel32,\
CloseHandle,'CloseHandle',\
CreateFile,'CreateFileA',\
ExitProcess,'ExitProcess',\
GetCommandLine,'GetCommandLineA',\
GetEnvironmentVariable,'GetEnvironmentVariableA',\
GetStdHandle,'GetStdHandle',\
GetSystemTime,'GetSystemTime',\
GetTickCount,'GetTickCount',\
HeapAlloc,'HeapAlloc',\
HeapCreate,'HeapCreate',\
HeapDestroy,'HeapDestroy',\
HeapFree,'HeapFree',\
HeapReAlloc,'HeapReAlloc',\
HeapSize,'HeapSize',\
VirtualAlloc,'VirtualAlloc',\
VirtualFree,'VirtualFree',\
ReadFile,'ReadFile',\
SetFilePointer,'SetFilePointer',\
SystemTimeToFileTime,'SystemTimeToFileTime',\
WriteFile,'WriteFile',\
GetLastError,'GetLastError'
end data
align 4
data export
export 'FASMG.DLL',\
fasmg_GetVersion,'fasmg_GetVersion',\
fasmg_Assemble,'fasmg_Assemble'
end data
include '../../tables.inc'
include '../../messages.inc'
version_string db VERSION,0
section '.reloc' fixups data readable discardable

View File

@ -0,0 +1,28 @@
macro pushd arg
{
if arg eqtype +ebp & arg relativeto ebp
if arg - ebp
push eax
lea eax,[arg]
xchg eax,[esp]
else
push ebp
end if
else if ~ arg eq
pushd arg
end if
}
macro mov dest,src
{
if src eqtype +ebp & src relativeto ebp
if src - ebp
lea dest,[src]
else
mov dest,ebp
end if
else
mov dest,src
end if
}

View File

@ -0,0 +1,266 @@
include '../../../examples/x86/include/80386.inc'
macro format?.PE? settings
PE.Settings.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE or IMAGE_FILE_LINE_NUMS_STRIPPED or IMAGE_FILE_LOCAL_SYMS_STRIPPED
PE.Settings.DllCharacteristics = 0
PE.Settings.Stamp = +VERSION
PE.Settings.LegacyHeaders = 0
local seq
define seq settings:
while 1
match :, seq
break
else match =DLL? more, seq
PE.Settings.Characteristics = PE.Settings.Characteristics or IMAGE_FILE_DLL
redefine seq more
else match =large? more, seq
PE.Settings.Characteristics = PE.Settings.Characteristics or IMAGE_FILE_LARGE_ADDRESS_AWARE
redefine seq more
else match =WDM? more, seq
PE.Settings.DllCharacteristics = PE.Settings.DllCharacteristics or IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
redefine seq more
else match =NX? more, seq
PE.Settings.DllCharacteristics = PE.Settings.DllCharacteristics or IMAGE_DLLCHARACTERISTICS_NX_COMPAT
redefine seq more
else match =at? base =on? stub :, seq
PE.Settings.ImageBase = base
PE.Settings.Stub = stub
break
else match =at? base :, seq
PE.Settings.ImageBase = base
break
else match =on? stub :, seq
PE.Settings.Stub = stub
break
else
match =GUI? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
redefine seq more
else match =console? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
redefine seq more
else match =native? more, seq
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_NATIVE
PE.Settings.SectionAlignment = 32
PE.Settings.FileAlignment = 32
redefine seq more
else match =EFI? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION
redefine seq more
else match =EFIboot? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
redefine seq more
else match =EFIruntime? more, seq
PE.Settings.Magic = 0x20B
PE.Settings.Subsystem = IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
redefine seq more
else
err 'invalid argument'
break
end match
match V.v more, seq
PE.Settings.MajorSubsystemVersion = V
PE.Settings.MinorSubsystemVersion = v
redefine seq more
end match
end match
end while
if PE.Settings.Characteristics and IMAGE_FILE_DLL
format binary as 'dll'
else
format binary as 'exe'
end if
include '../../../examples/x86/include/format/pe.inc'
use32
end macro
macro struct? name
macro ends?!
end namespace
esc end struc
virtual at 0
name name
sizeof.name = $
end virtual
purge ends?
end macro
esc struc name
label . : sizeof.name
namespace .
end macro
calminstruction invoke? proc*,args&
local tmp, tmpst, stack
match , args
jyes go
collect:
match tmpst=,args, args
take stack, tmpst
jyes collect
push:
match tmp], args
jyes regular
check args relativeto ebp & args - ebp
jno regular
arrange tmp, =push =eax
assemble tmp
arrange tmp, =lea =eax,[args]
assemble tmp
arrange tmp, =xchg =eax,[=esp]
assemble tmp
jump next
regular:
arrange tmp, =pushd args
assemble tmp
next:
take args, stack
jyes push
go:
arrange tmp, =call [proc]
assemble tmp
end calminstruction
calminstruction mov? dest*,src*
local tmp
match tmp], src
jyes regular
check src relativeto ebp & src - ebp
jno regular
arrange tmp, =lea dest,[src]
assemble tmp
exit
regular:
arrange tmp, =mov dest,src
assemble tmp
end calminstruction
macro library? definitions&
PE.Imports:
iterate <name,string>, definitions
if ~ name.redundant
dd RVA name.lookup,0,0,RVA name.str,RVA name.address
end if
name.referred = 1
end iterate
dd 0,0,0,0,0
iterate <name,string>, definitions
if ~ name.redundant
name.str db string,0
align 2
end if
end iterate
end macro
macro import? name,definitions&
align 4
if defined name.referred
name.lookup:
iterate <label,string>, definitions
if used label
if string eqtype ''
dd RVA name.label
else
dd 80000000h + string
end if
end if
end iterate
if $ > name.lookup
name.redundant = 0
dd 0
else
name.redundant = 1
end if
name.address:
iterate <label,string>, definitions
if used label
if string eqtype ''
label dd RVA name.label
else
label dd 80000000h + string
end if
end if
end iterate
if ~ name.redundant
dd 0
end if
iterate <label,string>, definitions
if used label & string eqtype ''
name.label dw 0
db string,0
align 2
end if
end iterate
end if
end macro
macro export dllname,exports&
iterate <label,string>, exports
local module,addresses,names,ordinal,count
count = %%
dd 0,0,0,RVA module,1
dd count,count,RVA addresses,RVA names,RVA ordinal
addresses:
repeat count
indx %
dd RVA label
end repeat
names:
repeat count
dd RVA names.name#%
end repeat
ordinal:
repeat count
dw %-1
end repeat
module db dllname,0
repeat count
indx %
names.name#% db string,0
end repeat
local x,y,z,str1,str2,v1,v2
x = count shr 1
while x > 0
y = x
while y < count
z = y
while z-x >= 0
load v1:dword from names+z*4
str1 = ($-(RVA $))+v1
load v2:dword from names+(z-x)*4
str2 = ($-(RVA $))+v2
while v1 > 0
load v1:byte from str1+%-1
load v2:byte from str2+%-1
if v1 <> v2
break
end if
end while
if v1 < v2
load v1:dword from names+z*4
load v2:dword from names+(z-x)*4
store v1:dword at names+(z-x)*4
store v2:dword at names+z*4
load v1:word from ordinal+z*2
load v2:word from ordinal+(z-x)*2
store v1:word at ordinal+(z-x)*2
store v2:word at ordinal+z*2
else
break
end if
z = z-x
end while
y = y+1
end while
x = x shr 1
end while
break
end iterate
end macro
include '../kernel32.inc'

View File

@ -0,0 +1,214 @@
LINE_FEED equ 13,10
system_init:
invoke HeapCreate,0,20000h,0
mov [memory],eax
test eax,eax
jz out_of_memory
invoke GetSystemTime,systemtime
invoke SystemTimeToFileTime,systemtime,filetime
mov ebx,[filetime.dwLowDateTime]
mov eax,[filetime.dwHighDateTime]
sub ebx,116444736000000000 and 0FFFFFFFFh
sbb eax,116444736000000000 shr 32
xor edx,edx
mov ecx,10000000
div ecx
mov dword [timestamp+4],eax
mov eax,ebx
div ecx
mov dword [timestamp],eax
retn
system_shutdown:
cmp [memory],0
je memory_released
invoke HeapDestroy,[memory]
memory_released:
retn
malloc:
malloc_fixed:
malloc_growable:
; in: ecx = requested size
; out: eax - allocated block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
; note:
; use of malloc_fixed hints that block will be kept as is until the end of assembly
; use of malloc_growable hints that block is likely to be resized
invoke HeapAlloc,[memory],0,ecx
test eax,eax
jz out_of_memory
memory_allocated:
push eax
invoke HeapSize,[memory],0,eax
mov ecx,eax
pop eax
cmp ecx,-1
je out_of_memory
retn
realloc:
; in: eax - memory block, ecx = requested size
; out: eax - resized block, ecx = allocated size, on error jumps to out_of_memory (does not return)
; preserves: ebx, esi, edi
invoke HeapReAlloc,[memory],0,eax,ecx
test eax,eax
jnz memory_allocated
jmp out_of_memory
mfree:
; in: eax - memory block
; out: cf set on error
; preserves: ebx, esi, edi
; note: eax may have value 0 or -1, it should be treated as invalid input then
test eax,eax
jz interface_error
cmp eax,-1
je interface_error
invoke HeapFree,[memory],0,eax
test eax,eax
jz interface_error
clc
retn
interface_error:
stc
retn
open:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
create:
; in: edx - path to file
; out: ebx = file handle, cf set on error
; preserves: esi, edi
invoke CreateFile,edx,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0
cmp eax,-1
je interface_error
mov ebx,eax
clc
retn
write:
; in: ebx = file handle, edx - data, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke WriteFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
read:
; in: ebx = file handle, edx - buffer, ecx = number of bytes
; out: cf set on error
; preserves: ebx, esi, edi
push ecx
invoke ReadFile,ebx,edx,ecx,systmp,0
pop ecx
test eax,eax
jz interface_error
cmp ecx,[systmp]
jne interface_error
clc
retn
close:
; in: ebx = file handle
; preserves: ebx, esi, edi
invoke CloseHandle,ebx
retn
lseek:
; in: ebx = file handle, cl = method, edx:eax = offset
; out: edx:eax = new offset from the beginning of file, cf set on error
; preserves: ebx, esi, edi
movzx ecx,cl
mov [systmp],edx
invoke SetFilePointer,ebx,eax,systmp,ecx
cmp eax,-1
jne lseek_ok
invoke GetLastError
test eax,eax
jnz interface_error
not eax
lseek_ok:
mov edx,[systmp]
clc
retn
get_timestamp:
; out: edx:eax = timestamp
; preserves: ebx, ecx, esi, edi
; note: during the passes of a single assembly this function should always return the same value
mov eax,dword [timestamp]
mov edx,dword [timestamp+4]
retn
display_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stdout]
jmp write_string
display_error_string:
; in:
; esi - string
; ecx = string length, zero for ASCIIZ string
; preserves: ebx, esi
push ebx
mov ebx,[stderr]
write_string:
test ebx,ebx
jz hidden_display
test ecx,ecx
jnz write_string_to_stdout
xor al,al
mov edi,esi
or ecx,-1
repne scasb
neg ecx
sub ecx,2
write_string_to_stdout:
mov edx,esi
write_portion_to_stdout:
mov eax,51200
cmp ecx,eax
jbe final_write_to_stdout
sub ecx,eax
add eax,edx
push eax ecx
invoke WriteFile,ebx,edx,51200,systmp,0
pop ecx edx
jmp write_portion_to_stdout
final_write_to_stdout:
invoke WriteFile,ebx,edx,ecx,systmp,0
hidden_display:
pop ebx
retn
get_environment_variable:
; in:
; esi - name
; edi - buffer for value
; ecx = size of buffer
; out:
; eax = length of value
; preserves: ebx, esi, edi
push ecx
invoke GetEnvironmentVariable,esi,edi,ecx
pop ecx
cmp eax,ecx
jae environment_variable_ready
mov byte [edi+eax],0
environment_variable_ready:
inc eax
retn