2021-01-21 01:04:41 +01:00
// Copyright Cheat Engine. All Rights Reserved.
( *
replaces {$luacode} / {$ccode} with a call to a safecall routine.
If lua:
This routine then calls a lua function in CE using the ceserver pipe with the saved state.
the lua function wraps the userprovided function with code that sets up the parameters to what the user wishes : "myvarname=RAX somethingelse=RDI"
on return of that lua function the given parameters get written back to the original state, which gets restored on function exit ( This is slightly different from {$ccode} which allows specifying reference of val )
If c:
This routine then calls a c- compiled function . One problem is that the address needs to be known before compilation, so has to be done on the 2 nd pass again
2021-01-24 22:37:53 +01:00
replaces {$c} with nothing, but adds it to the total c- code ( handy for headers, helper functions, libraries, etc.. . )
2021-01-21 01:04:41 +01:00
* )
unit autoassemblercode;
{$mode objfpc} {$H+}
interface
uses
2021-05-20 13:52:49 +02:00
Classes, SysUtils, SymbolListHandler, tcclib;
2021-01-21 01:04:41 +01:00
type
TAutoAssemblerCodePass2Data= record
//luadata not needed
2021-01-24 22:37:53 +01:00
cdata: record
cscript: TStringlist;
2021-01-21 01:04:41 +01:00
address: ptruint;
2021-01-24 22:37:53 +01:00
bytesize: integer ;
usesxmm: boolean ;
references: array of record
name : string ;
address: ptruint;
end ;
symbols: array of record
2021-01-21 01:04:41 +01:00
name : string ;
2023-08-25 08:48:13 +02:00
altname: string ;
2021-01-24 22:37:53 +01:00
address: ptruint;
2021-01-21 01:04:41 +01:00
end ;
2021-01-24 22:37:53 +01:00
linklist: array of record //list of symbolnames that need to be filled in after compilation. Name can be found in referenced, fromname in the symbollist of the compiled program
name : string ;
fromname: string ;
end ;
2021-01-21 01:04:41 +01:00
targetself: boolean ;
2021-05-10 18:26:50 +02:00
symbolPrefix: string ;
2021-05-20 13:52:49 +02:00
nodebug: boolean ;
sourceCodeInfo: TSourceCodeInfo;
2021-05-11 11:04:46 +02:00
{$ifdef windows}
2021-05-10 18:26:50 +02:00
kernelAlloc: boolean ;
2021-05-11 11:04:46 +02:00
{$endif}
2021-01-21 01:04:41 +01:00
end ;
end ;
procedure AutoAssemblerCodePass1( script: TStrings; out dataForPass2: TAutoAssemblerCodePass2Data; syntaxcheckonly: boolean ; targetself: boolean ) ;
2021-01-24 22:37:53 +01:00
procedure AutoAssemblerCodePass2( var dataForPass2: TAutoAssemblerCodePass2Data; symbollist: TSymbolListHandler) ;
2021-01-21 01:04:41 +01:00
implementation
2022-09-22 00:48:23 +02:00
uses {$ifdef windows} windows, {$endif} {$ifdef darwin} macport, macportdefines, math, {$endif}
ProcessHandlerUnit, symbolhandler, luahandler, lua, lauxlib, lualib, StrUtils,
Clipbrd, dialogs, lua_server, Assemblerunit, NewKernelHandler, DBK32functions,
2023-10-20 17:32:15 +02:00
StringHashList, globals, networkInterfaceApi, DebuggerInterfaceAPIWrapper,
GDBServerDebuggerInterface;
2021-01-21 01:04:41 +01:00
type
TAACodeType= ( ctLua, ctC) ;
2021-05-10 18:26:50 +02:00
TLuaCodeParameter= record //also CCode parameters
2021-01-21 01:04:41 +01:00
varname: string ;
contextitem: integer ;
{
ContextItem:
0 : RAX / EAX
1 : RBX / EBX
2 : RCX
3 : RDX
4 : RSI
5 : RDI
6 : RSP
7 : RBP
8 : R8
9 : R9
1 0 : R10
1 1 : R11
1 2 : R12
1 3 : R13
1 4 : R14
1 5 : R15
1 6 .. 3 1 : ^ as float ( bit 4 is 1 ) noted as RAXF, RBXF, RCXF, etc.. .
3 2 .. 4 7 : XMM0.. XMM15 ( bytetables/ bytetablestruct)
4 8 : XMM0. 0 or XMM0. 0 F ( float)
4 9 : XMM0. 1
5 0 : XMM0. 2
5 1 : XMM0. 3
5 2 .. 5 5 : XMM1. *
5 6 .. 5 9 : XMM2. *
6 0 .. 5 3 : XMM3. *
6 4 .. 6 7 : XMM4. *
6 8 .. 7 1 : XMM5. *
7 2 .. 7 5 : XMM6. *
7 6 .. 7 9 : XMM7. *
8 0 .. 8 3 : XMM8. *
8 4 .. 8 7 : XMM9. *
8 8 .. 9 1 : XMM10. *
9 2 .. 9 5 : XMM11. *
9 6 .. 9 9 : XMM12. *
1 0 0 .. 1 0 3 : XMM13. *
1 0 4 .. 1 0 7 : XMM14. *
1 0 8 .. 1 1 1 : XMM15. *
1 1 2 : XMM0. 0 D ( double )
1 1 3 : XMM0. 1 D ( double )
1 1 4 .. 1 1 5 : XMM1. * D
1 1 6 .. 1 1 7 : XMM2. * D
1 1 8 .. 1 1 9 : XMM3. * D
1 2 0 .. 1 2 1 : XMM4. * D
1 2 2 .. 1 2 3 : XMM5. * D
1 2 4 .. 1 2 5 : XMM6. * D
1 2 6 .. 1 2 7 : XMM7. * D
1 2 8 .. 1 2 9 : XMM8. * D
1 3 0 .. 1 3 1 : XMM9. * D
1 3 2 .. 1 3 3 : XMM10. * D
1 3 4 .. 1 3 5 : XMM11. * D
1 3 6 .. 1 3 7 : XMM12. * D
1 3 8 .. 1 3 9 : XMM13. * D
1 4 0 .. 1 4 1 : XMM14. * D
1 4 2 .. 1 4 3 : XMM15. * D
}
end ;
TLuaCodeParams= array of TLuaCodeParameter;
2021-09-22 17:34:44 +02:00
var
//list containing functions tcclib1.c defines.
//If any of these functions are used, compile tcclib1-ce.c into the target process.
//for __m* make
tcclibimportlist: TStringHashList;
2021-09-23 13:32:26 +02:00
{
3 2 - bit only:
__divdi3
__moddi3
__udivdi3
__umoddi3
__ashrdi3
__lshrdi3
__ashldi3
__floatundisf
//32 and 64-bit:
__floatundidf
__floatundixf
__fixunssfdi
__fixsfdi
__fixunsdfdi
__fixdfdi
__fixunsxfdi
__fixxfdi
}
2021-09-22 17:34:44 +02:00
2021-01-21 01:04:41 +01:00
procedure parseLuaCodeParameters( s: string ; var output: TLuaCodeParams) ;
var
i: integer ;
r, r2, r3: TStringArray;
varname, regname: string ;
so: TStringSplitOptions;
o: TLuaCodeParameter;
xmmnr: integer ;
subnr: integer ;
st: string ;
begin
setlength( output, 0 ) ;
r: = s. Split( ' ' ) ;
for i: = 0 to length( r) - 1 do
begin
FillByte( o, sizeof( o) , 0 ) ;
r2: = r[ i] . Split( '=' ) ;
if length( r2) < > 2 then
2021-09-27 09:04:18 +02:00
continue;
2021-01-21 01:04:41 +01:00
varname: = r2[ 0 ] ;
regname: = uppercase( r2[ 1 ] ) ;
o. varname: = varname;
case regname of
'EAX' , 'RAX' : o. contextitem: = 0 ;
'EBX' , 'RBX' : o. contextitem: = 1 ;
'ECX' , 'RCX' : o. contextitem: = 2 ;
'EDX' , 'RDX' : o. contextitem: = 3 ;
'ESI' , 'RSI' : o. contextitem: = 4 ;
'EDI' , 'RDI' : o. contextitem: = 5 ;
'ESP' , 'RSP' : o. contextitem: = 6 ;
'EBP' , 'RBP' : o. contextitem: = 7 ;
'R8' : o. contextItem: = 8 ;
'R9' : o. contextItem: = 9 ;
'R10' : o. contextItem: = 1 0 ;
'R11' : o. contextItem: = 1 1 ;
'R12' : o. contextItem: = 1 2 ;
'R13' : o. contextItem: = 1 3 ;
'R14' : o. contextItem: = 1 4 ;
'R15' : o. contextItem: = 1 5 ;
'EAXF' , 'RAXF' : o. contextitem: = 1 6 ;
'EBXF' , 'RBXF' : o. contextitem: = 1 7 ;
'ECXF' , 'RCXF' : o. contextitem: = 1 8 ;
'EDXF' , 'RDXF' : o. contextitem: = 1 9 ;
'ESIF' , 'RSIF' : o. contextitem: = 2 0 ;
'EDIF' , 'RDIF' : o. contextitem: = 2 1 ;
'EBPF' , 'RBPF' : o. contextitem: = 2 2 ;
'ESPF' , 'RSPF' : o. contextitem: = 2 3 ;
'R8F' : o. contextItem: = 2 4 ;
'R9F' : o. contextItem: = 2 5 ;
'R10F' : o. contextItem: = 2 6 ;
'R11F' : o. contextItem: = 2 7 ;
'R12F' : o. contextItem: = 2 8 ;
'R13F' : o. contextItem: = 2 9 ;
'R14F' : o. contextItem: = 3 0 ;
'R15F' : o. contextItem: = 3 1 ;
else
begin
2021-08-30 12:53:57 +02:00
if ( length( regname) > = 4 ) and regname. StartsWith( 'XMM' ) then
2021-01-21 01:04:41 +01:00
begin
if regname. Contains( '.' ) = false then
begin
//xmm bytetable
2021-08-30 12:53:57 +02:00
if regname[ 4 ] = '-' then
xmmnr: = strtoint( regname. Substring( 4 ) ) //XMM-x
else
xmmnr: = strtoint( regname. Substring( 3 ) ) ; //except on invalid data. That's ok
2021-01-21 01:04:41 +01:00
o. contextItem: = 3 2 + xmmnr;
end
else
begin
r3: = regname. Split( '.' ) ;
if length( r3) < > 2 then raise exception. create( 'Invalid xmm register format (Invalid dot usage)' ) ;
2021-08-30 12:53:57 +02:00
if regname[ 4 ] = '-' then
xmmnr: = strtoint( r3[ 0 ] . Substring( 4 ) ) //XMM-x.yyyyyyz
else
xmmnr: = strtoint( r3[ 0 ] . Substring( 3 ) ) ;
2021-01-21 01:04:41 +01:00
if ( length( r3[ 1 ] ) > 2 ) or ( length( r3[ 1 ] ) = 0 ) then raise exception. create( 'Invalid xmm register format' ) ;
if ( length( r3[ 1 ] ) = 2 ) and ( not ( uppercase( r3[ 1 ] ) [ 2 ] in [ 'D' , 'F' ] ) ) then exception. create( 'Invalid xmm register format (Not F or D)' ) ;
subnr: = strtoint( r3[ 1 ] [ 1 ] ) ;
if ( length( r3[ 1 ] ) = 2 ) and ( uppercase( r3[ 1 ] [ 2 ] ) = 'D' ) then
o. contextItem: = 1 1 2 + xmmnr* 2 + subnr //XMM*.*D (double)
else
o. contextItem: = 4 8 + xmmnr* 4 + subnr; //XMM*.*F or //XMM*.*
end ;
end ;
end ;
end ;
setlength( output, length( output) + 1 ) ;
output[ length( output) - 1 ] : = o;
end ;
end ;
function AddSafeCallStub( script: TStrings; functionname: string ; targetself: boolean ) : string ; //a function that can be called from any stack alignment
begin
2021-01-24 22:37:53 +01:00
if functionname[ 1 ] = '[' then
result : = 'ceinternal_autofree_safecallstub_for_' + copy( functionname, 2 , length( functionname) - 2 )
else
result : = 'ceinternal_autofree_safecallstub_for_' + functionname;
2021-01-21 01:04:41 +01:00
script. add( '' ) ;
2021-01-24 22:37:53 +01:00
script. insert( 0 , 'alloc(' + result + ',512)' ) ; //Let's place bets how many people are going to remark that this is what breaks their code and not because they didn't allocate enough memory properly...
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
script. add( result + ':' ) ;
2021-01-21 01:04:41 +01:00
if processhandler. is64Bit{$ifdef cpu64} or targetself{$endif} then
begin
script. add( 'pushfq //save flags' ) ;
script. add( 'push rax' ) ;
script. add( 'mov rax,rsp' ) ;
script. add( 'and rsp,fffffffffffffff0 //align stack' ) ;
script. add( 'sub rsp,2a0 //allocate local space for scratchspace, the registers, and sse registers. And keep alignment' ) ;
script. add( '//store state' ) ;
script. add( 'fxsave qword [rsp+20]' ) ;
script. add( 'mov [rsp+220],rbx' ) ;
script. add( 'mov [rsp+228],rcx' ) ;
script. add( 'mov [rsp+230],rdx' ) ;
script. add( 'mov [rsp+238],rsi' ) ;
script. add( 'mov [rsp+240],rdi' ) ;
script. add( 'mov [rsp+248],rax //rsp' ) ;
script. add( 'mov [rsp+250],rbp' ) ;
script. add( 'mov [rsp+258],r8' ) ;
script. add( 'mov [rsp+260],r9' ) ;
script. add( 'mov [rsp+268],r10' ) ;
script. add( 'mov [rsp+270],r11' ) ;
script. add( 'mov [rsp+278],r12' ) ;
script. add( 'mov [rsp+280],r13' ) ;
script. add( 'mov [rsp+288],r14' ) ;
script. add( 'mov [rsp+290],r15' ) ;
script. add( '//[rsp+248]+0=original rax' ) ;
script. add( '//[rsp+248]+8=original flags' ) ;
script. add( '//call lua function' ) ;
script. add( 'lea rcx,[rsp+20] //pointer to the saved state ([rcx+248-20]+0=rax [rcx+248-20]+0=flags)' ) ;
script. add( 'call ' + functionname) ;
script. add( '//restore registers (could have been changed by the function on purpose)' ) ;
script. add( 'mov r15,[rsp+290]' ) ;
script. add( 'mov r14,[rsp+288]' ) ;
script. add( 'mov r13,[rsp+280]' ) ;
script. add( 'mov r12,[rsp+278]' ) ;
script. add( 'mov r11,[rsp+270]' ) ;
script. add( 'mov r10,[rsp+268]' ) ;
script. add( 'mov r9,[rsp+260]' ) ;
script. add( 'mov r8,[rsp+258]' ) ;
script. add( 'mov rbp,[rsp+250]' ) ;
script. add( 'mov rdi,[rsp+240]' ) ;
script. add( 'mov rsi,[rsp+238]' ) ;
script. add( 'mov rdx,[rsp+230]' ) ;
script. add( 'mov rcx,[rsp+228]' ) ;
script. add( 'mov rbx,[rsp+220]' ) ;
script. add( 'fxrstor qword [rsp+20]' ) ;
script. add( 'mov rsp,[rsp+248] //restore rsp' ) ;
script. add( 'pop rax' ) ;
script. add( 'popfq' ) ;
script. add( 'ret' ) ;
2021-01-22 14:11:00 +01:00
end
else
begin
script. add( 'pushfd //save flags' ) ;
script. add( 'push eax' ) ;
script. add( 'mov eax,esp' ) ;
script. add( 'and esp,fffffff0 //align stack' ) ;
script. add( 'sub esp,220 //allocate local space for scratchspace, the registers, and sse registers. And keep alignment' ) ;
script. add( '//store state' ) ;
script. add( 'fxsave [esp]' ) ;
script. add( 'mov [esp+200],ebx' ) ;
script. add( 'mov [esp+204],ecx' ) ;
script. add( 'mov [esp+208],edx' ) ;
script. add( 'mov [esp+20c],esi' ) ;
script. add( 'mov [esp+210],edi' ) ;
script. add( 'mov [esp+214],eax //rsp' ) ;
script. add( 'mov [esp+218],ebp' ) ;
script. add( '//[esp+214]+0=original eax' ) ;
script. add( '//[esp+214]+4=original eflags' ) ;
script. add( '//call lua function' ) ;
script. add( 'mov eax,esp' ) ; //just to be safe
script. add( 'push eax' ) ;
script. add( 'call ' + functionname) ;
script. add( 'add esp,4' ) ;
script. add( '//restore registers (could have been changed by the function on purpose)' ) ;
script. add( 'mov ebp,[esp+218]' ) ;
script. add( 'mov edi,[rsp+210]' ) ;
script. add( 'mov esi,[rsp+20c]' ) ;
script. add( 'mov edx,[rsp+208]' ) ;
script. add( 'mov ecx,[rsp+204]' ) ;
script. add( 'mov ebx,[rsp+200]' ) ;
script. add( 'fxrstor [rsp]' ) ;
script. add( 'mov esp,[rsp+214] //restore rsp' ) ;
script. add( 'pop eax' ) ;
script. add( 'popfd' ) ;
script. add( 'ret' ) ;
2021-01-21 01:04:41 +01:00
end ;
end ;
2021-01-25 22:28:37 +01:00
procedure AutoAssemblerCCodePass2( var dataForPass2: TAutoAssemblerCodePass2Data; symbollist: TSymbolListHandler) ;
2021-01-21 01:04:41 +01:00
//right after the allocs have been done
var
secondarylist, errorlog: tstringlist;
2021-01-24 22:37:53 +01:00
i, j, k: integer ;
2021-01-21 01:04:41 +01:00
bytes: tmemorystream;
jmpbytes, nopfiller: array of byte ;
2021-01-24 22:37:53 +01:00
a, newAddress: ptruint;
syminfo, nextsyminfo: PCESymbolInfo;
2021-01-21 01:04:41 +01:00
bw: size_t;
2021-01-24 22:37:53 +01:00
psize: integer ;
2021-01-21 01:04:41 +01:00
phandle: THandle;
2021-01-22 14:11:00 +01:00
_tcc: TTCC;
2022-08-31 11:29:55 +02:00
s, s2: string ;
2021-01-22 14:11:00 +01:00
2021-05-10 18:26:50 +02:00
tempsymbollist: TStringlist;
2022-06-01 13:10:34 +02:00
oldprotection: dword;
tccregions: TTCCRegionList;
2022-09-22 00:48:23 +02:00
2022-09-29 11:59:17 +02:00
writesuccess: boolean ;
writesuccess2: boolean ;
2023-08-25 08:48:13 +02:00
temps: string ;
2022-09-29 11:59:17 +02:00
2021-01-24 22:37:53 +01:00
begin
2021-01-21 01:04:41 +01:00
secondarylist: = TStringList. create;
bytes: = tmemorystream. create;
2021-01-24 22:37:53 +01:00
2021-05-10 18:26:50 +02:00
tempsymbollist: = tstringlist. create;
2021-01-24 22:37:53 +01:00
2021-01-21 01:04:41 +01:00
errorlog: = tstringlist. create;
2022-06-01 13:10:34 +02:00
tccregions: = TTCCRegionList. Create;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
dataForPass2. cdata. address: = align( dataForPass2. cdata. address, 1 6 ) ;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
try
if dataForPass2. cdata. targetself then
2021-01-21 01:04:41 +01:00
begin
2021-01-24 22:37:53 +01:00
_tcc: = tccself;
phandle: = GetCurrentProcess;
{$ifdef cpu64}
psize: = 8 ;
{$else}
psize: = 4 ;
{$endif}
end
else
begin
phandle: = processhandle;
2022-09-27 16:31:24 +02:00
{$ifdef windows}
2022-09-22 00:48:23 +02:00
if getConnection< > nil then
_tcc: = tcc_linux
else
2022-09-27 16:31:24 +02:00
{$endif}
2021-01-24 22:37:53 +01:00
_tcc: = tcc;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
psize: = processhandler. pointersize;
end ;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
for i: = 0 to length( dataForPass2. cdata. references) - 1 do
secondarylist. AddObject( dataForPass2. cdata. references[ i] . name , tobject( dataForPass2. cdata. references[ i] . address) ) ;
2021-01-21 01:04:41 +01:00
2021-05-10 18:26:50 +02:00
2021-05-20 13:52:49 +02:00
if dataForPass2. cdata. nodebug= false then
dataForPass2. cdata. sourceCodeInfo: = TSourceCodeInfo. create;
2021-05-10 18:26:50 +02:00
2021-05-20 13:52:49 +02:00
2021-11-27 12:27:21 +01:00
2022-06-01 13:10:34 +02:00
2022-09-22 00:48:23 +02:00
if _tcc. compileScript( dataForPass2. cdata. cscript. Text , dataForPass2. cdata. address, bytes, tempsymbollist, tccregions, dataForPass2. cdata. sourceCodeInfo, errorlog, secondarylist, dataForPass2. cdata. targetself ) then
2021-01-24 22:37:53 +01:00
begin
if bytes. Size> dataForPass2. cdata. bytesize then
2021-01-21 01:04:41 +01:00
begin
2022-09-22 00:48:23 +02:00
tccregions. Clear;
2021-01-24 22:37:53 +01:00
//this will be a slight memoryleak but whatever
//allocate 4x the amount of memory needed
2021-05-11 11:04:46 +02:00
{$ifdef windows}
2021-05-10 18:26:50 +02:00
if dataForPass2. cdata. kernelAlloc then
newAddress: = ptruint( KernelAlloc( 4 * bytes. size) )
else
2021-05-11 11:04:46 +02:00
{$endif}
2022-06-01 13:10:34 +02:00
begin
if SystemSupportsWritableExecutableMemory then
newAddress: = ptruint( VirtualAllocEx( phandle, nil , 4 * bytes. size, mem_reserve or mem_commit, PAGE_EXECUTE_READWRITE) )
else
newAddress: = ptruint( VirtualAllocEx( phandle, nil , bytes. size, mem_reserve or mem_commit, PAGE_READWRITE) ) ; //these systems already waste memory as is so no *4
end ;
2021-05-10 18:26:50 +02:00
2021-01-24 22:37:53 +01:00
if newAddress< > 0 then
begin
dataForPass2. cdata. address: = newAddress;
dataForPass2. cdata. bytesize: = 4 * bytes. size;
//try again
2021-05-10 18:26:50 +02:00
tempsymbollist. clear;
2021-01-24 22:37:53 +01:00
bytes. clear;
secondarylist. Clear;
errorlog. clear;
2022-06-01 13:10:34 +02:00
if _tcc. compileScript( dataForPass2. cdata. cscript. text , dataForPass2. cdata. address, bytes, tempsymbollist, tccregions, dataForPass2. cdata. sourceCodeInfo, errorlog, secondarylist, dataForPass2. cdata. targetself ) = false then
2021-01-24 22:37:53 +01:00
begin
//wtf? something really screwed up here
2021-05-11 11:04:46 +02:00
{$ifdef windows}
2021-05-10 18:26:50 +02:00
if dataForPass2. cdata. kernelAlloc then
KernelFree( newAddress)
else
2021-05-11 11:04:46 +02:00
{$endif}
2021-05-10 18:26:50 +02:00
VirtualFreeEx( phandle, pointer( newAddress) , 0 , MEM_FREE) ;
2021-01-24 22:37:53 +01:00
raise exception. create( '3rd time failure of c-code' ) ;
end ;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
if bytes. Size> dataForPass2. cdata. bytesize then
2021-01-21 01:04:41 +01:00
begin
2021-05-11 11:04:46 +02:00
{$ifdef windows}
2021-05-10 18:26:50 +02:00
if dataForPass2. cdata. kernelAlloc then
KernelFree( newAddress)
else
2021-05-11 11:04:46 +02:00
{$endif}
2021-05-10 18:26:50 +02:00
VirtualFreeEx( phandle, pointer( newAddress) , 0 , MEM_FREE) ;
2021-01-24 22:37:53 +01:00
raise exception. create( '(Unexplained and unmitigated code growth)' ) ;
end ;
end
else
raise exception. create( 'Failure allocating memory for the C-code' ) ;
end ;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
//still here so compilation is within the given parameters
2021-01-21 01:04:41 +01:00
2022-09-29 11:59:17 +02:00
if not SystemSupportsWritableExecutableMemory then //could have been made execute readonly earlier, undo that here
virtualprotectex( processhandle, pointer( dataforpass2. cdata. address) , bytes. size, PAGE_READWRITE, oldprotection) ;
OutputDebugString( 'Writing c-code to ' + dataforpass2. cdata. address. ToHexString+ ' ( ' + bytes. size. ToString+ ' bytes )' ) ;
2023-10-20 17:32:15 +02:00
if ( CurrentDebuggerInterface is TGDBServerDebuggerInterface) and GDBWriteProcessMemoryCodeOnly then
writesuccess: = TGDBServerDebuggerInterface( CurrentDebuggerInterface) . writeBytes( dataforpass2. cdata. address, bytes. memory, bytes. size)
else
writesuccess: = writeProcessMemory( phandle, pointer( dataforpass2. cdata. address) , bytes. memory, bytes. size, bw) ;
2022-09-29 11:59:17 +02:00
{$ifdef darwin}
if ( writesuccess) then
2022-06-01 13:10:34 +02:00
begin
2022-09-29 11:59:17 +02:00
outputdebugstring( 'success. Wrote:' ) ;
s: = '' ;
for i: = 0 to bytes. size- 1 do
begin
s: = s+ pbyte( bytes. memory) [ i] . ToHexString( 2 ) + ' ' ;
end ;
outputdebugstring( s) ;
2022-06-01 13:10:34 +02:00
end ;
2022-09-29 11:59:17 +02:00
{$endif}
2022-06-01 13:10:34 +02:00
2021-01-24 22:37:53 +01:00
//fill in links
for i: = 0 to length( dataForPass2. cdata. linklist) - 1 do
begin
j: = secondarylist. IndexOf( dataforpass2. cdata. linklist[ i] . name ) ;
2022-08-31 11:29:55 +02:00
if j= - 1 then
begin
raise exception. create( 'Failure to link ' + dataForPass2. cdata. linklist[ i] . fromname+ ' due to missing reference' ) ;
end ;
2021-01-24 22:37:53 +01:00
2021-05-10 18:26:50 +02:00
k: = tempsymbollist. IndexOf( dataForPass2. cdata. linklist[ i] . fromname) ;
2022-08-31 11:29:55 +02:00
if k= - 1 then
begin
raise exception. create( 'Failure to link ' + dataForPass2. cdata. linklist[ i] . fromname+ ' due to it missing in the c-code' ) ;
end ;
2021-01-21 01:04:41 +01:00
2021-05-10 18:26:50 +02:00
a: = ptruint( tempsymbollist. Objects[ k] ) ;
2023-10-20 17:32:15 +02:00
if ( CurrentDebuggerInterface is TGDBServerDebuggerInterface) and GDBWriteProcessMemoryCodeOnly then
writesuccess2: = TGDBServerDebuggerInterface( CurrentDebuggerInterface) . writeBytes( dataForPass2. cdata. references[ j] . address, @ a, psize)
else
writesuccess2: = writeProcessMemory( phandle, pointer( dataForPass2. cdata. references[ j] . address) , @ a, psize, bw) ;
2021-01-24 22:37:53 +01:00
end ;
2021-01-21 01:04:41 +01:00
2023-08-25 08:48:13 +02:00
//stdcall symbols: (32-bit)
if processhandler. is64Bit= false then //unlikely nowadays, but check anyhow
begin
//could be using stdcall function names (_symbolname@#)
for i: = 0 to tempsymbollist. count- 1 do
begin
if tempsymbollist[ i] . StartsWith( '_' ) and
( tempsymbollist[ i] [ length( tempsymbollist[ i] ) ] in [ '0' .. '9' ] ) and
tempsymbollist[ i] . Contains( '@' ) then
begin
j: = tempsymbollist[ i] . IndexOf( '@' ) ;
temps: = tempsymbollist[ i] . Substring( j+ 1 ) ;
if TryStrToInt( temps, k) then
begin
//it is a _symbolname@###
temps: = tempsymbollist[ i] . Substring( 1 , j- 1 ) ;
tempsymbollist. AddObject( temps, tempsymbollist. Objects[ i] ) ;
end ;
end ;
end ;
end ;
2021-05-10 18:26:50 +02:00
2021-01-24 22:37:53 +01:00
for i: = 0 to length( dataForPass2. cdata. symbols) - 1 do
begin
2021-05-10 18:26:50 +02:00
j: = tempsymbollist. IndexOf( dataForPass2. cdata. symbols[ i] . name ) ;
if j< > - 1 then
dataforpass2. cdata. symbols[ i] . address: = ptruint( tempsymbollist. Objects[ j] )
else
begin
//not found. prefixed ?
if dataForPass2. cdata. symbolPrefix< > '' then
begin
s: = dataForPass2. cdata. symbols[ i] . name ;
if s. StartsWith( dataForPass2. cdata. symbolPrefix+ '.' ) then
begin
s: = copy( s, length( dataForPass2. cdata. symbolPrefix) + 2 ) ;
j: = tempsymbollist. IndexOf( s) ;
if j< > - 1 then
dataforpass2. cdata. symbols[ i] . address: = ptruint( tempsymbollist. Objects[ j] )
end ;
end ;
end ;
2021-01-24 22:37:53 +01:00
end ;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
if symbollist< > nil then //caller wants the list
begin
2021-05-10 18:26:50 +02:00
for i: = 0 to tempsymbollist. count- 1 do
2021-01-24 22:37:53 +01:00
begin
2021-05-10 18:26:50 +02:00
s: = tempsymbollist[ i] ;
if s. StartsWith( 'ceinternal_autofree_cfunction' ) then continue; //strip the ceinternal_autofree_cfunction
2021-01-21 01:04:41 +01:00
2021-05-10 18:26:50 +02:00
if dataForPass2. cdata. symbolPrefix< > '' then
begin
symbollist. AddSymbol( '' , dataForPass2. cdata. symbolPrefix+ '.' + tempsymbollist[ i] , ptruint( tempsymbollist. Objects[ i] ) , 1 ) ;
symbollist. AddSymbol( '' , tempsymbollist[ i] , ptruint( tempsymbollist. Objects[ i] ) , 1 , true ) ;
end
else
symbollist. AddSymbol( '' , tempsymbollist[ i] , ptruint( tempsymbollist. Objects[ i] ) , 1 ) ;
2021-01-24 22:37:53 +01:00
end ;
end ;
2022-09-29 11:59:17 +02:00
if not SystemSupportsWritableExecutableMemory then
begin
//apply protections
for i: = 0 to tccregions. Count- 1 do
virtualprotectex( processhandle, pointer( tccregions[ i] . address) , tccregions[ i] . size, tccregions[ i] . protection, oldprotection) ;
end ;
if not writesuccess then
raise exception. create( 'Failure writing the generated c-code to memory' ) ;
if not writesuccess2 then
raise exception. create( 'Failure writing referenced addresses' ) ;
2021-02-17 23:32:01 +01:00
end
else
begin
raise Exception. Create( 'ccode section compilation failed:' + errorlog. text ) ;
2021-01-21 01:04:41 +01:00
end ;
2021-01-24 22:37:53 +01:00
2021-01-21 01:04:41 +01:00
finally
freeandnil( errorlog) ;
2021-01-24 22:37:53 +01:00
2021-01-21 01:04:41 +01:00
freeandnil( bytes) ;
freeandnil( secondarylist) ;
2021-01-24 22:37:53 +01:00
2021-01-25 22:28:37 +01:00
freeandnil( dataForPass2. cdata. cscript) ;
2021-05-10 18:26:50 +02:00
freeandnil( tempsymbollist) ;
2022-06-01 13:10:34 +02:00
freeandnil( tccregions) ;
2021-01-24 22:37:53 +01:00
end ;
end ;
2021-05-10 18:26:50 +02:00
procedure ParseCBlockSpecificParameters( s: string ; var dataForPass2: TAutoAssemblerCodePass2Data) ;
var
i, j: integer ;
params: array of string ;
us: string ;
begin
params: = s. Split( [ ' ' , ',' ] ) ;
for i: = 0 to length( params) - 1 do
begin
us: = uppercase( params[ i] ) ;
2021-05-11 11:04:46 +02:00
{$ifdef windows}
2021-05-10 18:26:50 +02:00
if ( us= 'KALLOC' ) or ( us= 'KERNELMODE' ) or ( us= 'KERNEL' ) then
DataForPass2. cdata. kernelAlloc: = true ;
2021-05-11 11:04:46 +02:00
{$endif}
2021-05-10 18:26:50 +02:00
2021-05-20 13:52:49 +02:00
if ( us= 'NODEBUG' ) then
DataForPass2. cdata. nodebug: = true ;
2021-05-10 18:26:50 +02:00
if copy( us, 1 , 7 ) = 'PREFIX=' then
DataForPass2. cdata. symbolPrefix: = copy( params[ i] , 8 ) ;
end ;
end ;
2021-01-24 22:37:53 +01:00
procedure AutoAssemblerCBlockPass1( Script: TStrings; var i: integer ; var dataForPass2: TAutoAssemblerCodePass2Data) ;
//just copy the lines from script to cscript
2021-05-10 18:26:50 +02:00
var
s: string ;
2021-01-24 22:37:53 +01:00
begin
if dataForPass2. cdata. cscript= nil then
dataForPass2. cdata. cscript: = tstringlist. create;
dataForPass2. cdata. cscript. add( '//{$C} block at line ' + ptruint( script. Objects[ i] ) . ToString) ; ;
2021-05-10 18:26:50 +02:00
s: = trim( script[ i] ) ;
s: = copy( s, 5 , length( s) - 5 ) ;
ParseCBlockSpecificParameters( s, dataForPass2) ;
2021-01-24 22:37:53 +01:00
script. delete( i) ; //remove the {$C} line
while i< script. Count- 1 do
begin
if uppercase( script[ i] ) = '{$ASM}' then
begin
//finished
script. delete( i) ;
dataForPass2. cdata. cscript. add( '' ) ; //just a seperator to make debugging easier
exit;
end ;
dataForPass2. cdata. cscript. AddObject( script[ i] , script. Objects[ i] ) ;
script. Delete( i) ;
2021-01-21 01:04:41 +01:00
end ;
end ;
2021-01-24 22:37:53 +01:00
procedure AutoAssemblerCCodePass1( script: TStrings; parameters: TLuaCodeParams; var i: integer ; var dataForPass2: TAutoAssemblerCodePass2Data; syntaxcheckonly: boolean ; targetself: boolean ) ;
2021-01-21 01:04:41 +01:00
var
j, k: integer ;
2021-05-26 15:22:15 +02:00
tst: ptruint;
2021-01-21 01:04:41 +01:00
s: string ;
endpos, scriptstart, scriptend: integer ;
scriptstartlinenr: integer ;
stubcounter: integer = 0 ;
cscript, imports, errorlog: tstringlist;
functionname: string ;
refnr: integer ;
usesXMMType: boolean = false ;
ms: TMemorystream;
bytesizeneeded: integer ;
2021-01-22 14:11:00 +01:00
2021-01-21 01:04:41 +01:00
begin
2022-01-12 00:37:46 +01:00
2021-05-10 18:26:50 +02:00
s: = trim( script[ i] ) ;
s: = copy( s, 9 , length( s) - 9 ) ;
ParseCBlockSpecificParameters( s, dataForPass2) ;
2021-01-24 22:37:53 +01:00
if dataForPass2. cdata. cscript= nil then
dataForPass2. cdata. cscript: = tstringlist. create;
2021-01-22 14:11:00 +01:00
2021-01-21 01:04:41 +01:00
scriptstartlinenr: = ptruint( script. Objects[ i] ) ;
scriptstart: = i;
j: = i+ 1 ;
while j< script. Count- 1 do
begin
if uppercase( script[ j] ) = '{$ASM}' then
break;
inc( j) ;
end ;
scriptend: = j;
2021-01-24 22:37:53 +01:00
cscript: = dataForPass2. cdata. cscript; //shortens the code
2021-01-21 01:04:41 +01:00
functionname: = 'ceinternal_autofree_cfunction_at_line' + inttostr( ptruint( script. objects[ scriptstart] ) ) ;
cscript. add( 'void ' + functionname+ '(void *parameters)' ) ;
cscript. add( '{' ) ;
2021-05-26 15:22:15 +02:00
cscript. add( ' //get the values from the parameter pointer' ) ;
2021-01-21 01:04:41 +01:00
//load the values from parameters pointer
2021-01-22 14:11:00 +01:00
if processhandler. is64Bit {$ifdef cpu64} or targetself{$endif} then
2021-01-21 01:04:41 +01:00
begin
2021-01-22 14:11:00 +01:00
for j: = 0 to length( parameters) - 1 do
begin
case parameters[ j] . contextitem of
2021-05-26 15:22:15 +02:00
0 : s: = 'unsigned long long ' + parameters[ j] . varname+ '=*(unsigned long long *)*(unsigned long long *)((unsigned long long)parameters+0x228);' ; //RAX
2021-11-14 21:14:26 +01:00
1 .. 5 , 7 .. 1 5 : s: = 'unsigned long long ' + parameters[ j] . varname+ '=*(unsigned long long*)((unsigned long long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 8 , 1 ) + ');' ; //RBX..R15
2022-01-12 00:37:46 +01:00
6 : s: = 'unsigned long long ' + parameters[ j] . varname+ '=*(unsigned long long*)((unsigned long long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 8 , 1 ) + ')+24;' ; //RSP
2021-05-26 15:22:15 +02:00
1 6 : s: = 'float ' + parameters[ j] . varname+ '=*(float *)((unsigned long long)parameters+0x228);' ;
2022-02-08 23:12:58 +01:00
1 7 .. 3 1 : s: = 'float ' + parameters[ j] . varname+ '=*(float *)((unsigned long long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 - 1 6 ) * 8 , 1 ) + ');' ; //RBX..R15
2021-01-22 14:11:00 +01:00
3 2 .. 4 7 :
begin
usesXMMType: = true ;
2021-05-26 15:22:15 +02:00
s: = 'xmmreg ' + parameters[ j] . varname+ '=*(pxmmreg)((unsigned long long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ');' ;
2021-01-22 14:11:00 +01:00
end ;
2021-05-26 15:22:15 +02:00
4 8 .. 1 1 1 : s: = 'float ' + parameters[ j] . varname+ '=*(float *)((unsigned long long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ');' ; //RBX..R15
1 1 2 .. 1 4 3 : s: = 'double ' + parameters[ j] . varname+ '=*(double *)((unsigned long long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ');' ;
2021-01-21 01:04:41 +01:00
end ;
2021-05-26 15:22:15 +02:00
cscript. add( ' ' + s) ;
2021-01-22 14:11:00 +01:00
end ;
end
else
begin
for j: = 0 to length( parameters) - 1 do
begin
case parameters[ j] . contextitem of
2021-05-26 15:22:15 +02:00
0 : s: = 'unsigned long ' + parameters[ j] . varname+ '=*(unsigned long *)*(unsigned long *)((unsigned long)parameters+0x214);' ; //EAX
2021-11-14 21:14:26 +01:00
1 .. 5 , 7 : s: = 'unsigned long ' + parameters[ j] . varname+ '=*(unsigned long*)((unsigned long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 4 , 1 ) + ');' ; //RBX..R15
2022-01-12 00:37:46 +01:00
6 : s: = 'unsigned long ' + parameters[ j] . varname+ '=*(unsigned long*)((unsigned long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 4 , 1 ) + ')+12;' ; //RBX..R15
2021-05-26 15:22:15 +02:00
1 6 : s: = 'float ' + parameters[ j] . varname+ '=*(float *)((unsigned long)parameters+0x214);' ;
2022-02-08 23:12:58 +01:00
1 7 .. 2 3 : s: = 'float ' + parameters[ j] . varname+ '=*(float *)((unsigned long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 - 1 6 ) * 4 , 1 ) + ');' ; //EBX..EBP
2021-01-22 14:11:00 +01:00
3 2 .. 3 9 :
begin
usesXMMType: = true ;
2021-05-26 15:22:15 +02:00
s: = 'xmmreg ' + parameters[ j] . varname+ '=*(pxmmreg)((unsigned long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ');' ;
2021-01-22 14:11:00 +01:00
end ;
2021-05-26 15:22:15 +02:00
4 8 .. 7 9 : s: = 'float ' + parameters[ j] . varname+ '=*(float *)((unsigned long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ');' ; //EBX..EBP
1 1 2 .. 1 2 7 : s: = 'double ' + parameters[ j] . varname+ '=*(double *)((unsigned long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ');' ;
2021-01-22 14:11:00 +01:00
end ;
2021-05-26 15:22:15 +02:00
cscript. add( ' ' + s) ;
2021-01-21 01:04:41 +01:00
end ;
end ;
2021-05-26 15:22:15 +02:00
cscript. add( ' //start of user script' ) ;
2021-01-21 01:04:41 +01:00
for j: = scriptstart+ 1 to scriptend- 1 do
2021-05-26 15:22:15 +02:00
begin
tst: = ptruint( script. objects[ j] ) ;
cscript. AddObject( script[ j] , tobject( tst) ) ;
end ;
2021-08-10 15:36:00 +02:00
cscript. add( '; //end of user script' ) ;
2021-05-26 15:22:15 +02:00
//end of the script: write the values back
cscript. add( ' //Write back values' ) ;
if processhandler. is64Bit {$ifdef cpu64} or targetself{$endif} then
begin
for j: = 0 to length( parameters) - 1 do
begin
2022-01-12 00:37:46 +01:00
s: = '' ;
2021-05-26 15:22:15 +02:00
case parameters[ j] . contextitem of
0 : s: = '*(unsigned long long *)*(unsigned long long *)((unsigned long long)parameters+0x228)=' + parameters[ j] . varname+ ';' ; //RAX
2021-11-14 21:14:26 +01:00
1 .. 5 , 7 .. 1 5 : s: = '*(unsigned long long*)((unsigned long long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 8 , 1 ) + ')=' + parameters[ j] . varname+ ';' ; //RBX..R15
2022-01-12 00:37:46 +01:00
6 : s: = '' ; //skip, do not write rsp
2021-05-26 15:22:15 +02:00
1 6 : s: = '*(float *)((unsigned long long)parameters+0x228)=' + parameters[ j] . varname+ ';' ;
2022-02-08 23:12:58 +01:00
1 7 .. 3 1 : s: = '*(float *)((unsigned long long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 - 1 6 ) * 8 , 1 ) + ')=' + parameters[ j] . varname+ ';' ; //RBX..R15
2021-05-26 15:22:15 +02:00
3 2 .. 4 7 :
begin
usesXMMType: = true ;
s: = '*(pxmmreg)((unsigned long long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ')=' + parameters[ j] . varname+ ';' ;
end ;
4 8 .. 1 1 1 : s: = '*(float *)((unsigned long long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ')=' + parameters[ j] . varname+ ';' ; //RBX..R15
1 1 2 .. 1 4 3 : s: = '*(double *)((unsigned long long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ')=' + parameters[ j] . varname+ ';' ;
end ;
2022-01-12 00:37:46 +01:00
if s< > '' then
cscript. add( ' ' + s) ;
2021-05-26 15:22:15 +02:00
end ;
end
else
begin
for j: = 0 to length( parameters) - 1 do
begin
2022-02-07 15:00:08 +01:00
s: = '' ;
2021-05-26 15:22:15 +02:00
case parameters[ j] . contextitem of
0 : s: = '*(unsigned long *)*(unsigned long *)((unsigned long)parameters+0x214)=' + parameters[ j] . varname+ ';' ; //EAX
2021-11-14 21:14:26 +01:00
1 .. 5 , 7 : s: = '*(unsigned long*)((unsigned long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 4 , 1 ) + ')=' + parameters[ j] . varname+ ';' ; //RBX..R15
2022-01-12 00:37:46 +01:00
6 : s: = '' ;
2021-05-26 15:22:15 +02:00
1 6 : s: = '*(float *)((unsigned long)parameters+0x214)=' + parameters[ j] . varname+ ';' ;
2022-02-08 23:12:58 +01:00
1 7 .. 2 3 : s: = '*(float *)((unsigned long)parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 - 1 6 ) * 4 , 1 ) + ')=' + parameters[ j] . varname+ ';' ; //EBX..EBP
2021-05-26 15:22:15 +02:00
3 2 .. 3 9 :
begin
usesXMMType: = true ;
s: = '*(pxmmreg)((unsigned long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ')=' + parameters[ j] . varname+ ';' ;
end ;
4 8 .. 7 9 : s: = '*(float *)((unsigned long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ')=' + parameters[ j] . varname+ ';' ; //EBX..EBP
1 1 2 .. 1 2 7 : s: = '*(double *)((unsigned long)parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ')=' + parameters[ j] . varname+ ';' ;
end ;
2022-01-12 00:37:46 +01:00
if s< > '' then
cscript. add( ' ' + s) ;
2021-05-26 15:22:15 +02:00
end ;
end ;
2021-01-21 01:04:41 +01:00
cscript. add( '}' ) ;
2021-05-10 18:26:50 +02:00
2021-01-24 22:37:53 +01:00
//allocate a spot for the linker stage to put the address
if processhandler. is64Bit {$ifdef cpu64} or targetself{$endif} then
2021-05-11 11:04:46 +02:00
script. insert( 0 , {$ifdef windows} ifthen( DataForPass2. cdata. kernelAlloc, 'k' , '' ) + {$endif} 'alloc(' + functionname+ '_address,8)' )
2021-01-24 22:37:53 +01:00
else
2021-05-11 11:04:46 +02:00
script. insert( 0 , {$ifdef windows} ifthen( DataForPass2. cdata. kernelAlloc, 'k' , '' ) + {$endif} 'alloc(' + functionname+ '_address,4)' ) ;
2021-01-21 01:04:41 +01:00
inc( scriptstart, 1 ) ;
inc( scriptend, 1 ) ;
2021-01-24 22:37:53 +01:00
//create a safecall stub to call this routine with a simple call
s: = AddSafeCallStub( script, '[' + functionname+ '_address]' , targetself) ;
2021-01-21 01:04:41 +01:00
inc( scriptstart, 1 ) ;
inc( scriptend, 1 ) ;
//and finally replace the c block with a call to the safecallstub
for j: = scriptend downto scriptstart+ 1 do
script. Delete( j) ;
2021-01-24 22:37:53 +01:00
2021-01-21 01:04:41 +01:00
script[ scriptstart] : = 'call ' + s;
2021-01-24 22:37:53 +01:00
j: = length( dataForPass2. cdata. linklist) ;
setlength( dataForPass2. cdata. linklist, j+ 1 ) ;
dataForPass2. cdata. linklist[ j] . name : = functionname+ '_address' ;
dataForPass2. cdata. linklist[ j] . fromname: = functionname;
2021-08-30 12:53:57 +02:00
dataForPass2. cdata. usesxmm: = usesXMMType;
2021-01-21 01:04:41 +01:00
end ;
procedure AutoAssemblerLuaCodePass( script: TStrings; parameters: TLuaCodeParams; var i: integer ; syntaxcheckonly: boolean ) ;
var
j, k: integer ;
s: string ;
endpos, scriptstart, scriptend: integer ;
luascript: tstringlist;
linenr: integer ;
refnr: integer ;
hasAddedLuaServerCode: boolean = false ;
hasAddedAsmStatement: boolean = false ;
begin
//search for {$LUACODE/
linenr: = ptruint( script. Objects[ i] ) ;
scriptstart: = i;
2023-10-18 14:42:36 +02:00
2021-01-21 01:04:41 +01:00
j: = i+ 1 ;
while j< script. Count do
begin
if uppercase( script[ j] ) = '{$ASM}' then
break;
inc( j) ;
end ;
scriptend: = j;
luascript: = tstringlist. Create;
for j: = i+ 1 to scriptend- 1 do
luascript. add( script[ j] ) ;
if luaL_loadstring( luavm, pchar( luascript. text ) ) = 0 then
lua_pop( LuaVM, 1 )
else
begin
s: = lua_tostring( LuaVM, - 1 ) ;
lua_pop( LuaVM, 1 ) ;
// clipboard.AsText:=luascript.text;
raise exception. create( 'Invalid lua code in {$LUACODE} block at line ' + inttostr( linenr) + ' :' + s) ;
end ;
//parse s for the parameters that it wants
luascript. insert( 0 , 'return createRef(function(parameters)' ) ;
//load the values from parameters pointer
2021-01-22 14:11:00 +01:00
if processhandler. is64bit then
begin
for j: = 0 to length( parameters) - 1 do
begin
s: = 'local ' + parameters[ j] . varname+ '=' ;
case parameters[ j] . contextitem of
0 : s: = s+ 'readPointer(readPointer(parameters+0x228))' ; //RAX
2022-01-12 00:37:46 +01:00
1 .. 5 , 7 .. 1 5 : s: = s+ 'readPointer(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 8 , 1 ) + ')' ; //RBX..R15
6 : s: = s+ 'readPointer(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 8 , 1 ) + '+24)' ;
2021-01-22 14:11:00 +01:00
1 6 : s: = s+ 'readFloat(readPointer(parameters+0x228))' ; //RAX as float
1 7 .. 3 1 : s: = s+ 'readFloat(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 7 ) * 8 , 1 ) + ')' ; //RBX..R15 as float
3 2 .. 4 7 : s: = s+ 'readBytes(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ',16,true)' ;
4 8 .. 1 1 1 : s: = s+ 'readFloat(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ')' ;
1 1 2 .. 1 4 3 : s: = s+ 'readDouble(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ')' ;
end ;
luascript. insert( j+ 1 , s) ;
end ;
end
else
2021-01-21 01:04:41 +01:00
begin
2021-01-22 14:11:00 +01:00
for j: = 0 to length( parameters) - 1 do
begin
s: = 'local ' + parameters[ j] . varname+ '=' ;
case parameters[ j] . contextitem of
0 : s: = s+ 'readPointer(readPointer(parameters+0x214))' ; //RAX
2022-01-12 00:37:46 +01:00
1 .. 5 , 7 : s: = s+ 'readPointer(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 4 , 1 ) + ')' ; //RBX..R15
6 : s: = s+ 'readPointer(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 8 , 1 ) + '+12)' ;
2021-01-22 14:11:00 +01:00
1 6 : s: = s+ 'readFloat(readPointer(parameters+0x214))' ; //RAX as float
1 7 .. 2 3 : s: = s+ 'readFloat(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 7 ) * 4 , 1 ) + ')' ; //RBX..R15 as float
3 2 .. 3 9 : s: = s+ 'readBytes(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ',16,true)' ;
4 8 .. 7 9 : s: = s+ 'readFloat(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ')' ;
1 1 2 .. 1 2 7 : s: = s+ 'readDouble(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ')' ;
end ;
luascript. insert( j+ 1 , s) ;
2021-01-21 01:04:41 +01:00
end ;
end ;
//end of the script: write the values back
2021-01-22 14:11:00 +01:00
if processhandler. is64bit then
2021-01-21 01:04:41 +01:00
begin
2021-01-22 14:11:00 +01:00
for j: = 0 to length( parameters) - 1 do
begin
case parameters[ j] . contextitem of
0 : s: = 'writePointer(readPointer(parameters+0x228),' + parameters[ j] . varname+ ')' ;
2022-01-12 00:37:46 +01:00
1 .. 5 , 7 .. 1 5 : s: = 'writePointer(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 8 , 1 ) + ',' + parameters[ j] . varname+ ')' ; //RBX..R15
6 : s: = '' ;
2021-01-22 14:11:00 +01:00
1 6 : s: = 'writeFloat(readPointer(parameters+0x228),' + parameters[ j] . varname+ ')' ; //RAX as float
1 7 .. 3 1 : s: = 'writeFloat(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 7 ) * 8 , 1 ) + ',' + parameters[ j] . varname+ ')' ; //RBX..R15 as float
3 2 .. 4 7 : s: = 'writeBytes(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ',' + parameters[ j] . varname+ ')' ;
4 8 .. 1 1 1 : s: = 'writeFloat(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ',' + parameters[ j] . varname+ ')' ;
1 1 2 .. 1 4 3 : s: = 'writeDouble(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ',' + parameters[ j] . varname+ ')' ;
2022-10-23 10:39:22 +02:00
else
s: = '' ;
2021-01-22 14:11:00 +01:00
end ;
luascript. add( s) ;
2021-01-21 01:04:41 +01:00
end ;
2021-01-22 14:11:00 +01:00
end
else
begin
for j: = 0 to length( parameters) - 1 do
begin
case parameters[ j] . contextitem of
0 : s: = 'writePointer(readPointer(parameters+0x214),' + parameters[ j] . varname+ ')' ;
2022-01-12 00:37:46 +01:00
1 .. 5 , 7 : s: = 'writePointer(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 ) * 4 , 1 ) + ',' + parameters[ j] . varname+ ')' ; //EBX..EBP
6 : s: = '' ;
2021-01-22 14:11:00 +01:00
1 6 : s: = 'writeFloat(readPointer(parameters+0x214),' + parameters[ j] . varname+ ')' ; //EAX as float
1 7 .. 2 3 : s: = 'writeFloat(parameters+0x' + inttohex( $200 + ( parameters[ j] . contextitem- 1 7 ) * 4 , 1 ) + ',' + parameters[ j] . varname+ ')' ; //EBX..EBP as float
3 2 .. 3 9 : s: = 'writeBytes(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 3 2 ) * 1 6 , 1 ) + ',' + parameters[ j] . varname+ ')' ;
4 8 .. 7 9 : s: = 'writeFloat(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 4 8 ) * 4 , 1 ) + ',' + parameters[ j] . varname+ ')' ;
1 1 2 .. 1 2 7 : s: = 'writeDouble(parameters+0x' + inttohex( $a0 + ( parameters[ j] . contextitem- 1 1 2 ) * 8 , 1 ) + ',' + parameters[ j] . varname+ ')' ;
end ;
luascript. add( s) ;
2021-01-21 01:04:41 +01:00
2021-01-22 14:11:00 +01:00
end ;
2021-01-21 01:04:41 +01:00
end ;
luascript. add( 'return end )' ) ;
if lua_dostring( luavm, pchar( luascript. Text ) ) = 0 then
begin
refnr: = lua_tointeger( LuaVM, - 1 ) ;
lua_pop( LuaVM, 1 ) ;
if syntaxcheckonly then //remove this reference
lua_unref( LuaVM, refnr) ;
end
else
begin
s: = lua_tostring( LuaVM, - 1 ) ;
lua_pop( LuaVM, 1 ) ;
raise exception. create( 'Invalid lua code in internal {$LUACODE} block at line ' + inttostr( linenr) + ' :' + s) ;
end ;
//add the assemble function used to call the lua code, no need to save registers, it's called by a safecall stub, just pass param1 to lua
script. insert( 0 , 'alloc(ceinternal_autofree_luacallstub_at' + inttostr( linenr) + ',64)' ) ;
inc( scriptstart, 1 ) ;
inc( scriptend, 1 ) ;
script. add( 'ceinternal_autofree_luacallstub_at' + inttostr( linenr) + ':' ) ;
2021-01-22 14:11:00 +01:00
if processhandler. is64Bit then
begin
script. add( 'sub rsp,28' ) ; //scratchspace, and parameter save. Also aligns the stack
script. add( 'mov [rsp+20],rcx' ) ; //save the parameter pointer
script. add( 'mov ecx,' + inttohex( refnr, 1 ) ) ;
script. add( 'mov edx,1' ) ; //1 parameteer
script. add( 'lea r8,[rsp+20]' ) ; //the address where the parameter pointer is stored
script. add( 'mov r9,1' ) ;
script. add( 'call CELUA_ExecuteFunctionByReference' ) ;
script. add( 'add rsp,28' ) ;
script. add( 'ret' ) ;
end
else
begin
script. add( 'lea eax,[esp+4]' ) ; //esp=return address, esp+4=param1
//[ebp]=old ebp
//[ebp+4]=return address
//[ebp+8]=param1 (parameters)
script. add( 'push 1' ) ;
script. add( 'push eax' ) ; //push pointer to param1
script. add( 'push 1' ) ; //1 parameter
script. add( 'push ' + inttohex( refnr, 1 ) ) ;
script. add( 'call CELUA_ExecuteFunctionByReference' ) ;
script. add( 'ret' ) ;
end ;
2021-01-21 01:04:41 +01:00
//create a safecall stub to call this routine with a simple call (note, could be a 16 byte call so beware of that)
s: = AddSafeCallStub( script, 'ceinternal_autofree_luacallstub_at' + inttostr( linenr) , false ) ;
inc( scriptstart, 1 ) ; //also inserts an alloc at top
inc( scriptend, 1 ) ;
//and finally replace the luacode block with a call to the safecallstub
for j: = scriptend downto scriptstart+ 1 do
begin
script. Delete( j) ;
end ;
script[ scriptstart] : = 'call ' + s;
2021-01-24 22:37:53 +01:00
2021-01-21 01:04:41 +01:00
//clipboard.AsText:=script.text;
//debug^^^
end ;
2021-01-24 22:37:53 +01:00
procedure AutoAssemblerCodePass2( var dataForPass2: TAutoAssemblerCodePass2Data; symbollist: TSymbolListHandler) ;
2021-01-21 01:04:41 +01:00
begin
2021-01-24 22:37:53 +01:00
AutoAssemblerCCodePass2( dataForPass2, symbollist) ;
2021-01-25 22:28:37 +01:00
2021-01-21 01:04:41 +01:00
end ;
procedure AutoAssemblerCodePass1( script: TStrings; out dataForPass2: TAutoAssemblerCodePass2Data; syntaxcheckonly: boolean ; targetself: boolean ) ;
//this way the script only needs to be parsed once for quite similar code
var
2023-08-25 08:48:13 +02:00
i, j, k, r: integer ;
2021-01-21 01:04:41 +01:00
endpos: integer ;
uppercaseline: string ;
2021-01-24 22:37:53 +01:00
s, linenrstring: string ;
2021-01-21 01:04:41 +01:00
parameterstring: string ;
2021-01-24 22:37:53 +01:00
linenr: integer ;
2021-05-26 15:22:15 +02:00
lnstart: integer ;
2021-01-21 01:04:41 +01:00
parameters: TLuaCodeParams;
hasAddedLuaServerCode: boolean = false ;
2021-01-24 22:37:53 +01:00
_tcc: TTCC;
//
symbols, imports, errorlog: tstringlist;
ms: TMemorystream;
bytesizeneeded: integer ;
2021-09-23 13:32:26 +02:00
symbolerror: boolean ;
2023-08-25 08:48:13 +02:00
temps: string ;
2021-01-24 22:37:53 +01:00
//
2021-01-21 01:04:41 +01:00
begin
2021-09-22 17:34:44 +02:00
if tcclibimportlist= nil then
begin
tcclibimportlist: = TStringHashList. Create( true ) ;
2021-09-23 13:32:26 +02:00
tcclibimportlist. Add( '__divdi3' ) ;
tcclibimportlist. Add( '__moddi3' ) ;
tcclibimportlist. Add( '__udivdi3' ) ;
tcclibimportlist. Add( '__umoddi3' ) ;
tcclibimportlist. Add( '__ashrdi3' ) ;
tcclibimportlist. Add( '__lshrdi3' ) ;
tcclibimportlist. Add( '__ashldi3' ) ;
2021-09-22 17:34:44 +02:00
tcclibimportlist. Add( '__floatundisf' ) ;
2021-09-23 13:32:26 +02:00
tcclibimportlist. Add( '__floatundidf' ) ;
tcclibimportlist. Add( '__floatundixf' ) ;
tcclibimportlist. Add( '__fixunssfdi' ) ;
tcclibimportlist. Add( '__fixsfdi' ) ;
tcclibimportlist. Add( '__fixunsdfdi' ) ;
tcclibimportlist. Add( '__fixdfdi' ) ;
tcclibimportlist. Add( '__fixunsxfdi' ) ;
tcclibimportlist. Add( '__fixxfdi' ) ;
2021-09-22 17:34:44 +02:00
end ;
2021-01-24 22:37:53 +01:00
dataForPass2. cdata. cscript: = nil ;
2021-05-20 15:38:22 +02:00
dataForPass2. cdata. address: = 0 ;
dataForPass2. cdata. bytesize: = 0 ;
2021-01-24 22:37:53 +01:00
dataForPass2. cdata. usesxmm: = false ;
2021-05-20 15:38:22 +02:00
dataForPass2. cdata. symbols: = [ ] ;
dataForPass2. cdata. linklist: = [ ] ;
dataForPass2. cdata. references: = [ ] ;
2021-01-24 22:37:53 +01:00
dataForPass2. cdata. targetself: = false ;
2021-05-20 15:38:22 +02:00
dataForPass2. cdata. symbolPrefix: = '' ;
dataForPass2. cdata. nodebug: = false ;
dataForPass2. cdata. sourceCodeInfo: = nil ;
{$ifdef windows}
dataForPass2. cdata. kernelAlloc: = false ;
{$endif}
//setlength(dataForPass2.cdata.linklist,0);
//setlength(dataForPass2.cdata.references,0);
2021-01-24 22:37:53 +01:00
try
i: = 0 ;
while i< script. count do
2021-01-21 01:04:41 +01:00
begin
2021-01-24 22:37:53 +01:00
s: = script[ i] ;
if ( length( s) > = 4 ) and ( s[ 1 ] = '{' ) and ( s[ 2 ] = '$' ) and ( s[ 3 ] in [ 'l' , 'L' , 'c' , 'C' ] ) then //{$C or {$L
begin
2021-05-10 18:26:50 +02:00
if ( s[ 4 ] in [ 'u' , 'U' , 'c' , 'C' , '}' , ' ' ] ) then //{$CC, $CU, $LC, $LU , {$L}, {$C},.. {$C ..., {$CU ....,....
2021-01-24 22:37:53 +01:00
begin
endpos: = pos( '}' , s) ;
if endpos= - 1 then
raise exception. create( 'Invalid command line at ' + inttostr( ptrUint( script. Objects[ i] ) ) + ' (' + script[ i] + ')' ) ;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
uppercaseline: = uppercase( s) ;
2021-01-21 01:04:41 +01:00
2021-03-28 22:09:07 +02:00
{$ifdef windows}
2021-01-24 22:37:53 +01:00
if copy( uppercaseline, 1 , 9 ) = '{$LUACODE' then
begin
if targetself or ( processid= GetCurrentProcessId) then
raise exception. create( '{$LUACODE} blocks can not be used inside CE' ) ;
parameterstring: = copy( s, 1 1 , endpos- 1 1 ) ;
setlength( parameters, 0 ) ;
parseLuaCodeParameters( parameterstring, parameters) ;
2023-08-25 08:48:13 +02:00
if luaserverExists( 'CELUASERVER' + inttostr( getcurrentprocessid) ) = false then
tluaserver. create( 'CELUASERVER' + inttostr( getcurrentprocessid) ) ;
2021-01-21 01:04:41 +01:00
2023-08-25 08:48:13 +02:00
symhandler. getAddressFromName( 'CELUA_ServerName' , false , symbolerror) ;
2021-01-21 01:04:41 +01:00
2023-08-25 08:48:13 +02:00
if symbolerror then
begin
//need to add the CELUA_ library
2021-01-24 22:37:53 +01:00
if processhandler. is64Bit then
script. insert( 0 , 'loadlibrary(luaclient-x86_64.dll)' )
else
script. insert( 0 , 'loadlibrary(luaclient-i386.dll)' ) ;
2023-10-18 14:42:36 +02:00
inc( i, 1 ) ;
2023-08-25 08:48:13 +02:00
end ;
2021-01-24 22:37:53 +01:00
2023-08-25 08:48:13 +02:00
//add the code that runs and configures the luaserver
script. insert( 1 , 'CELUA_ServerName:' ) ;
script. insert( 2 , 'db ' 'CELUASERVER' + inttostr( getcurrentprocessid) + '' ',0' ) ;
2023-10-08 11:43:51 +02:00
inc( i, 2 ) ;
2023-08-25 08:48:13 +02:00
hasAddedLuaServerCode: = true ;
2021-01-24 22:37:53 +01:00
AutoAssemblerLuaCodePass( script, parameters, i, syntaxcheckonly)
end
else
2021-03-28 22:09:07 +02:00
{$endif}
2021-05-10 18:26:50 +02:00
if copy( uppercaseline, 1 , 3 ) = '{$C' then
2021-01-24 22:37:53 +01:00
begin
2021-05-10 18:26:50 +02:00
if uppercaseline[ 4 ] in [ '}' , ' ' ] then //{$C} {$C ....}
begin
AutoAssemblerCBlockPass1( script, i, dataForPass2) ;
end
else
if copy( uppercaseline, 1 , 7 ) = '{$CCODE' then
begin
parameterstring: = copy( s, 9 , endpos- 9 ) ;
setlength( parameters, 0 ) ;
parseLuaCodeParameters( parameterstring, parameters) ; //same data needed for C, so use it
AutoAssemblerCCodePass1( script, parameters, i, dataForPass2, syntaxcheckonly, targetself) ;
end ;
2021-01-24 22:37:53 +01:00
end ;
end ;
end ;
inc( i) ;
end ;
if dataForPass2. cdata. cscript< > nil then
begin
if dataforpass2. cdata. usesxmm then
2021-01-21 01:04:41 +01:00
begin
2021-01-24 22:37:53 +01:00
//insert the xmm type
dataForPass2. cdata. cscript. insert( 0 , 'typedef struct {' ) ;
dataForPass2. cdata. cscript. insert( 1 , ' union{' ) ;
dataForPass2. cdata. cscript. insert( 2 , ' struct{' ) ;
dataForPass2. cdata. cscript. insert( 3 , ' float f0;' ) ;
dataForPass2. cdata. cscript. insert( 4 , ' float f1;' ) ;
dataForPass2. cdata. cscript. insert( 5 , ' float f2;' ) ;
dataForPass2. cdata. cscript. insert( 6 , ' float f3;' ) ;
dataForPass2. cdata. cscript. insert( 7 , ' };' ) ;
dataForPass2. cdata. cscript. insert( 8 , ' struct{' ) ;
dataForPass2. cdata. cscript. insert( 9 , ' double d0;' ) ;
dataForPass2. cdata. cscript. insert( 1 0 , ' double d1;' ) ;
dataForPass2. cdata. cscript. insert( 1 1 , ' };' ) ;
dataForPass2. cdata. cscript. insert( 1 2 , ' float fa[4];' ) ;
dataForPass2. cdata. cscript. insert( 1 3 , ' double da[2];' ) ;
dataForPass2. cdata. cscript. insert( 1 4 , ' };' ) ;
dataForPass2. cdata. cscript. insert( 1 5 , '} xmmreg, *pxmmreg;' ) ;
end ;
2021-01-21 01:04:41 +01:00
2021-06-02 19:11:08 +02:00
2021-01-24 22:37:53 +01:00
//testcompile the full script
if targetself then
_tcc: = tccself
else
2022-09-22 00:48:23 +02:00
begin
2022-09-27 16:31:24 +02:00
{$ifdef windows}
2022-09-22 00:48:23 +02:00
if getConnection< > nil then
_tcc: = tcc_linux
else
{$endif}
2022-09-27 16:31:24 +02:00
_tcc: = tcc;
2022-09-22 00:48:23 +02:00
end ;
2021-01-24 22:37:53 +01:00
//clipboard.AsText:=dataForPass2.cdata.cscript.text;
2021-01-21 01:04:41 +01:00
2022-09-22 00:48:23 +02:00
2021-01-24 22:37:53 +01:00
ms: = TMemoryStream. Create;
errorlog: = tstringlist. create;
imports: = tstringlist. create;
symbols: = tstringlist. create;
try
bytesizeneeded: = 0 ;
2021-05-20 13:52:49 +02:00
if _tcc. testcompileScript( dataForPass2. cdata. cscript. text , bytesizeneeded, imports, symbols, nil , errorlog) = false then
2021-01-21 01:04:41 +01:00
begin
2021-05-26 15:22:15 +02:00
//example: <string-12>:6: error: 'fffff' undeclared
//search for <string*>: and replace the linenumber with the AA script linenumber
2021-01-24 22:37:53 +01:00
for i: = 0 to errorlog. count- 1 do
begin
s: = errorlog[ i] ;
2021-05-26 15:22:15 +02:00
if s. StartsWith( '<string' ) then
2021-01-24 22:37:53 +01:00
begin
2021-08-30 12:53:57 +02:00
// Clipboard.AsText:=dataForPass2.cdata.cscript.text;
2021-05-26 15:22:15 +02:00
2021-01-24 22:37:53 +01:00
linenrstring: = '' ;
2021-05-26 15:22:15 +02:00
lnstart: = pos( '>:' , s) + 2 ;
for j: = lnstart to length( s) do
2021-01-24 22:37:53 +01:00
begin
if not ( s[ j] in [ '0' .. '9' ] ) then
begin
2021-05-26 15:22:15 +02:00
if j> lnstart then
2021-01-24 22:37:53 +01:00
begin
2021-05-26 15:22:15 +02:00
linenrstring: = copy( s, lnstart, j- lnstart) ;
linenr: = strtoint( linenrstring) ;
2021-01-24 22:37:53 +01:00
//convert linenr to AA linenr (if possible)
if ( linenr> = 0 ) and ( linenr< dataForPass2. cdata. cscript. count) then
begin
2021-08-30 12:53:57 +02:00
//Clipboard.AsText:=dataForPass2.cdata.cscript[linenr-1];
2021-01-24 22:37:53 +01:00
linenr: = integer( ptruint( dataForPass2. cdata. cscript. objects[ linenr- 1 ] ) ) ;
s: = 'Error at line ' + linenr. ToString+ ' ' + Copy( s, j) ;
end ;
errorlog[ i] : = s;
end ;
break;
end ;
end ;
end ;
end ;
2021-01-21 01:04:41 +01:00
2021-01-24 22:37:53 +01:00
raise exception. create( 'C Error :' + errorlog. text ) ;
end ;
dataforpass2. cdata. bytesize: = max( 3 2 , align( ptruint( bytesizeneeded* 2 ) , 1 6 ) ) ;
dataforpass2. cdata. targetself: = targetself;
setlength( dataforpass2. cdata. references, imports. Count+ length( dataforpass2. cdata. linklist) ) ;
//fill the functions this script referenced by name
for i: = 0 to imports. count- 1 do
2021-09-22 17:34:44 +02:00
begin
if ( length( imports[ i] ) = 9 ) and ( imports[ i] [ 1 ] = '_' ) and ( ( imports[ i] = '__mzerosf' ) or ( imports[ i] = '__mzerodf' ) ) then
begin
//it's using these negative 0 types it assumes it has access to.
if imports[ i] [ 8 ] = 's' then dataForPass2. cdata. cscript. Insert( 0 , 'float __mzerosf=-0.0f; //Autogenerated' ) ;
if imports[ i] [ 8 ] = 'd' then dataForPass2. cdata. cscript. Insert( 0 , 'double __mzerodf=-0.0f; //Autogenerated' ) ;
end
else
begin
if tcclibimportlist. Find( imports[ i] ) < > - 1 then
begin
2021-09-23 13:32:26 +02:00
symhandler. getAddressFromName( '__floatundidf' , false , symbolerror) ;
if symbolerror then
begin
j: = lua_gettop( LuaVM) ;
lua_getglobal( LuaVM, 'compileTCCLib' ) ;
r: = lua_pcall( LuaVM, 0 , 0 , 0 ) ;
lua_settop( LuaVM, j) ;
symhandler. getAddressFromName( '__floatundidf' , false , symbolerror) ;
if symbolerror then
2021-09-23 20:28:14 +02:00
raise exception. create( 'This code requires the TCC Library, but it failed to compile' ) ;
2021-09-23 13:32:26 +02:00
end ;
2021-09-22 17:34:44 +02:00
end ;
end ;
2021-01-24 22:37:53 +01:00
dataforpass2. cdata. references[ i] . name : = imports[ i] ;
2021-09-22 17:34:44 +02:00
end ;
2021-01-22 14:11:00 +01:00
2021-01-24 22:37:53 +01:00
for i: = imports. count to imports. count+ length( dataforpass2. cdata. linklist) - 1 do
dataforpass2. cdata. references[ i] . name : = dataforpass2. cdata. linklist[ i- imports. count] . name ;
2021-01-21 01:04:41 +01:00
2023-08-25 08:48:13 +02:00
if processhandler. is64Bit= false then //unlikely nowadays, but check anyhow
begin
//could be using stdcall function names (_symbolname@#)
for i: = 0 to symbols. count- 1 do
begin
if symbols[ i] . StartsWith( '_' ) and
( symbols[ i] [ length( symbols[ i] ) ] in [ '0' .. '9' ] ) and
symbols[ i] . Contains( '@' ) then
begin
j: = symbols[ i] . IndexOf( '@' ) ;
temps: = symbols[ i] . Substring( j+ 1 ) ;
if TryStrToInt( temps, k) then
begin
//it is a _symbolname@###
temps: = symbols[ i] . Substring( 1 , j- 1 ) ;
symbols. Add( temps) ;
end ;
end ;
end ;
end ;
2021-05-10 18:26:50 +02:00
if dataforpass2. cdata. symbolPrefix< > '' then
begin //add another version with the prefix added
setlength( dataforpass2. cdata. symbols, symbols. count* 2 ) ;
for i: = 0 to symbols. count- 1 do
begin
dataforpass2. cdata. symbols[ i* 2 ] . name : = symbols[ i shr 1 ] ;
dataforpass2. cdata. symbols[ i* 2 ] . address: = 0 ;
dataforpass2. cdata. symbols[ i* 2 + 1 ] . name : = dataforpass2. cdata. symbolPrefix+ '.' + symbols[ i] ;
dataforpass2. cdata. symbols[ i* 2 + 1 ] . address: = 0 ;
end ;
end
else
2021-01-24 22:37:53 +01:00
begin
2021-05-10 18:26:50 +02:00
setlength( dataforpass2. cdata. symbols, symbols. count) ;
for i: = 0 to symbols. count- 1 do
begin
dataforpass2. cdata. symbols[ i] . name : = symbols[ i] ;
dataforpass2. cdata. symbols[ i] . address: = 0 ;
2023-08-25 08:48:13 +02:00
//dataforpass2.cdata.symbols[i].altname:=stripsymbolname(symbols[i]);
2021-05-10 18:26:50 +02:00
end ;
2021-01-21 01:04:41 +01:00
end ;
2021-01-24 22:37:53 +01:00
2021-05-10 18:26:50 +02:00
2021-01-24 22:37:53 +01:00
finally
ms. free;
imports. free;
errorlog. free;
symbols. free;
2021-01-21 01:04:41 +01:00
end ;
2021-01-24 22:37:53 +01:00
script. insert( 0 , 'alloc(ceinternal_autofree_ccode,' + dataforpass2. cdata. bytesize. ToString+ ')' ) ;
2021-01-21 01:04:41 +01:00
end ;
2021-01-24 22:37:53 +01:00
except
2021-01-25 22:28:37 +01:00
if dataforpass2. cdata. cscript< > nil then
freeandnil( dataforpass2. cdata. cscript) ;
2021-01-24 22:37:53 +01:00
raise ; //reraise the exception
2021-01-21 01:04:41 +01:00
end ;
end ;
2021-09-22 17:34:44 +02:00
2021-01-21 01:04:41 +01:00
end .