added fasm2 as well

This commit is contained in:
2024-11-25 00:04:53 -05:00
parent 8a974e9c89
commit dceb330571
165 changed files with 78512 additions and 0 deletions

View File

@ -0,0 +1,54 @@
macro cominvk Object,proc,args&
iterate arg, args
indx 1+%%-%
pushd arg
end iterate
if ~ defined Object#.com.object
err `Object,' is not a COM object'
end if
mov eax,[Object]
push eax
mov eax,[eax]
call [eax+Object.proc]
end macro
macro comcall handle,Interface,proc,args&
iterate arg, args
indx 1+%%-%
pushd arg
end iterate
if ~ defined Interface#.com.interface
err `Interface,' is not a COM interface'
end if
match prefix [addr], :handle
mov eax,handle
push eax
mov eax,[eax]
else
push handle
local _handle
_handle := handle
mov eax,[_handle]
end match
call [eax+Interface.proc]
end macro
macro interface name,methods&
struc name
. dd ?
virtual at 0
iterate method, methods
.method dd ?
end iterate
end virtual
.com.object = name.com.interface
end struc
virtual at 0
iterate method, methods
name.method dd ?
end iterate
define name
name.com.interface = $ shr 2
end virtual
end macro

View File

@ -0,0 +1,51 @@
macro cominvk Object,proc,args&
if ~ defined Object#.com.object
err `Object,' is not a COM object'
end if
macro call dummy
mov rax,[rcx]
Call [rax+Object.proc]
end macro
match any, args
fastcall -,[Object],args
else
fastcall -,[Object]
end match
purge call
end macro
macro comcall handle,Interface,proc,args&
if ~ defined Interface#.com.interface
err `Interface,' is not a COM interface'
end if
macro call dummy
mov rax,[rcx]
Call [rax+Interface.proc]
end macro
match any, args
fastcall -,handle,args
else
fastcall -,handle
end match
purge call
end macro
macro interface name,methods&
struc name
. dq ?
virtual at 0
iterate method, methods
.method dq ?
end iterate
end virtual
.com.object = name.com.interface
end struc
virtual at 0
iterate method, methods
name.method dq ?
end iterate
define name
name.com.interface = $ shr 3
end virtual
end macro

View File

@ -0,0 +1,67 @@
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

View File

@ -0,0 +1,337 @@
define _if _if
define _if..if? _if
define _if..else? _else
define _if..elseif? _elseif
define _if..endif? _endif
define _if..while? _while
define _if..endw? _endw
define _if..repeat? _repeat
define _if..until? _until
calminstruction (cmd) ? &a&
transform cmd,_if
arrange cmd, cmd a
assemble cmd
end calminstruction
macro _if cond
__IF equ :
local endif
__ENDIF equ endif
local else
__ELSE equ else
jcondexpr __ELSE,1,cond
end macro
macro _else
jmp __ENDIF
match _else, __ELSE
_else:
end match
restore __IF
__IF equ
end macro
macro _elseif cond
jmp __ENDIF
match _else, __ELSE
_else:
end match
restore __ELSE
local else
__ELSE equ else
jcondexpr __ELSE,1,cond
end macro
macro _endif
match :_else, __IF __ELSE
_else:
end match
match endif, __ENDIF
endif:
end match
restore __ELSE
restore __ENDIF
restore __IF
end macro
macro _while cond
local while
while:
__WHILE equ while
local endw
__ENDW equ endw
jcondexpr __ENDW,1,cond
end macro
macro _endw
jmp __WHILE
match endw, __ENDW
endw:
end match
restore __ENDW
restore __WHILE
end macro
macro _repeat
local repeat
repeat:
__REPEAT equ repeat
end macro
macro _until cond
jcondexpr __REPEAT,1,cond
restore __REPEAT
end macro
macro newlocal? var
local new
redefine var new
end macro
macro JCONDEXPR?: target,mode,cond
local buffer,current,counter
local neg,conj
local f,t
buffer equ cond
newlocal f
newlocal t
while 1
match ~x, buffer
buffer equ x
neg = (mode) xor 1
else
neg = mode
end match
match (x, buffer
counter = 1
current equ (
buffer equ x
while counter > 0
match p)s, buffer
match (ps, p
counter = counter + 1
current equ current (
buffer equ ps)s
else match pp(ps, p
counter = counter + 1
current equ current pp(
buffer equ ps)s
else
counter = counter - 1
current equ current p
buffer equ )s
end match
else
current equ current buffer
buffer equ
break
end match
end while
else
current equ
end match
match a|b, buffer
match c&d, a
current equ current c
buffer equ &d|b
else
current equ current a
buffer equ |b
end match
else match c&d, buffer
match a|b, c
current equ current a
buffer equ |b&d
else
current equ current c
buffer equ &d
end match
else
current equ current buffer
buffer equ
end match
match , buffer
match (c), current
jcondexpr t,neg,c
else match c, current
jcond t,neg,c
end match
break
else
match |b, buffer
buffer equ b
conj = 0
else match &d, buffer
buffer equ d
conj = 1
else
err 'invalid expression'
end match
if (mode) xor conj
match (c), current
jcondexpr f,neg xor 1,c
else match c, current
jcond f,neg xor 1,c
end match
match t,t
t:
end match
newlocal t
else
match (c), current
jcondexpr t,neg,c
else match c, current
jcond t,neg,c
end match
match f,f
f:
end match
newlocal f
end if
end match
end while
match t,t
label t at target
end match
match f,f
f:
end match
end macro
macro JCOND? target,neg,cond
match =signed? v1>==v2, cond
cmp v1,v2
if neg
jl target
else
jge target
end if
else match =signed? v1<==v2, cond
cmp v1,v2
if neg
jg target
else
jle target
end if
else match v1>==v2, cond
cmp v1,v2
if neg
jb target
else
jae target
end if
else match v1<==v2, cond
cmp v1,v2
if neg
ja target
else
jbe target
end if
else match v1==v2, cond
cmp v1,v2
if neg
jne target
else
je target
end if
else match v1<>v2, cond
cmp v1,v2
if neg
je target
else
jne target
end if
else match =signed? v1>v2, cond
cmp v1,v2
if neg
jle target
else
jg target
end if
else match =signed? v1<v2, cond
cmp v1,v2
if neg
jge target
else
jl target
end if
else match v1>v2, cond
cmp v1,v2
if neg
jbe target
else
ja target
end if
else match v1<v2, cond
cmp v1,v2
if neg
jae target
else
jb target
end if
else match =ZERO=?, cond
if neg
jnz target
else
jz target
end if
else match =CARRY=?, cond
if neg
jnc target
else
jc target
end if
else match =OVERFLOW=?, cond
if neg
jno target
else
jo target
end if
else match =SIGN=?, cond
if neg
jns target
else
js target
end if
else match =PARITY?, cond
if neg
jnp target
else
jp target
end if
else match v, cond
x86.parse_operand@aux v
if @aux.type = 'imm'
if neg
if v = 0
jmp target
end if
else
if v
jmp target
end if
end if
else if @aux.type = 'reg'
test v,v
if neg
jz target
else
jnz target
end if
else
cmp v,0
if neg
je target
else
jne target
end if
end if
end match
end macro

View File

@ -0,0 +1,59 @@
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

View File

@ -0,0 +1,59 @@
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 8
if defined name.referred
name.lookup:
iterate <label,string>, definitions
if used label
if string eqtype ''
dq RVA name.label
else
dq 8000000000000000h + string
end if
end if
end iterate
if $ > name.lookup
name.redundant = 0
dq 0
else
name.redundant = 1
end if
name.address:
iterate <label,string>, definitions
if used label
if string eqtype ''
label dq RVA name.label
else
label dq 8000000000000000h + string
end if
end if
end iterate
if ~ name.redundant
dq 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

View File

@ -0,0 +1,88 @@
; Simple preprocessor for inline macros.
; Example of use:
;
; inlinemacro oddflip(number)
; return = (number) xor 1
; end inlinemacro
;
; db oddflip(3), oddflip(oddflip(0) shl 1)
; Any kind of definition of an expression-class symbol may be used for the return value.
include 'xcalm.inc'
define inlinemacro? inlinemacro?
inlinemacro... = 0
calminstruction inlinemacro?! &declaration&
local name
match name(arguments?), declaration
jyes define
match name= arguments?, declaration
jyes define
match name arguments?, declaration
define:
arrange tmp, =__inline__.name
arrange name, =inlinemacro.name
publish name, tmp
arrange tmp, =struc (=return?) name arguments
assemble tmp
end calminstruction
calminstruction end?.inlinemacro?!
asm end struc
check inlinemacro...
jyes done
compute inlinemacro..., 1
asm inlinemacro?.enable?
done:
end calminstruction
macro inlinemacro?.enable? chain
chain
macro include?! file*, head
include file, inlinemacro.enable head
purge ?, include?
end macro
calminstruction ?! &text&
local head, tail, name, arguments, more, i
init i, 0
match =inlinemacro? more, text
jyes ready
transform text, inlinemacro
jno ready
match =else? more, text
jno preprocess
compute i, i+1
arrange text, =__inline__.?(=else =if 1) =__inline__.?(=__return__.i==1) text =__inline__.?(=end =if) =__inline__.?(=if ~=definite =__return__.i)
preprocess:
match head? =__inline__.name tail?, text
jno ready
match (arguments?) tail?, tail, ()
jyes inline
arrange text, head name tail
jump preprocess
inline:
match ?, name
jyes special
local tmp, return
compute i, i+1
arrange return, =__return__.i
arrange tmp, return =inlinemacro.name arguments
arrange text, head return tail
take text, tmp
jump preprocess
special:
arrange text, head tail
take text, arguments
jump preprocess
ready:
assemble text
take , text
take text, text
jyes preprocess
end calminstruction
end macro

View File

@ -0,0 +1,395 @@
define stdcall? stdcall
macro stdcall?.push_string value&
local continue
if sizeof.TCHAR > 1
local alignment
virtual at $+5
align sizeof.TCHAR
alignment = $-$$
end virtual
db alignment dup 90h
end if
call continue
TCHAR value,0
continue:
end macro
macro stdcall?: proc*,args&
local count
count = 0
iterate arg, args
indx 1+%%-%
match =addr? val, arg
if val relativeto 0 | val relativeto $
push dword val
else
lea edx,[val]
push edx
end if
else match =double? [var], arg
push dword [var+4]
push dword [var]
count = count + 1
else match =double? val, arg
local low,high
virtual at 0
dq val
load low:dword from 0
load high:dword from 4
end virtual
push dword high
push dword low
count = count + 1
else match =invoke? func, arg
invoke func
push eax
else match =cinvoke? func, arg
cinvoke func
push eax
else match =stdcall? func, arg
stdcall func
push eax
else match =ccall? func, arg
ccall func
push eax
else match first=,rest, arg
stdcall?.push_string arg
else match size [var], arg
if size = 4
push arg
else
if size = 1
mov al, arg
else if size = 2
mov ax, arg
else
mov eax, arg
end if
push eax
end if
else match [var], arg
push dword arg
else
if arg eqtype ''
stdcall?.push_string arg
else
push dword arg
end if
end match
count = count + 1
end iterate
pcountcheck proc,count
call proc
end macro
macro ccall?: proc*,args&
local count
count = 0
iterate arg, args
indx 1+%%-%
match =addr? val, arg
if val relativeto 0 | val relativeto $
push dword val
else
lea edx,[val]
push edx
end if
else match =double? [var], arg
push dword [var+4]
push dword [var]
count = count + 1
else match =double? val, arg
local low,high
virtual at 0
dq val
load low:dword from 0
load high:dword from 4
end virtual
push dword high
push dword low
count = count + 1
else match =invoke? func, arg
invoke func
push eax
else match =cinvoke? func, arg
cinvoke func
push eax
else match =stdcall? func, arg
stdcall func
push eax
else match =ccall? func, arg
ccall func
push eax
else match first=,rest, arg
stdcall?.push_string arg
else match size [var], arg
if size = 4
push arg
else
if size = 1
mov al, arg
else if size = 2
mov ax, arg
else
mov eax, arg
end if
push eax
end if
else match [var], arg
push dword arg
else
if arg eqtype ''
stdcall?.push_string arg
else
push dword arg
end if
end match
count = count + 1
end iterate
pcountcheck proc,count
call proc
if count
add esp,count*4
end if
end macro
macro invoke?: proc*,args&
stdcall [proc],args
end macro
macro cinvoke?: proc*,args&
ccall [proc],args
end macro
macro pcountcheck? proc*,args*
end macro
define pcountsuffix %
prologue@proc equ prologuedef
macro prologuedef procname,flag,parmbytes,localbytes,reglist
local loc
loc = (localbytes+3) and (not 3)
parmbase@proc equ ebp+8
localbase@proc equ ebp-loc
if parmbytes | localbytes
push ebp
mov ebp,esp
if localbytes
sub esp,loc
end if
end if
iterate reg, reglist
push reg
end iterate
end macro
epilogue@proc equ epiloguedef
macro epiloguedef procname,flag,parmbytes,localbytes,reglist
iterate reg, reglist
indx %%-%+1
pop reg
end iterate
if parmbytes | localbytes
leave
end if
if flag and 10000b
retn
else
retn parmbytes
end if
end macro
close@proc equ
macro proc? statement&
local _local,params,flag,regs,parmbytes,localbytes,current,tmp,initlocal
macro endp?!
localbytes = current
purge ret?,locals?,endl?,proclocal?
match close:reglist, close@proc,<regs>
close name,flag,parmbytes,localbytes,reglist
end match
end match
end namespace
end if
end match
purge endp?
end macro
match name declaration, statement :
if used name
name:
namespace name
outscope match local?, proclocal
match =stdcall? args :, declaration
define params args
flag = 11b
else match =stdcall? :, declaration
define params
flag = 11b
else match =c? args :, declaration
define params args
flag = 10001b
else match =c? :, declaration
define params
flag = 10001b
else match args :, declaration
define params args
flag = 0
else
define params
flag = 0
end match
define regs
match =uses? list, params
define params list
while 1
match =, tail, params
define params tail
break
else match reg tail, params&
match more&, tail
define params more
else
define params
end match
if % = 1
regs equ reg
else
regs equ regs,reg
end if
else
break
end match
end while
else match =, tail, params
define params tail
end match
match prologue:reglist, prologue@proc:<regs>
prologue name,flags,parmbytes,localbytes,reglist
end match
virtual at parmbase@proc
namespace name
match args, params
iterate arg, args
match argname:type, arg
label argname:type
rb type
else
?arg dd ?
end match
end iterate
end match
parmbytes := $-(parmbase@proc)
match p, pcountsuffix
name#p = parmbytes/4
end match
end namespace
end virtual
macro ret? operand
match any, operand
retn operand
else
match epilogue:reglist, epilogue@proc:<regs>
epilogue name,flag,parmbytes,localbytes,reglist
end match
end match
end macro
current = 0
macro initlocal
local area,pointer,length,value
area::
pointer = localbase@proc+current
length = $@ - (localbase@proc) - current
current = $ - (localbase@proc)
end virtual
while length > 0
if length < 2
load value:byte from area:pointer
mov byte [pointer],value
pointer = pointer + 1
length = length - 1
else if length < 4
load value:word from area:pointer
mov word [pointer],value
pointer = pointer + 2
length = length - 2
else
load value:dword from area:pointer
mov dword [pointer],value
pointer = pointer + 4
length = length - 4
end if
end while
virtual at localbase@proc+current
end macro
macro locals?
virtual at localbase@proc+current
iterate dword, dword,qword
macro dword? value
if value relativeto 0
emit dword: value
else
initlocal
local pointer
pointer := $
end virtual
mov dword [pointer],value
virtual at pointer+4
current = $ - (localbase@proc)
end if
end macro
end iterate
macro ? line&
line
if $ > $@
initlocal
end if
end macro
end macro
macro endl?
purge ?, dword?,qword?
initlocal
end virtual
end macro
macro proclocal? args&
locals
iterate arg, args
match varname[count]:type, arg
?varname dbx type:count dup ?
else match varname:type, arg
?varname dbx type, ?
else match varname[count], arg
?varname rd count
else match varname type, arg
?varname type
else
?arg dd ?
end match
end iterate
endl
end macro
end macro

View File

@ -0,0 +1,491 @@
define fastcall? fastcall
fastcall.r1 equ rcx
fastcall.rd1 equ ecx
fastcall.rw1 equ cx
fastcall.rb1 equ cl
fastcall.rf1 equ xmm0
fastcall.r2 equ rdx
fastcall.rd2 equ edx
fastcall.rw2 equ dx
fastcall.rb2 equ dl
fastcall.rf2 equ xmm1
fastcall.r3 equ r8
fastcall.rd3 equ r8d
fastcall.rw3 equ r8w
fastcall.rb3 equ r8b
fastcall.rf3 equ xmm2
fastcall.r4 equ r9
fastcall.rd4 equ r9d
fastcall.rw4 equ r9w
fastcall.rb4 equ r9b
fastcall.rf4 equ xmm3
fastcall?.frame = -1
macro frame?
local size
define fastcall?.frame_size size
fastcall?.frame =: 0
sub rsp,size
end macro
macro end?.frame?
match size, fastcall?.frame_size
size := fastcall?.frame
add rsp,size
end match
restore fastcall?.frame,fastcall?.frame_size
end macro
macro endf?
end frame
end macro
macro fastcall?.inline_string var
local data,continue
jmp continue
if sizeof.TCHAR > 1
align sizeof.TCHAR,90h
end if
match value, var
data TCHAR value,0
end match
redefine var data
continue:
end macro
macro fastcall?: proc*,args&
local offset,framesize,type,value
if framesize & fastcall?.frame < 0
sub rsp,framesize
end if
offset = 0
local nest,called
called = 0
iterate arg, args
nest = 0
match =invoke? func, arg
nest = %
else match =fastcall? func, arg
nest = %
end match
if nest
if called
mov [rsp+8*(called-1)],rax
end if
frame
arg
end frame
called = nest
end if
end iterate
iterate arg, args
match =float? val, arg
type = 'f'
value reequ val
SSE.parse_operand@src val
else match =addr? val, arg
type = 'a'
value reequ val
x86.parse_operand@src [val]
else match =invoke? func, arg
if called = %
type = 0
value reequ rax
x86.parse_operand@src rax
else
type = 'r'
end if
else match =fastcall? func, arg
if called = %
type = 0
value reequ rax
x86.parse_operand@src rax
else
type = 'r'
end if
else match first=,rest, arg
type = 's'
value reequ arg
else
type = 0
value reequ arg
SSE.parse_operand@src arg
if @src.type = 'imm' & @src.size = 0
if value eqtype ''
type = 's'
end if
end if
end match
if type = 's'
fastcall.inline_string value
type = 'a'
end if
if % < 5
if type = 'f'
if @src.size = 8 | ~ @src.size | @src.type = 'mmreg'
if @src.type = 'imm'
mov rax,value
movq fastcall.rf#%,rax
else
movq fastcall.rf#%,value
end if
else if @src.size = 4
if @src.type = 'imm'
mov eax,value
movd fastcall.rf#%,eax
else
movd fastcall.rf#%,value
end if
else
err 'invalid argument ',`arg
end if
else
if type = 'a'
lea fastcall.r#%,[value]
else
if type = 'r'
@src.size = 8
@src.type = 'mem'
value equ [rsp+8*(%-1)]
end if
if @src.size = 8 | ~ @src.size
if @src.type <> 'reg' | ~ @src.imm eq fastcall.r#%
mov fastcall.r#%,value
end if
else if @src.size = 4
if @src.type <> 'reg' | ~ @src.imm eq fastcall.rd#%
mov fastcall.rd#%,value
end if
else if @src.size = 2
if @src.type <> 'reg' | ~ @src.imm eq fastcall.rw#%
mov fastcall.rw#%,value
end if
else if @src.size = 1
if @src.type <> 'reg' | ~ @src.imm eq fastcall.rb#%
mov fastcall.rb#%,value
end if
else
err 'invalid argument ',`arg
end if
end if
end if
else
if type = 'r'
; already on stack
else if @src.type = 'reg'
mov [rsp+offset],value
else if @src.type = 'mem'
if type = 'a'
lea rax,[value]
mov [rsp+offset],rax
else
if @src.size = 8 | ~ @src.size
mov rax,value
mov [rsp+offset],rax
else if @src.size = 4
mov eax,value
mov [rsp+offset],eax
else if @src.size = 2
mov ax,value
mov [rsp+offset],ax
else if @src.size = 1
mov al,value
mov [rsp+offset],al
else
err 'invalid argument ',`arg
end if
end if
else if @src.type = 'imm'
if @src.size = 8 | ~ @src.size
if (value) relativeto 0 & (value) - 1 shl 64 >= -80000000h & (value) < 1 shl 64
mov rax,(value) - 1 shl 64
mov [rsp+offset],rax
else if (value) relativeto 0 & ( (value) >= 80000000h | (value) < -80000000h )
mov rax,value
mov [rsp+offset],rax
else
mov qword [rsp+offset],value
end if
else if @src.size = 4
mov dword [rsp+offset],value
else if @src.size = 2
mov word [rsp+offset],value
else if @src.size = 1
mov byte [rsp+offset],value
else
err 'invalid argument ',`arg
end if
else if type = 'f' & @src.type = 'mmreg' & @src.size = 16
movq [rsp+offset],value
else
err 'invalid argument ',`arg
end if
end if
offset = offset + 8
end iterate
pcountcheck proc,offset/8
if offset < 20h
offset = 20h
end if
framesize = offset + offset and 8
call proc
if framesize & fastcall?.frame < 0
add rsp,framesize
else if fastcall?.frame >= 0 & framesize > fastcall?.frame
fastcall?.frame = framesize
end if
end macro
macro invoke?: proc*,args&
fastcall [proc],args
end macro
macro cinvoke?: proc*,args&
fastcall [proc],args
end macro
macro pcountcheck? proc*,args*
end macro
define pcountsuffix %
prologue@proc equ prologuedef
macro prologuedef procname,flag,parmbytes,localbytes,reglist
local loc,fill
loc = (localbytes+15) and (not 15)
parmbase@proc equ rbp+16
localbase@proc equ rbp-loc
push rbp
mov rbp,rsp
if loc+fill
sub rsp,loc+fill
end if
match any, reglist
iterate reg, reglist
push reg
if % = %%
fill := 8*(% and 1)
end if
end iterate
else
fill := 0
end match
end macro
epilogue@proc equ epiloguedef
macro epiloguedef procname,flag,parmbytes,localbytes,reglist
iterate reg, reglist
indx %%-%+1
pop reg
end iterate
leave
retn
end macro
close@proc equ
macro proc? statement&
local _local,params,flag,regs,parmbytes,localbytes,current,tmp,initlocal
macro endp?!
localbytes = current
purge ret?,locals?,endl?,proclocal?
match close:reglist, close@proc,<regs>
close name,flag,parmbytes,localbytes,reglist
end match
end match
end namespace
end if
end match
purge endp?
end macro
match name declaration, statement :
if used name
name:
namespace name
outscope match local?, proclocal
match =stdcall? args :, declaration
define params args
flag = 11b
else match =stdcall? :, declaration
define params
flag = 11b
else match =c? args :, declaration
define params args
flag = 10001b
else match =c? :, declaration
define params
flag = 10001b
else match args :, declaration
define params args
flag = 0
else
define params
flag = 0
end match
define regs
match =uses? list, params
define params list
while 1
match =, tail, params
define params tail
break
else match reg tail, params&
match more&, tail
define params more
else
define params
end match
if % = 1
regs equ reg
else
regs equ regs,reg
end if
else
break
end match
end while
else match =, tail, params
define params tail
end match
match prologue:reglist, prologue@proc:<regs>
prologue name,flags,parmbytes,localbytes,reglist
end match
virtual at parmbase@proc
namespace name
match args, params
iterate arg, args
match argname:type, arg
label argname:type
rb type
else
?arg dq ?
end match
end iterate
end match
parmbytes := $-(parmbase@proc)
match p, pcountsuffix
name#p = parmbytes/8
end match
end namespace
end virtual
macro ret? operand
match any, operand
retn operand
else
match epilogue:reglist, epilogue@proc:<regs>
epilogue name,flag,parmbytes,localbytes,reglist
end match
end match
end macro
current = 0
macro initlocal
local area,pointer,length,value
area::
pointer = localbase@proc+current
length = $@ - (localbase@proc) - current
current = $ - (localbase@proc)
end virtual
while length > 0
if length < 2
load value:byte from area:pointer
mov byte [pointer],value
pointer = pointer + 1
length = length - 1
else if length < 4
load value:word from area:pointer
mov word [pointer],value
pointer = pointer + 2
length = length - 2
else if length < 8
load value:dword from area:pointer
mov dword [pointer],value
pointer = pointer + 4
length = length - 4
else
load value:qword from area:pointer
if value < 80000000h | value >= 1 shl 64 - 80000000h
mov qword [pointer],value
pointer = pointer + 8
length = length - 8
else
mov dword [pointer],value and 0FFFFFFFFh
pointer = pointer + 4
length = length - 4
end if
end if
end while
virtual at localbase@proc+current
end macro
macro locals?
virtual at localbase@proc+current
iterate dword, dword,qword
macro dword? value
if value relativeto 0
emit dword: value
else
initlocal
local pointer
pointer := $
end virtual
mov dword [pointer],value
virtual at pointer+4
current = $ - (localbase@proc)
end if
end macro
end iterate
macro ? line&
line
if $ > $@
initlocal
end if
end macro
end macro
macro endl?
purge ?, dword?,qword?
initlocal
end virtual
end macro
macro proclocal? args&
locals
iterate arg, args
match varname[count]:type, arg
?varname dbx type:count dup ?
else match varname:type, arg
?varname dbx type, ?
else match varname[count], arg
?varname rq count
else match varname type, arg
?varname type
else
?arg dq ?
end match
end iterate
endl
end macro
end macro

View File

@ -0,0 +1,314 @@
macro directory definitions&
iterate <type,label>, definitions
root@resource dd 0,%t,0,%% shl 16
local total,current,next
total = %%
current = -1
next = 0
while current < next
current = next
repeat total
indx %
if type = current
dd type,80000000h+label-root@resource
else if type > current & ( next = current | next > type )
next = type
end if
end repeat
end while
break
end iterate
end macro
macro resource dir,definitions&
iterate <id,lang,label>, definitions
dir dd 0,%t,0,%% shl 16
local total,current,next,counter
total = %%
current = -1
next = 0
while current < next
current = next
counter = 0
repeat total
indx %
if id = current
if counter = 0
dd id,80000000h+label.directory-root@resource
end if
counter = counter + 1
label.count = counter
else if id > current & ( next = current | next > id )
next = id
end if
end repeat
end while
current = -1
next = 0
while current < next
current = next
counter = 0
repeat total
indx %
if id = current
if counter = 0
label.directory dd 0,%t,0,label.count shl 16
dd lang,label-root@resource
label.resid = id
else
dd lang,label-root@resource
end if
counter = counter + 1
else if id > current & ( next = current | next > id )
next = id
end if
end repeat
end while
break
end iterate
end macro
macro bitmap label,bitmap_file
local data,size
label dd RVA data,size,0,0
data file bitmap_file:0Eh
size = $ - data
align 4
end macro
macro icon group,definitions&
local data,size,position,header
iterate <label,icon_file>, definitions
virtual at 0
file icon_file:6,16
load size:dword from 8
load position:dword from 12
end virtual
label dd RVA data#%,size,0,0
data#% file icon_file:position,size
if % = %%
align 4
group dd RVA header,6+%%*14,0,0
header dw 0,1,%%
repeat %%
indx %
file icon_file:6,12
dw label.resid
end repeat
align 4
end if
end iterate
end macro
macro cursor group,definitions&
local data,header
iterate <label,cursor_file>, definitions
virtual at 0
file cursor_file:6,16
load label.width:byte from 0
load label.height:byte from 1
load label.size:dword from 8
load label.position:dword from 12
end virtual
label dd RVA data#%,label.size+4,0,0
data#% file cursor_file:10,4
file cursor_file:label.position,label.size
if % = %%
align 4
group dd RVA header,6+%%*14,0,0
header dw 0,2,%%
repeat %%
indx %
dw label.width,label.height,1,0
dd label.size+4
dw label.resid
end repeat
align 4
end if
end iterate
end macro
macro menu label
local data,size
label dd RVA data,size,0,0
data dw 1,4,0,0
local menu_level
menu_level = 1
macro menuitem string,id,resinfo:0,status:0,type:0
dd MFT_STRING or type,status,id
dw resinfo
du string,0
align 4
if resinfo and MFR_END
menu_level = menu_level - 1
end if
if resinfo and MFR_POPUP
menu_level = menu_level + 1
dd 0
end if
if menu_level = 0
size = $ - data
purge menuitem,menuseparator
end if
end macro
macro menuseparator resinfo:0
dd MFT_SEPARATOR,0,0
dw resinfo,0
if resinfo and MFR_END
menu_level = menu_level - 1
end if
if menu_level = 0
size = $ - data
purge menuitem,menuseparator
end if
end macro
end macro
macro dialog label,title,x,y,cx,cy,style,exstyle:0,menu:0,fontname:'MS Sans Serif',fontsize:8
local data,size,items
label dd RVA data,size,0,0
data dd style or DS_SETFONT,exstyle
dw items,x,y,cx,cy
if menu <> 0
dw 0FFFFh
end if
du menu,0,title,0
du fontsize,fontname,0
align 4
local dialog_items_counter
dialog_items_counter = 0
macro dialogitem class,it_title,it_id,it_x,it_y,it_cx,it_cy,it_style,it_exstyle:0
dd it_style or WS_CHILD,it_exstyle
dw it_x,it_y,it_cx,it_cy,it_id
if class eq 'BUTTON'
dw 0FFFFh,80h
else if class eq 'EDIT'
dw 0FFFFh,81h
else if class eq 'STATIC'
dw 0FFFFh,82h
else if class eq 'LISTBOX'
dw 0FFFFh,83h
else if class eq 'SCROLLBAR'
dw 0FFFFh,84h
else if class eq 'COMBOBOX'
dw 0FFFFh,85h
else
du class,0
end if
match any=,any, it_title
du it_title,0
else if it_title eqtype ''
du it_title,0
else
dw 0FFFFh,it_title
end if
dw 0
align 4
dialog_items_counter = dialog_items_counter + 1
end macro
macro enddialog
size = $ - data
items = dialog_items_counter
purge dialogitem,enddialog
end macro
end macro
macro accelerator label,definitions&
local data,size
label dd RVA data,size,0,0
data:
iterate <fvirt,key,cmd>, definitions
if % = %%
dw fvirt or 80h,key
size = %% * 8
else
dw fvirt,key
end if
dd cmd
end iterate
end macro
macro versioninfo label,fileos,filetype:0,filesubtype:0,lang,cp:0,values&
local data,size,vivalue,visize
label dd RVA data,size,0,0
data dw size,visize,0
du 'VS_VERSION_INFO',0,0
vivalue dd 0FEEF04BDh,00010000h
local version,count,shift,char,filever,productver
filever = 0
productver = 0
iterate <name,value>, values
if name eq 'FileVersion' | name eq 'ProductVersion'
virtual at 0
db value
count = $
version = 0
shift = 16
repeat count
load char:byte from %-1
if char='.'
if shift mod 32
shift = shift-16
else
shift = shift+32+16
end if
else
version = (version and not (0FFFFh shl shift)) or ((version shr shift and 0FFFFh)*10+char-'0') shl shift
end if
end repeat
end virtual
if name eq 'FileVersion'
filever = version
else if name eq 'ProductVersion'
productver = version
end if
end if
end iterate
dq filever,productver
dd 0,0,fileos,filetype,filesubtype,0,0
visize = $ - vivalue
local sfi_data,sfi_size
sfi_data dd sfi_size
du 1,'StringFileInfo',0
local str_data,str_size
str_data dd str_size
du 1,'040904E4',0
macro vdata name,value&
local vs_data,vs_size,value_data,value_size
align 4
vs_data dw vs_size,value_size/2
du 1,name,0
align 4
value_data du value,0
value_size = $ - value_data
vs_size = $ - vs_data
end macro
iterate <name,value>, values
vdata name,value
end iterate
purge vdata
align 4
str_size = $ - str_data
sfi_size = $ - sfi_data
local vfi_data,vfi_size,var_data,var_size
vfi_data dd vfi_size
du 1,'VarFileInfo',0,0
var_data dw var_size,4
du 0,'Translation',0,0
dw lang,cp
var_size = $ - var_data
vfi_size = $ - vfi_data
size = $ - data
end macro
macro resdata label
local data,size
label dd RVA data,size,0,0
data = $
macro endres
size = $ - data
align 4
purge endres
end macro
end macro

View File

@ -0,0 +1,456 @@
define struct? struct?
namespace struct?
calminstruction instantiate: instance*, sname*, &values&
local tmp
arrange tmp, =label instance : sname.=__size__
assemble tmp
arrange tmp, =namespace instance
assemble tmp
match , values
jyes values_ready
call struct?.initialize, sname, values
values_ready:
local i
compute i, 1
local field, val, stack
process_statement:
arrange field, sname.=__label#i
transform field
jyes labeled_statement
arrange field,
arrange tmp, sname.=__statement#i
transform tmp
jyes statement_ready
jump finish
labeled_statement:
arrange tmp, sname.=__label#i sname.=__definition#i
transform tmp
arrange val, =__init__.#field
transform val
jyes got_value
arrange val, sname.=__default__.#field
arrange field,
transform val
jno statement_ready
got_value:
arrange tmp, tmp val
statement_ready:
take stack, field
take stack, i
take stack, sname
assemble tmp
take , sname
take sname, stack
take , i
take i, stack
take , field
take field, stack
match , field
jyes next_statement
arrange tmp, sname.=__size__.#field - (=$ - field)
compute tmp, tmp
check tmp = 0
jyes next_statement
check tmp > 0
jyes fill_up
stringify field
err 'value too long to fit in ' bappend field
jump next_statement
fill_up:
arrange tmp, =rb tmp
assemble tmp
next_statement:
compute i, i + 1
jump process_statement
finish:
asm end namespace
end calminstruction
calminstruction initialize sname*, values&
local j, a
compute j, 0
arrange a, sname.=__argument
local tmp, field, val, sub
process_argument:
match field=, values, values, <>
jyes got_argument
arrange field, values
arrange values,
got_argument:
match field:val?, field, <>
jyes labeled_argument
check j < 0
jyes mixed_arguments
compute j, j + 1
arrange val, field
match <val>, val
arrange field, a#j
transform field
jno excess_arguments
match <tmp>, field
jno got_argument_field
take a, tmp
compute tmp, 0
take j, tmp
take values, val
jump process_argument
excess_arguments:
err 'excess arguments'
jump arguments_processed
mixed_arguments:
err 'unsupported mixing of labeled and ordered values'
jump arguments_processed
labeled_argument:
check j > 0
jyes mixed_arguments
compute j, -1
match <val>, val
got_argument_field:
arrange tmp, sname.=__default__.#field
transform tmp
jyes argument_ok
match field.sub, field
jno unknown_field
arrange tmp, sname.=__default__.#field
transform tmp
jno unknown_field
arrange val, sub:val
arrange tmp, =__multi__.#field
transform tmp
jno append_value
arrange val, tmp, val
arrange tmp, =__multi__.#field
append_value:
publish tmp, val
jump argument_ok
unknown_field:
stringify field
arrange tmp, sname
stringify tmp
err tmp bappend ' has no field named ' bappend field
jump next_argument
argument_ok:
arrange tmp, =__init__.#field
publish tmp, val
next_argument:
match , values
jno process_argument
arguments_processed:
take , values
take , j
take , a
take values, values
jyes next_argument
end calminstruction
define pname
define i
define j
define u
define a
calminstruction (&label) collect? &definition&
local sym, default, tmp
match , definition
jyes plain
match :tmp?, definition
jyes ignored
match ==tmp?, definition
jyes ignored
arrange default,
match definition= default, definition
arrange sym, pname.=__definition#i
publish sym:, definition
arrange sym, pname.=__label#i
publish sym:, label
arrange sym, pname.=__default__.#label
publish sym:, default
arrange definition, label definition default
assemble definition
arrange definition, =__size__.#label == =$ - label
assemble definition
match , a
jyes done
compute j, j + 1
arrange sym, a#j
publish sym:, label
done:
exit
ignored:
arrange label, label definition
plain:
assemble label
end calminstruction
calminstruction collect? &statement&
local proto, sym, tmp
check i
jyes in_body
compute u, 0
compute i, 1
compute j, 1
asm virtual at 0
match pname= proto, pname
arrange tmp, =namespace pname
assemble tmp
jno prototype_copied
use_prototype:
arrange a,
arrange tmp, proto.=__statement#i
transform tmp
jno prototype_arguments
arrange sym, pname.=__statement#i
publish sym:, tmp
assemble tmp
compute i, i + 1
jump use_prototype
prototype_arguments:
arrange tmp, proto.=__argument#j
transform tmp
jno prototype_copied
arrange sym, pname.=__argument#j
publish sym:, tmp
compute j, j + 1
jump prototype_arguments
prototype_copied:
compute j, j - 1
arrange a, pname.=__argument
in_body:
match =ends?, statement
jyes close
check u
jno process_definition
check u > 1
jno union_divider_ok
arrange tmp, =__union_divider
arrange sym, pname.=__statement#i
publish sym:, tmp
assemble tmp
compute i, i + 1
arrange a,
union_divider_ok:
compute u, u + 1
process_definition:
match =struct?, statement
jyes open_struct
match =union?, statement
jyes open_union
arrange sym, pname.=__statement#i
publish sym:, statement
assemble statement
compute i, i + 1
exit
open_union:
arrange tmp, =__union_start
arrange sym, pname.=__statement#i
publish sym:, tmp
assemble tmp
compute i, i + 1
arrange tmp, a
take a, tmp
compute tmp, 1
take u, tmp
exit
open_struct:
match , a
jyes unlisted_substruct
compute j, j + 1
arrange sym, a#j
arrange tmp, a#j#=_
take a, tmp
arrange tmp, <a>
publish sym:, tmp
jump begin_substruct
unlisted_substruct:
arrange tmp,
take a, tmp
begin_substruct:
compute tmp, 0
take j, tmp
compute tmp, 0
take u, tmp
exit
close:
check u
jno close_struct
arrange tmp, =__union_end
arrange sym, pname.=__statement#i
publish sym:, tmp
assemble tmp
compute i, i + 1
take , a
take , u
exit
close_struct:
take , a
take , j
take , u
take a, a
jyes done
asm end namespace
arrange sym, pname.=__size__
compute tmp, $
publish sym:, tmp
arrange tmp, #sym
arrange sym, =sizeof.pname
publish sym, tmp
asm end virtual
assemble statement
done:
end calminstruction
end namespace
macro struct? declaration*, attributes
if defined Struct.CheckAlignment & Struct.CheckAlignment
struct?.packed = 0
else
struct?.packed = 1
end if
match =packed?, attributes
struct?.packed = 1
else match any, attributes
err 'unknown attribute ',`any
end match
define struct?.pname declaration
struct?.i = 0
mvstruc ?, struct?.collect?
mvmacro ?, struct?.collect?
end macro
macro ends?
mvmacro struct?.collect?, ?
mvstruc struct?.collect?, ?
match name, struct?.pname
label name: name.__size__ at name.__size__
struct?.check name
local sname
define sname name
calminstruction (instance) name values&
call struct?.instantiate, instance, sname, values
end calminstruction
calminstruction name &values&
local ic, iname
init ic
compute ic, ic + 1
arrange iname, sname#ic
call struct?.instantiate, iname, sname, values
end calminstruction
end match
end macro
macro __union_start
local union
union:
union.i = 0
union.size = 0
union.initialized = 0
macro __union_open
union.i = union.i + 1
if (defined union.init & union.i <> union.init) | (~ defined union.init & union.i > 1)
virtual at union
end if
end macro
macro __union_close
if $@ > union
if union.i > 1
union.init := union.i
end if
if union.initialized
err 'conflicting initialization of union'
else
union.initialized = union.i
end if
end if
if $ - union > union.size
union.size = $ - union
end if
if (defined union.init & union.i <> union.init) | (~ defined union.init & union.i > 1)
end virtual
end if
end macro
macro __union_divider
__union_close
__union_open
end macro
macro __union_end
__union_close
if $ - union < union.size
rb union.size - ($ - union)
end if
purge __union_open,__union_close,__union_divider,__union_end
end macro
__union_open
end macro
calminstruction breakifndef? sym
transform sym
jyes ok
asm break
ok:
end calminstruction
macro struct?.check name
if ~ struct?.packed
local alignment, maxalignment
maxalignment = 1
while 1
breakifndef name.__statement#%
match label, name.__label#%
if defined name.label
local alignment
alignment = 1
if sizeof name.label > 0
alignment = 1 shl (bsf sizeof name.label)
end if
match type, name.__definition#%
if defined type.__alignment
alignment = type.__alignment
end if
end match
if name.label mod alignment > 0
repeat 1, natural: alignment
display 'warning: ',`name,'.',`label,' not aligned to its natural boundary (',`natural,')',13,10
end repeat
else if alignment > maxalignment
maxalignment = alignment
end if
end if
end match
end while
if sizeof name mod maxalignment > 0
repeat 1, size: sizeof name, natural: maxalignment
display 'warning: size of ',`name,' (',`size,') not aligned to its natural boundary (',`natural,')',13,10
end repeat
end if
name.__alignment := maxalignment
end if
end macro