mirror of https://github.com/red-prig/fpPS4.git
1555 lines
27 KiB
Plaintext
1555 lines
27 KiB
Plaintext
unit kern_jit2;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
mqueue,
|
|
x86_fpdbgdisas,
|
|
x86_jit,
|
|
kern_jit2_ctx,
|
|
kern_jit2_ops_avx;
|
|
|
|
var
|
|
print_asm:Boolean=False;
|
|
|
|
procedure pick(var ctx:t_jit_context2);
|
|
procedure pick_locked(var ctx:t_jit_context2);
|
|
|
|
implementation
|
|
|
|
uses
|
|
sysutils,
|
|
kern_thr,
|
|
ucontext,
|
|
vmparam,
|
|
vm_pmap,
|
|
vm_map,
|
|
systm,
|
|
trap,
|
|
md_context,
|
|
kern_sig,
|
|
kern_jit2_ops,
|
|
kern_jit_dynamic;
|
|
|
|
procedure jit_syscall; assembler; nostackframe;
|
|
label
|
|
_after_call,
|
|
_doreti,
|
|
_fail,
|
|
_ast,
|
|
_doreti_exit;
|
|
asm
|
|
//prolog (debugger)
|
|
pushq %rbp
|
|
movqq %rsp,%rbp
|
|
|
|
movqq %rax,jit_frame.tf_rip(%r15) //save %rax to tf_rip
|
|
|
|
pushf
|
|
pop %rax
|
|
|
|
movqq %gs:teb.thread,%r14 //curkthread
|
|
test %r14,%r14
|
|
jz _fail
|
|
|
|
andl NOT_PCB_FULL_IRET,kthread.pcb_flags(%r14) //clear PCB_FULL_IRET
|
|
|
|
movqq %rax,kthread.td_frame.tf_rflags(%r14) //save flags
|
|
|
|
movqq %rdi,kthread.td_frame.tf_rdi(%r14)
|
|
movqq %rsi,kthread.td_frame.tf_rsi(%r14)
|
|
movqq %rdx,kthread.td_frame.tf_rdx(%r14)
|
|
movqq $0,kthread.td_frame.tf_rcx(%r14)
|
|
movqq %r8 ,kthread.td_frame.tf_r8 (%r14)
|
|
movqq %r9 ,kthread.td_frame.tf_r9 (%r14)
|
|
movqq %rbx,kthread.td_frame.tf_rbx(%r14)
|
|
movqq %r10,kthread.td_frame.tf_r10(%r14)
|
|
movqq $0,kthread.td_frame.tf_r11(%r14)
|
|
movqq %r12,kthread.td_frame.tf_r12(%r14)
|
|
movqq %r13,kthread.td_frame.tf_r13(%r14)
|
|
|
|
movqq $1,kthread.td_frame.tf_trapno(%r14)
|
|
movqq $0,kthread.td_frame.tf_addr (%r14)
|
|
movqq $0,kthread.td_frame.tf_flags (%r14)
|
|
movqq $2,kthread.td_frame.tf_err (%r14) //sizeof(syscall)
|
|
|
|
movqq jit_frame.tf_rax(%r15),%rax
|
|
movqq %rax,kthread.td_frame.tf_rax(%r14)
|
|
|
|
movqq jit_frame.tf_rsp(%r15),%rax
|
|
movqq %rax,kthread.td_frame.tf_rsp(%r14)
|
|
|
|
movqq jit_frame.tf_rbp(%r15),%rax
|
|
movqq %rax,kthread.td_frame.tf_rbp(%r14)
|
|
|
|
movqq jit_frame.tf_r14(%r15),%rax
|
|
movqq %rax,kthread.td_frame.tf_r14(%r14)
|
|
|
|
movqq jit_frame.tf_r15(%r15),%rax
|
|
movqq %rax,kthread.td_frame.tf_r15(%r14)
|
|
|
|
movqq jit_frame.tf_rip(%r15),%rax
|
|
movqq %rax,kthread.td_frame.tf_rip(%r14)
|
|
|
|
andq $-16,%rsp //align stack
|
|
|
|
call amd64_syscall
|
|
|
|
_after_call:
|
|
|
|
movqq %gs:teb.thread ,%r14 //curkthread
|
|
movqq kthread.td_jit_ctx(%r14),%r15 //jit_frame
|
|
|
|
//Requested full context restore
|
|
testl PCB_FULL_IRET,kthread.pcb_flags(%r14)
|
|
jnz _doreti
|
|
|
|
testl TDF_AST,kthread.td_flags(%r14)
|
|
jne _ast
|
|
|
|
//Restore preserved registers.
|
|
|
|
//get flags
|
|
movqq kthread.td_frame.tf_rflags(%r14),%rax
|
|
push %rax
|
|
popf
|
|
|
|
movqq kthread.td_frame.tf_rdi(%r14),%rdi
|
|
movqq kthread.td_frame.tf_rsi(%r14),%rsi
|
|
movqq kthread.td_frame.tf_rdx(%r14),%rdx
|
|
|
|
movqq kthread.td_frame.tf_rax(%r14),%rax
|
|
movqq %rax,jit_frame.tf_rax(%r15)
|
|
|
|
movqq kthread.td_frame.tf_rsp(%r14),%rax
|
|
movqq %rax,jit_frame.tf_rsp(%r15)
|
|
|
|
movqq kthread.td_frame.tf_rbp(%r14),%rax
|
|
movqq %rax,jit_frame.tf_rbp(%r15)
|
|
|
|
movqq $0,%rcx
|
|
movqq $0,%r11
|
|
|
|
//epilog (debugger)
|
|
popq %rbp
|
|
ret
|
|
|
|
//fail (curkthread=nil)
|
|
_fail:
|
|
|
|
or $1,%rax //set CF
|
|
push %rax
|
|
popf
|
|
|
|
movqq $14,jit_frame.tf_rax(%r15) //EFAULT
|
|
movqq $0,%rdx
|
|
movqq $0,%rcx
|
|
movqq $0,%r11
|
|
|
|
popq %rbp
|
|
ret
|
|
|
|
//ast
|
|
_ast:
|
|
|
|
call ast
|
|
jmp _after_call
|
|
|
|
//doreti
|
|
_doreti:
|
|
|
|
//%r14=curkthread
|
|
testl TDF_AST,kthread.td_flags(%r14)
|
|
je _doreti_exit
|
|
|
|
call ast
|
|
jmp _doreti
|
|
|
|
_doreti_exit:
|
|
|
|
//Restore full.
|
|
call ipi_sigreturn
|
|
hlt
|
|
end;
|
|
|
|
procedure jit_before_start; assembler; nostackframe;
|
|
asm
|
|
nop
|
|
end;
|
|
|
|
procedure jit_jmp_dispatch; assembler; nostackframe;
|
|
asm
|
|
//prolog (debugger)
|
|
push %rbp
|
|
movq %rsp,%rbp
|
|
|
|
andq $-16,%rsp //align stack
|
|
|
|
pushf //0
|
|
push %rdi //1
|
|
push %rsi //2
|
|
push %rdx //3
|
|
push %rcx //4
|
|
push %r8 //5
|
|
push %r9 //6
|
|
push %r10 //7
|
|
push %r11 //8
|
|
|
|
lea -8(%rsp),%rsp //align
|
|
|
|
lea -16(%rsp),%rsp
|
|
movdqa %xmm0,(%rsp)
|
|
|
|
mov %rax,%rdi
|
|
mov $0,%rsi
|
|
|
|
call jmp_dispatcher
|
|
|
|
movdqa (%rsp),%xmm0
|
|
lea 16(%rsp),%rsp
|
|
|
|
lea 8(%rsp),%rsp //align
|
|
|
|
pop %r11 //0
|
|
pop %r10 //1
|
|
pop %r9 //2
|
|
pop %r8 //3
|
|
pop %rcx //4
|
|
pop %rdx //5
|
|
pop %rsi //6
|
|
pop %rdi //7
|
|
popf //8
|
|
|
|
//epilog
|
|
movq %rbp,%rsp
|
|
pop %rbp
|
|
|
|
lea 8(%rsp),%rsp
|
|
jmp %rax
|
|
end;
|
|
|
|
procedure jit_call_dispatch; assembler; nostackframe;
|
|
asm
|
|
//prolog (debugger)
|
|
push %rbp
|
|
movq %rsp,%rbp
|
|
|
|
andq $-16,%rsp //align stack
|
|
|
|
push %rdi //0
|
|
push %rsi //1
|
|
push %rdx //2
|
|
push %rcx //3
|
|
push %r8 //4
|
|
push %r9 //5
|
|
push %r10 //6
|
|
push %r11 //7
|
|
|
|
mov %rax,%rdi
|
|
mov $1,%rsi
|
|
|
|
lea -16(%rsp),%rsp
|
|
movdqa %xmm0,(%rsp)
|
|
|
|
call jmp_dispatcher
|
|
|
|
movdqa (%rsp),%xmm0
|
|
lea 16(%rsp),%rsp
|
|
|
|
pop %r11 //0
|
|
pop %r10 //1
|
|
pop %r9 //2
|
|
pop %r8 //3
|
|
pop %rcx //4
|
|
pop %rdx //5
|
|
pop %rsi //6
|
|
pop %rdi //7
|
|
|
|
//epilog
|
|
movq %rbp,%rsp
|
|
pop %rbp
|
|
|
|
lea 8(%rsp),%rsp
|
|
jmp %rax
|
|
end;
|
|
|
|
procedure jit_assert;
|
|
begin
|
|
Writeln('TODO:jit_assert');
|
|
Assert(False);
|
|
end;
|
|
|
|
procedure jit_system_error;
|
|
begin
|
|
Writeln('TODO:jit_system_error');
|
|
Assert(False);
|
|
end;
|
|
|
|
procedure jit_exit_proc;
|
|
begin
|
|
Writeln('TODO:jit_exit_proc');
|
|
//Assert(False);
|
|
end;
|
|
|
|
//0x0
|
|
//0x1
|
|
//0x4
|
|
//0x6
|
|
//0xb
|
|
|
|
//0x40000000
|
|
//0x40000010
|
|
|
|
//0x80000001
|
|
//0x80000002
|
|
//0x80000004
|
|
//0x80000005
|
|
//0x80000006
|
|
//0x80000008
|
|
|
|
//0xc0000000
|
|
//0xc0000001
|
|
procedure jit_cpuid; assembler; nostackframe;
|
|
label
|
|
_cpuid_0,
|
|
_cpuid_1;
|
|
asm
|
|
pushf
|
|
|
|
mov jit_frame.tf_rax(%r15),%rax
|
|
|
|
cmp $0,%eax
|
|
je _cpuid_0
|
|
|
|
cmp $1,%eax
|
|
je _cpuid_1
|
|
|
|
ud2
|
|
|
|
_cpuid_0:
|
|
|
|
//cpu_high TODO check
|
|
mov $0xF,%eax
|
|
|
|
//cpu_vendor
|
|
mov $0x68747541,%ebx
|
|
mov $0x69746E65,%edx
|
|
mov $0x444D4163,%ecx
|
|
|
|
mov %rax,jit_frame.tf_rax(%r15)
|
|
popf
|
|
ret
|
|
|
|
_cpuid_1:
|
|
|
|
//get host
|
|
cpuid
|
|
|
|
//if ((cpu_id & 0xffffff80) == 0x740f00) then
|
|
//if "machdep.bootparams.base_ps4_mode" then sceKernelHasNeoMode
|
|
|
|
//if ((cpu_id & 0xffffff80) == 0x740f00) then sceKernelIsAuthenticNeo
|
|
|
|
mov $0x00710f13,%eax //cpu_id
|
|
mov $0x178bfbff,%edx //cpu_feature
|
|
mov $0x36d8220b,%ecx //cpu_feature2
|
|
|
|
//CPUID_BRAND_INDEX 0x000000ff
|
|
//CPUID_CLFUSH_SIZE 0x0000ff00
|
|
//CPUID_HTT_CORES 0x00ff0000 //sceKernelGetCurrentCpu 0..7
|
|
//CPUID_LOCAL_APIC_ID 0xff000000
|
|
|
|
and $0xFF070000,%ebx //filter CPUID_LOCAL_APIC_ID|CPUID_HTT_CORES
|
|
|
|
or $0x00000800,%ebx //cpu_procinfo
|
|
|
|
mov %rax,jit_frame.tf_rax(%r15)
|
|
popf
|
|
ret
|
|
|
|
end;
|
|
|
|
procedure op_jmp_dispatcher(var ctx:t_jit_context2);
|
|
begin
|
|
ctx.builder.call_far(@jit_jmp_dispatch); //input:rax
|
|
end;
|
|
|
|
procedure op_call_dispatcher(var ctx:t_jit_context2);
|
|
begin
|
|
ctx.builder.call_far(@jit_call_dispatch); //input:rax
|
|
end;
|
|
|
|
procedure op_push_rip(var ctx:t_jit_context2);
|
|
var
|
|
i:Integer;
|
|
stack:TRegValue;
|
|
imm:Int64;
|
|
begin
|
|
//lea rsp,[rsp-8]
|
|
//mov [rsp],rax
|
|
|
|
with ctx.builder do
|
|
begin
|
|
stack:=r_tmp0;
|
|
|
|
i:=GetFrameOffset(rsp);
|
|
movq(stack,[r_thrd+i]);
|
|
leaq(stack,[stack-8]);
|
|
movq([r_thrd+i],stack);
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
imm:=Int64(ctx.ptr_next);
|
|
|
|
if (classif_offset_se64(imm)=os64) then
|
|
begin
|
|
if (classif_offset_u64(imm)=os64) then
|
|
begin
|
|
//64bit imm
|
|
movi64(r_tmp1,imm);
|
|
movq([stack],r_tmp1);
|
|
end else
|
|
begin
|
|
//32bit zero extend
|
|
movi(new_reg_size(r_tmp1,os32),imm);
|
|
movq([stack],r_tmp1);
|
|
end;
|
|
end else
|
|
begin
|
|
//32bit sign extend
|
|
movi(os64,[stack],imm);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure op_pop_rip(var ctx:t_jit_context2); //out:rax
|
|
var
|
|
i:Integer;
|
|
stack:TRegValue;
|
|
begin
|
|
//mov rax,[rsp]
|
|
//lea rsp,[rsp+8]
|
|
|
|
with ctx.builder do
|
|
begin
|
|
stack:=r_tmp0;
|
|
|
|
i:=GetFrameOffset(rsp);
|
|
movq(stack,[r_thrd+i]);
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
movq(r_tmp1,[stack]);
|
|
|
|
seto(al);
|
|
lahf;
|
|
addi8(os64,[r_thrd+i],8);
|
|
addi(al,127);
|
|
sahf;
|
|
|
|
movq(r_tmp0,r_tmp1);
|
|
end;
|
|
end;
|
|
|
|
procedure op_set_rax_imm(var ctx:t_jit_context2;imm:Int64);
|
|
begin
|
|
with ctx.builder do
|
|
if (classif_offset_u64(imm)=os64) then
|
|
begin
|
|
//64bit imm
|
|
movi64(r_tmp0,imm);
|
|
end else
|
|
begin
|
|
//32bit zero extend
|
|
movi(new_reg_size(r_tmp0,os32),imm);
|
|
end;
|
|
end;
|
|
|
|
procedure op_call(var ctx:t_jit_context2);
|
|
var
|
|
id:t_jit_i_link;
|
|
ofs:Int64;
|
|
dst:Pointer;
|
|
new1,new2:TRegValue;
|
|
i:Integer;
|
|
link:t_jit_i_link;
|
|
begin
|
|
op_push_rip(ctx);
|
|
|
|
if (ctx.din.Operand[1].RegValue[0].AType=regNone) then
|
|
begin
|
|
//imm offset
|
|
|
|
ofs:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,1,ofs);
|
|
|
|
dst:=ctx.ptr_next+ofs;
|
|
|
|
if ctx.is_text_addr(QWORD(dst)) and
|
|
(not exist_entry(dst)) then
|
|
begin
|
|
link:=ctx.get_link(dst);
|
|
|
|
if (link<>nil_link) then
|
|
begin
|
|
ctx.builder.jmp(link);
|
|
ctx.add_forward_point(nil_link,dst);
|
|
end else
|
|
begin
|
|
id:=ctx.builder.jmp(nil_link);
|
|
ctx.add_forward_point(id,dst);
|
|
end;
|
|
end else
|
|
begin
|
|
op_set_rax_imm(ctx,Int64(dst));
|
|
//
|
|
op_call_dispatcher(ctx);
|
|
end;
|
|
|
|
end else
|
|
if is_memory(ctx.din) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
//
|
|
build_lea(ctx,1,new1,[inc8_rsp,code_ref]);
|
|
//
|
|
ctx.builder.call_far(@uplift_jit); //in/out:rax uses:r14
|
|
//
|
|
ctx.builder.movq(new1,[new1]);
|
|
//
|
|
op_call_dispatcher(ctx);
|
|
end else
|
|
if is_preserved(ctx.din) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
//
|
|
i:=GetFrameOffset(ctx.din.Operand[1].RegValue[0]);
|
|
ctx.builder.movq(new1,[r_thrd+i]);
|
|
//
|
|
if is_rsp(ctx.din.Operand[1].RegValue[0]) then
|
|
begin
|
|
ctx.builder.leaq(new1,[new1+8]);
|
|
end;
|
|
//
|
|
op_call_dispatcher(ctx);
|
|
end else
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
new2:=new_reg(ctx.din.Operand[1]);
|
|
//
|
|
ctx.builder.movq(new1,new2);
|
|
//
|
|
op_call_dispatcher(ctx);
|
|
end;
|
|
|
|
//
|
|
ctx.add_forward_point(nil_link,ctx.ptr_next);
|
|
end;
|
|
|
|
procedure op_ret(var ctx:t_jit_context2);
|
|
begin
|
|
Assert(ctx.din.Operand[1].ByteCount=0);
|
|
|
|
op_pop_rip(ctx); //out:rax
|
|
//
|
|
op_jmp_dispatcher(ctx);
|
|
//
|
|
ctx.trim:=True;
|
|
end;
|
|
|
|
procedure op_jmp(var ctx:t_jit_context2);
|
|
var
|
|
id:t_jit_i_link;
|
|
ofs:Int64;
|
|
dst:Pointer;
|
|
new1,new2:TRegValue;
|
|
i:Integer;
|
|
link:t_jit_i_link;
|
|
begin
|
|
if (ctx.din.Operand[1].RegValue[0].AType=regNone) then
|
|
begin
|
|
ofs:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,1,ofs);
|
|
|
|
dst:=ctx.ptr_next+ofs;
|
|
|
|
if ctx.is_text_addr(QWORD(dst)) and
|
|
(not exist_entry(dst)) then
|
|
begin
|
|
link:=ctx.get_link(dst);
|
|
|
|
if (link<>nil_link) then
|
|
begin
|
|
ctx.builder.jmp(link);
|
|
ctx.add_forward_point(nil_link,dst);
|
|
end else
|
|
begin
|
|
id:=ctx.builder.jmp(nil_link);
|
|
ctx.add_forward_point(id,dst);
|
|
end;
|
|
end else
|
|
begin
|
|
op_set_rax_imm(ctx,Int64(dst));
|
|
//
|
|
op_jmp_dispatcher(ctx);
|
|
end;
|
|
|
|
end else
|
|
if is_memory(ctx.din) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
//
|
|
build_lea(ctx,1,new1,[code_ref]);
|
|
//
|
|
ctx.builder.call_far(@uplift_jit); //in/out:rax uses:r14
|
|
//
|
|
ctx.builder.movq(new1,[new1]);
|
|
//
|
|
op_jmp_dispatcher(ctx);
|
|
end else
|
|
if is_preserved(ctx.din) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
//
|
|
i:=GetFrameOffset(ctx.din.Operand[1].RegValue[0]);
|
|
ctx.builder.movq(new1,[r_thrd+i]);
|
|
//
|
|
op_jmp_dispatcher(ctx);
|
|
end else
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
new2:=new_reg(ctx.din.Operand[1]);
|
|
//
|
|
ctx.builder.movq(new1,new2);
|
|
//
|
|
op_jmp_dispatcher(ctx);
|
|
end;
|
|
//
|
|
ctx.trim:=True;
|
|
end;
|
|
|
|
procedure op_jcc(var ctx:t_jit_context2);
|
|
var
|
|
id,id2:t_jit_i_link;
|
|
ofs:Int64;
|
|
dst:Pointer;
|
|
link:t_jit_i_link;
|
|
begin
|
|
ofs:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,1,ofs);
|
|
|
|
dst:=ctx.ptr_next+ofs;
|
|
|
|
if ctx.is_text_addr(QWORD(dst)) and
|
|
(not exist_entry(dst)) then
|
|
begin
|
|
link:=ctx.get_link(dst);
|
|
|
|
if (link<>nil_link) then
|
|
begin
|
|
ctx.builder.jcc(ctx.din.OpCode.Suffix,link);
|
|
ctx.add_forward_point(nil_link,dst);
|
|
end else
|
|
begin
|
|
id:=ctx.builder.jcc(ctx.din.OpCode.Suffix,nil_link);
|
|
ctx.add_forward_point(id,dst);
|
|
end;
|
|
end else
|
|
begin
|
|
id:=ctx.builder.jcc(ctx.din.OpCode.Suffix,nil_link,os8);
|
|
|
|
id2:=ctx.builder.jmp(nil_link,os8);
|
|
|
|
id._label:=ctx.builder.get_curr_label.after;
|
|
//
|
|
op_set_rax_imm(ctx,Int64(dst));
|
|
//
|
|
op_jmp_dispatcher(ctx);
|
|
|
|
id2._label:=ctx.builder.get_curr_label.after;
|
|
end;
|
|
end;
|
|
|
|
const
|
|
movsx8_desc:t_op_type=(op:$0FBE);
|
|
movsxd_desc:t_op_type=(op:$63);
|
|
|
|
procedure op_push(var ctx:t_jit_context2);
|
|
var
|
|
i:Integer;
|
|
imm:Int64;
|
|
stack,new:TRegValue;
|
|
begin
|
|
//lea rsp,[rsp-len]
|
|
//mov [rsp],reg
|
|
|
|
with ctx.builder do
|
|
begin
|
|
stack:=r_tmp0;
|
|
|
|
if is_memory(ctx.din) then
|
|
begin
|
|
build_lea(ctx,1,r_tmp0);
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
new:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
|
|
movq(new,[r_tmp0]);
|
|
end else
|
|
if (ctx.din.Operand[1].ByteCount<>0) then
|
|
begin
|
|
imm:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,1,imm);
|
|
|
|
new:=new_reg_size(r_tmp1,ctx.din.Operand[1].Size);
|
|
|
|
movi(new,imm);
|
|
end else
|
|
if is_preserved(ctx.din) then
|
|
begin
|
|
new:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq(new,[r_thrd+i]);
|
|
end else
|
|
begin
|
|
new:=new_reg(ctx.din.Operand[1]);
|
|
end;
|
|
|
|
//sign extend
|
|
case new.ASize of
|
|
os8:
|
|
begin
|
|
ctx.builder._RR(movsx8_desc,new,new,os64);
|
|
new:=new_reg_size(new,os64);
|
|
end;
|
|
os32:
|
|
begin
|
|
ctx.builder._RR(movsxd_desc,new,new,os64);
|
|
new:=new_reg_size(new,os64);
|
|
end
|
|
else;
|
|
end;
|
|
|
|
i:=GetFrameOffset(rsp);
|
|
movq(stack,[r_thrd+i]);
|
|
leaq(stack,[stack-OPERAND_BYTES[new.ASize]]);
|
|
movq([r_thrd+i],stack);
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
movq([stack],new);
|
|
end;
|
|
end;
|
|
|
|
procedure op_pushfq(var ctx:t_jit_context2);
|
|
var
|
|
i:Integer;
|
|
mem_size:TOperandSize;
|
|
stack,new:TRegValue;
|
|
begin
|
|
//lea rsp,[rsp-len]
|
|
//mov [rsp],rflags
|
|
|
|
with ctx.builder do
|
|
begin
|
|
stack:=r_tmp0;
|
|
|
|
new:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
pushfq(mem_size);
|
|
pop(new);
|
|
|
|
i:=GetFrameOffset(rsp);
|
|
movq(stack,[r_thrd+i]);
|
|
leaq(stack,[stack-OPERAND_BYTES[new.ASize]]);
|
|
movq([r_thrd+i],stack);
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
movq([stack],new);
|
|
end;
|
|
end;
|
|
|
|
procedure op_pop(var ctx:t_jit_context2);
|
|
var
|
|
i:Integer;
|
|
new,stack:TRegValue;
|
|
begin
|
|
//mov reg,[rsp]
|
|
//lea rsp,[rsp+len]
|
|
|
|
with ctx.builder do
|
|
begin
|
|
stack:=r_tmp0;
|
|
|
|
i:=GetFrameOffset(rsp);
|
|
movq(stack,[r_thrd+i]);
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
if is_memory(ctx.din) then
|
|
begin
|
|
new:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
|
|
movq(new,[stack]);
|
|
|
|
build_lea(ctx,1,r_tmp0);
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
movq([r_tmp0],new);
|
|
end else
|
|
if is_preserved(ctx.din) then
|
|
begin
|
|
new:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
|
|
movq(new,[stack]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],new);
|
|
end else
|
|
begin
|
|
new:=new_reg(ctx.din.Operand[1]);
|
|
|
|
movq(new,[stack]);
|
|
end;
|
|
|
|
i:=GetFrameOffset(rsp);
|
|
|
|
seto(al);
|
|
lahf;
|
|
addi8(os64,[r_thrd+i],OPERAND_BYTES[new.ASize]);
|
|
addi(al,127);
|
|
sahf;
|
|
end;
|
|
end;
|
|
|
|
procedure op_syscall(var ctx:t_jit_context2);
|
|
begin
|
|
ctx.add_forward_point(nil_link,ctx.ptr_curr);
|
|
ctx.add_forward_point(nil_link,ctx.ptr_next);
|
|
//
|
|
op_set_rax_imm(ctx,Int64(ctx.ptr_next));
|
|
//
|
|
ctx.builder.call_far(@jit_syscall); //syscall dispatcher
|
|
end;
|
|
|
|
procedure op_int(var ctx:t_jit_context2);
|
|
var
|
|
i:Integer;
|
|
id:Byte;
|
|
begin
|
|
i:=ctx.din.Operand[1].ByteCount;
|
|
Assert(i=1);
|
|
id:=PByte(ctx.code)[i];
|
|
|
|
case id of
|
|
$41: //assert?
|
|
begin
|
|
//
|
|
ctx.builder.call_far(@jit_assert); //TODO error dispatcher
|
|
end;
|
|
|
|
$44: //system error?
|
|
begin
|
|
//
|
|
ctx.builder.call_far(@jit_system_error); //TODO error dispatcher
|
|
ctx.trim:=True;
|
|
end;
|
|
else
|
|
begin
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure op_ud2(var ctx:t_jit_context2);
|
|
begin
|
|
//exit proc?
|
|
ctx.builder.call_far(@jit_exit_proc); //TODO exit dispatcher
|
|
ctx.trim:=True;
|
|
end;
|
|
|
|
procedure op_iretq(var ctx:t_jit_context2);
|
|
begin
|
|
//exit proc?
|
|
ctx.builder.call_far(@jit_exit_proc); //TODO exit dispatcher
|
|
ctx.trim:=True;
|
|
end;
|
|
|
|
procedure op_hlt(var ctx:t_jit_context2);
|
|
begin
|
|
//stop thread?
|
|
ctx.builder.call_far(@jit_exit_proc); //TODO exit dispatcher
|
|
end;
|
|
|
|
procedure op_cpuid(var ctx:t_jit_context2);
|
|
begin
|
|
ctx.builder.call_far(@jit_cpuid); //TODO CPUID
|
|
end;
|
|
|
|
procedure op_rdtsc(var ctx:t_jit_context2);
|
|
begin
|
|
add_orig(ctx);
|
|
op_save_rax(ctx,ctx.builder.rax);
|
|
end;
|
|
|
|
procedure op_nop(var ctx:t_jit_context2);
|
|
begin
|
|
//align?
|
|
end;
|
|
|
|
const
|
|
test_desc:t_op_type=(op:$85;index:0);
|
|
bt_desc_imm:t_op_type=(op:$0FBA;index:4);
|
|
|
|
procedure _op_rep_cmps(var ctx:t_jit_context2;dflag:Integer);
|
|
var
|
|
op:DWORD;
|
|
size:TOperandSize;
|
|
|
|
link_start:t_jit_i_link;
|
|
link___end:t_jit_i_link;
|
|
|
|
link_jmp0:t_jit_i_link;
|
|
link_jmp1:t_jit_i_link;
|
|
begin
|
|
//rdi,rsi
|
|
//prefix $67 TODO
|
|
|
|
op:=$A7;
|
|
case ctx.din.OpCode.Suffix of
|
|
OPSx_b:
|
|
begin
|
|
size:=os8;
|
|
op:=$A6;
|
|
end;
|
|
OPSx_w:size:=os16;
|
|
OPSx_d:size:=os32;
|
|
OPSx_q:size:=os64;
|
|
else;
|
|
Assert(False);
|
|
end;
|
|
|
|
//(r_tmp0)rax <-> rdi
|
|
//(r_tmp1)r14 <-> rsi
|
|
with ctx.builder do
|
|
begin
|
|
|
|
link_jmp0:=nil_link;
|
|
link_jmp1:=nil_link;
|
|
|
|
link_start:=ctx.builder.get_curr_label.after;
|
|
|
|
//repeat
|
|
seto(al);
|
|
lahf;
|
|
_RR(test_desc,rcx,rcx,os0);
|
|
link_jmp0:=jcc(OPSc_z,nil_link,os8);
|
|
addi(al,127);
|
|
sahf;
|
|
|
|
movq(r_tmp0,rsi);
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
movq(r_tmp1,r_tmp0);
|
|
|
|
movq(r_tmp0,rdi);
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
xchgq(rdi,r_tmp0);
|
|
xchgq(rsi,r_tmp1);
|
|
|
|
_O(op,Size);
|
|
|
|
xchgq(rdi,r_tmp0);
|
|
xchgq(rsi,r_tmp1);
|
|
|
|
leaq(rcx,[rcx-1]);
|
|
|
|
if (dflag=0) then
|
|
begin
|
|
leaq(rdi,[rdi+OPERAND_BYTES[size]]);
|
|
leaq(rsi,[rsi+OPERAND_BYTES[size]]);
|
|
end else
|
|
begin
|
|
leaq(rdi,[rdi-OPERAND_BYTES[size]]);
|
|
leaq(rsi,[rsi-OPERAND_BYTES[size]]);
|
|
end;
|
|
|
|
if (ifPrefixRepE in ctx.din.Flags) then
|
|
begin
|
|
//if a[i]<>b[i] then exit
|
|
link_jmp1:=jcc(OPSc_nz,nil_link,os8);
|
|
end else
|
|
if (ifPrefixRepNe in ctx.din.Flags) then
|
|
begin
|
|
//if a[i]=b[i] then exit
|
|
link_jmp1:=jcc(OPSc_z,nil_link,os8);
|
|
end;
|
|
|
|
//until
|
|
jmp(link_start,os8);
|
|
|
|
//exit1
|
|
addi(al,127);
|
|
sahf;
|
|
|
|
//exit2
|
|
|
|
link___end:=ctx.builder.get_curr_label.before; //exit1
|
|
|
|
link_jmp0._label:=link___end;
|
|
|
|
link___end:=link___end.after; //exit2
|
|
|
|
link_jmp1._label:=link___end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure op_rep_cmps(var ctx:t_jit_context2);
|
|
var
|
|
link_jmp0:t_jit_i_link;
|
|
link_jmp1:t_jit_i_link;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
|
|
//get d flag
|
|
pushfq(os64);
|
|
_MI8(bt_desc_imm,os64,[rsp],10); //bt rax, 10
|
|
|
|
link_jmp0:=jcc(OPSc_b,nil_link,os8);
|
|
|
|
popfq(os64);
|
|
_op_rep_cmps(ctx,0);
|
|
|
|
link_jmp1:=jmp(nil_link,os8);
|
|
|
|
link_jmp0._label:=ctx.builder.get_curr_label.after;
|
|
|
|
popfq(os64);
|
|
_op_rep_cmps(ctx,1);
|
|
|
|
link_jmp1._label:=ctx.builder.get_curr_label.after;
|
|
|
|
end;
|
|
end;
|
|
|
|
///
|
|
|
|
procedure _op_rep_stos(var ctx:t_jit_context2;dflag:Integer);
|
|
var
|
|
i:Integer;
|
|
size:TOperandSize;
|
|
|
|
new:TRegValue;
|
|
|
|
link_start:t_jit_i_link;
|
|
link___end:t_jit_i_link;
|
|
|
|
link_jmp0:t_jit_i_link;
|
|
begin
|
|
//rdi,rsi
|
|
//prefix $67 TODO
|
|
|
|
case ctx.din.OpCode.Suffix of
|
|
OPSx_b:size:=os8;
|
|
OPSx_w:size:=os16;
|
|
OPSx_d:size:=os32;
|
|
OPSx_q:size:=os64;
|
|
else;
|
|
Assert(False);
|
|
end;
|
|
|
|
//(r_tmp0)rax <-> rdi
|
|
//(r_tmp1)r14 <-> rax
|
|
with ctx.builder do
|
|
begin
|
|
|
|
link_jmp0:=nil_link;
|
|
|
|
new:=new_reg_size(r_tmp1,size);
|
|
|
|
i:=GetFrameOffset(rax);
|
|
movq(new,[r_thrd+i]);
|
|
|
|
link_start:=ctx.builder.get_curr_label.after;
|
|
|
|
//repeat
|
|
seto(al);
|
|
lahf;
|
|
_RR(test_desc,rcx,rcx,os0);
|
|
link_jmp0:=jcc(OPSc_z,nil_link,os8);
|
|
addi(al,127);
|
|
sahf;
|
|
|
|
movq(r_tmp0,rdi);
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
movq([r_tmp0],new);
|
|
|
|
leaq(rcx,[rcx-1]);
|
|
|
|
if (dflag=0) then
|
|
begin
|
|
leaq(rdi,[rdi+OPERAND_BYTES[size]]);
|
|
end else
|
|
begin
|
|
leaq(rdi,[rdi-OPERAND_BYTES[size]]);
|
|
end;
|
|
|
|
//until
|
|
jmp(link_start,os8);
|
|
|
|
//exit1
|
|
sahf;
|
|
|
|
//exit2
|
|
|
|
link___end:=ctx.builder.get_curr_label.before; //exit1
|
|
|
|
link_jmp0._label:=link___end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure op_rep_stos(var ctx:t_jit_context2);
|
|
var
|
|
link_jmp0:t_jit_i_link;
|
|
link_jmp1:t_jit_i_link;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
|
|
//get d flag
|
|
pushfq(os64);
|
|
_MI8(bt_desc_imm,os64,[rsp],10); //bt rax, 10
|
|
|
|
link_jmp0:=jcc(OPSc_b,nil_link,os8);
|
|
|
|
popfq(os64);
|
|
_op_rep_stos(ctx,0);
|
|
|
|
link_jmp1:=jmp(nil_link,os8);
|
|
|
|
link_jmp0._label:=ctx.builder.get_curr_label.after;
|
|
|
|
popfq(os64);
|
|
_op_rep_stos(ctx,1);
|
|
|
|
link_jmp1._label:=ctx.builder.get_curr_label.after;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure init_cbs;
|
|
begin
|
|
jit_cbs[OPPnone,OPcall,OPSnone]:=@op_call;
|
|
jit_cbs[OPPnone,OPjmp ,OPSnone]:=@op_jmp;
|
|
jit_cbs[OPPnone,OPret ,OPSnone]:=@op_ret;
|
|
|
|
jit_cbs[OPPnone,OPj__,OPSc_o ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_no ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_b ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_nb ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_z ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_nz ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_be ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_nbe]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_s ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_ns ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_p ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_np ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_l ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_nl ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_le ]:=@op_jcc;
|
|
jit_cbs[OPPnone,OPj__,OPSc_nle]:=@op_jcc;
|
|
|
|
jit_cbs[OPPnone,OPpush,OPSnone]:=@op_push;
|
|
jit_cbs[OPPnone,OPpop ,OPSnone]:=@op_pop;
|
|
|
|
jit_cbs[OPPnone,OPpushf ,OPSnone]:=@op_pushfq;
|
|
jit_cbs[OPPnone,OPpushf ,OPSx_q ]:=@op_pushfq;
|
|
//
|
|
//jit_cbs[OPpopf ,OPSnone]:=@;
|
|
//jit_cbs[OPpopf ,OPSx_q ]:=@;
|
|
|
|
jit_cbs[OPPnone,OPsyscall,OPSnone]:=@op_syscall;
|
|
jit_cbs[OPPnone,OPint ,OPSnone]:=@op_int;
|
|
jit_cbs[OPPnone,OPud2 ,OPSnone]:=@op_ud2;
|
|
|
|
jit_cbs[OPPnone,OPiret,OPSnone]:=@op_iretq;
|
|
jit_cbs[OPPnone,OPiret,OPSx_d ]:=@op_iretq;
|
|
jit_cbs[OPPnone,OPiret,OPSx_q ]:=@op_iretq;
|
|
|
|
jit_cbs[OPPnone,OPhlt ,OPSnone]:=@op_hlt;
|
|
|
|
jit_cbs[OPPnone,OPcpuid,OPSnone]:=@op_cpuid;
|
|
jit_cbs[OPPnone,OPrdtsc,OPSnone]:=@op_rdtsc;
|
|
|
|
jit_cbs[OPPnone,OPnop,OPSnone]:=@op_nop;
|
|
|
|
end;
|
|
|
|
function test_disassemble(addr:Pointer;vsize:Integer):Boolean;
|
|
var
|
|
proc:TDbgProcess;
|
|
adec:TX86AsmDecoder;
|
|
ptr,fin:Pointer;
|
|
ACodeBytes,ACode:RawByteString;
|
|
begin
|
|
Result:=True;
|
|
|
|
ptr:=addr;
|
|
fin:=addr+vsize;
|
|
|
|
proc:=TDbgProcess.Create(dm64);
|
|
adec:=TX86AsmDecoder.Create(proc);
|
|
|
|
while (ptr<fin) do
|
|
begin
|
|
adec.Disassemble(ptr,ACodeBytes,ACode);
|
|
|
|
case adec.Instr.OpCode.Opcode of
|
|
OPX_Invalid..OPX_GroupP:
|
|
begin
|
|
Result:=False;
|
|
Break;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (adec.Instr.Flags * [ifOnly32, ifOnly64, ifOnlyVex] <> []) or
|
|
is_invalid(adec.Instr) then
|
|
begin
|
|
Result:=False;
|
|
Break;
|
|
end;
|
|
|
|
end;
|
|
|
|
adec.Free;
|
|
proc.Free;
|
|
end;
|
|
|
|
procedure pick(var ctx:t_jit_context2);
|
|
begin
|
|
vm_map_lock (@g_vmspace.vm_map);
|
|
|
|
pick_locked(ctx);
|
|
|
|
vm_map_unlock(@g_vmspace.vm_map);
|
|
end;
|
|
|
|
procedure pick_locked(var ctx:t_jit_context2);
|
|
const
|
|
SCODES:array[TSimdOpcode] of Byte=(0,0,1,3,2);
|
|
MCODES:array[0..3] of RawByteString=('','0F','0F38','0F3A');
|
|
label
|
|
_next,
|
|
_build;
|
|
var
|
|
addr:Pointer;
|
|
ptr:Pointer;
|
|
|
|
links:t_jit_context2.t_forward_links;
|
|
entry_link:Pointer;
|
|
|
|
proc:TDbgProcess;
|
|
adec:TX86AsmDecoder;
|
|
ACodeBytes,ACode:RawByteString;
|
|
|
|
cb:t_jit_cb;
|
|
|
|
link_new :t_jit_i_link;
|
|
link_curr:t_jit_i_link;
|
|
link_next:t_jit_i_link;
|
|
|
|
node,node_curr,node_next:p_jit_instruction;
|
|
begin
|
|
if (ctx.max=QWORD(-1)) then
|
|
begin
|
|
//dont scan rip relative
|
|
ctx.max:=0;
|
|
end else
|
|
begin
|
|
ctx.max:=QWORD(ctx.max_forward_point);
|
|
end;
|
|
|
|
Writeln(' ctx.text_start:0x',HexStr(ctx.text_start,16));
|
|
Writeln(' ctx.max :0x',HexStr(ctx.max,16));
|
|
Writeln(' ctx.text___end:0x',HexStr(ctx.text___end,16));
|
|
Writeln(' ctx.map____end:0x',HexStr(ctx.map____end,16));
|
|
|
|
links:=Default(t_jit_context2.t_forward_links);
|
|
addr:=nil;
|
|
|
|
if not ctx.fetch_forward_point(links,addr) then
|
|
begin
|
|
ctx.Free;
|
|
Exit;
|
|
end;
|
|
|
|
ctx.trim:=False;
|
|
|
|
entry_link:=addr;
|
|
|
|
ctx.builder._new_chunk(QWORD(entry_link));
|
|
|
|
//debug
|
|
ctx.builder.call_far(@jit_before_start);
|
|
//debug
|
|
|
|
ptr:=addr;
|
|
|
|
proc:=TDbgProcess.Create(dm64);
|
|
adec:=TX86AsmDecoder.Create(proc);
|
|
|
|
while True do
|
|
begin
|
|
|
|
if ((pmap_get_raw(QWORD(ptr)) and PAGE_PROT_EXECUTE)=0) then
|
|
begin
|
|
//writeln('not excec:0x',HexStr(ptr));
|
|
ctx.builder.ud2;
|
|
goto _next; //trim
|
|
end;
|
|
|
|
ctx.ptr_curr:=ptr;
|
|
|
|
adec.Disassemble(ptr,ACodeBytes,ACode);
|
|
|
|
case adec.Instr.OpCode.Opcode of
|
|
OPX_Invalid..OPX_GroupP:
|
|
begin
|
|
//invalid
|
|
//writeln('invalid:0x',HexStr(ctx.ptr_curr));
|
|
ctx.builder.ud2;
|
|
goto _next; //trim
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (adec.Instr.Flags * [ifOnly32, ifOnly64, ifOnlyVex] <> []) or
|
|
is_invalid(adec.Instr) then
|
|
begin
|
|
//writeln('invalid:0x',HexStr(ctx.ptr_curr));
|
|
ctx.builder.ud2;
|
|
goto _next; //trim
|
|
end;
|
|
|
|
if print_asm then
|
|
begin
|
|
Writeln('original------------------------':32,' ','0x',HexStr(ptr-adec.Disassembler.CodeIdx));
|
|
Writeln(ACodeBytes:32,' ',ACode);
|
|
Writeln('original------------------------':32,' ','0x',HexStr(ptr));
|
|
end;
|
|
|
|
ctx.ptr_next:=ptr;
|
|
|
|
ctx.code:=ctx.ptr_curr;
|
|
|
|
ctx.dis:=adec.Disassembler;
|
|
ctx.din:=adec.Instr;
|
|
|
|
if is_rep_prefix(ctx.din) then
|
|
begin
|
|
cb:=nil;
|
|
if (ctx.din.OpCode.Prefix=OPPnone) then
|
|
begin
|
|
case ctx.din.OpCode.Opcode of
|
|
OPcmps:cb:=@op_rep_cmps;
|
|
OPstos:cb:=@op_rep_stos;
|
|
else;
|
|
end;
|
|
end;
|
|
end else
|
|
begin
|
|
cb:=jit_cbs[ctx.din.OpCode.Prefix,ctx.din.OpCode.Opcode,ctx.din.OpCode.Suffix];
|
|
end;
|
|
|
|
if (cb=nil) then
|
|
begin
|
|
Writeln('original------------------------':32,' ','0x',HexStr(ptr-adec.Disassembler.CodeIdx));
|
|
Writeln(ACodeBytes:32,' ',ACode);
|
|
Writeln('original------------------------':32,' ','0x',HexStr(ptr));
|
|
|
|
Writeln('Unhandled jit:',
|
|
ctx.din.OpCode.Prefix,' ',
|
|
ctx.din.OpCode.Opcode,' ',
|
|
ctx.din.OpCode.Suffix,' ',
|
|
ctx.din.Operand[1].Size,' ',
|
|
ctx.din.Operand[2].Size);
|
|
Writeln('MIndex=',ctx.dis.ModRM.Index,' ',
|
|
'SOpcode=',ctx.dis.SimdOpcode,':',SCODES[ctx.dis.SimdOpcode],' ',
|
|
'mm=',ctx.dis.mm,':',MCODES[ctx.dis.mm and 3]);
|
|
Assert(false);
|
|
end;
|
|
|
|
link_curr:=ctx.builder.get_curr_label.after;
|
|
node_curr:=link_curr._node;
|
|
|
|
cb(ctx);
|
|
|
|
link_next:=ctx.builder.get_curr_label.after;
|
|
node_next:=link_next._node;
|
|
|
|
{
|
|
if (node_curr<>node_next) and
|
|
(node_curr<>nil) then
|
|
begin
|
|
node:=TAILQ_NEXT(node_curr,@node_curr^.link);
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
|
|
if not test_disassemble(@node^.AData,node^.ASize) then
|
|
begin
|
|
print_asm:=True;
|
|
Break;
|
|
end;
|
|
|
|
|
|
node:=TAILQ_NEXT(node,@node^.link);
|
|
end;
|
|
end;
|
|
}
|
|
|
|
if print_asm then
|
|
if (node_curr<>node_next) and
|
|
(node_curr<>nil) then
|
|
begin
|
|
node:=TAILQ_NEXT(node_curr,@node_curr^.link);
|
|
|
|
Writeln('recompiled----------------------':32,' ','');
|
|
while (node<>nil) do
|
|
begin
|
|
|
|
print_disassemble(@node^.AData,node^.ASize);
|
|
|
|
|
|
node:=TAILQ_NEXT(node,@node^.link);
|
|
end;
|
|
Writeln('recompiled----------------------':32,' ','');
|
|
end;
|
|
|
|
//debug
|
|
op_set_rax_imm(ctx,$FACEADD7);
|
|
op_set_rax_imm(ctx,Int64(ctx.ptr_next));
|
|
op_set_rax_imm(ctx,$FACEADDE);
|
|
//debug
|
|
|
|
begin
|
|
link_next:=ctx.builder.get_curr_label.after;
|
|
|
|
ctx.add_label(ctx.ptr_curr,
|
|
ctx.ptr_next,
|
|
link_curr,
|
|
link_next);
|
|
end;
|
|
|
|
if (links.root<>nil) then
|
|
begin
|
|
links.Resolve(link_curr);
|
|
links.root:=nil;
|
|
end;
|
|
|
|
if (entry_link<>nil) then
|
|
begin
|
|
ctx.add_entry_point(entry_link,link_curr);
|
|
entry_link:=nil;
|
|
end;
|
|
|
|
begin
|
|
link_new:=ctx.get_link(ptr);
|
|
|
|
if (link_new<>nil_link) then
|
|
begin
|
|
ctx.builder.jmp(link_new);
|
|
//Writeln('jmp next:0x',HexStr(ptr));
|
|
goto _next; //trim
|
|
end;
|
|
end;
|
|
|
|
if exist_entry(ptr) then
|
|
begin
|
|
op_set_rax_imm(ctx,Int64(ptr));
|
|
//
|
|
op_jmp_dispatcher(ctx);
|
|
//
|
|
goto _next; //trim
|
|
end;
|
|
|
|
if ctx.trim then
|
|
begin
|
|
_next:
|
|
|
|
ctx.trim:=False;
|
|
|
|
//close chunk
|
|
ctx.builder._end_chunk(QWORD(ctx.ptr_next));
|
|
|
|
repeat
|
|
|
|
if not ctx.fetch_forward_point(links,addr) then
|
|
begin
|
|
goto _build;
|
|
end;
|
|
|
|
link_new:=ctx.get_link(addr);
|
|
if (link_new=nil_link) then
|
|
begin
|
|
//Writeln('not found:0x',HexStr(addr));
|
|
Break;
|
|
end else
|
|
begin
|
|
links.Resolve(link_new);
|
|
links.root:=nil;
|
|
//
|
|
ctx.add_entry_point(addr,link_new);
|
|
end;
|
|
|
|
until false;
|
|
|
|
entry_link:=addr;
|
|
|
|
ctx.builder._new_chunk(QWORD(entry_link));
|
|
|
|
//debug
|
|
ctx.builder.call_far(@jit_before_start);
|
|
//debug
|
|
|
|
ptr:=addr;
|
|
end;
|
|
|
|
end;
|
|
|
|
_build:
|
|
//build blob
|
|
|
|
ctx.builder.ud2;
|
|
|
|
build(ctx);
|
|
ctx.Free;
|
|
|
|
adec.Free;
|
|
proc.Free;
|
|
end;
|
|
|
|
initialization
|
|
init_cbs;
|
|
|
|
|
|
end.
|
|
|
|
|