这是一款UWP应用。我在ARM / Release版本中遇到了这个问题。
变量指向extra_memory,其中每次在重新编译之前由protect_readwrite更改内存的保护,并且每次在执行重新编译的代码之前由protect_exec更改。基本上,extra_memory是我们重新编译代码的地方。
首先,在调用new_dynarec_init以将extra_memory的保护更改为read& write之后,out将指向extra_memory,这样我们就可以使用out作为执行重新编译代码的入口点。
new_recompile_block是执行重新编译的函数,从函数new_dyna_start调用。
extern char extra_memory[33554432];
#define BASE_ADDR ((int)(&extra_memory))
void *base_addr;
u_char *out;
void new_dynarec_init()
{
protect_readwrite();
base_addr = ((int)(&extra_memory));
out = (u_char *)base_addr;
}
int new_recompile_block(int addr)
{
//if(g_cp0_regs[CP0_COUNT_REG]==365117028) tracedebug=1;
protect_readwrite();
//the recompiling code here
......
protect_exec();
return 0;
}
void protect_readwrite()
{
#if NEW_DYNAREC == NEW_DYNAREC_ARM
PVOID addr = BASE_ADDR;
#else
PVOID addr = base_addr;
#endif
BOOL bVirPro = VirtualProtectFromApp(addr, 1 << TARGET_SIZE_2, PAGE_READWRITE, &oldProt);
oldProt = PAGE_READWRITE;
if (!bVirPro)
{
OutputDebugString("PAGE_READWRITE fail");
}
}
void protect_exec()
{
#if NEW_DYNAREC == NEW_DYNAREC_ARM
PVOID addr = BASE_ADDR;
#else
PVOID addr = base_addr;
#endif
BOOL bVirPro = VirtualProtectFromApp(addr, 1 << TARGET_SIZE_2, PAGE_EXECUTE, &oldProt);
oldProt = PAGE_EXECUTE;
if (!bVirPro)
{
OutputDebugString("PAGE_EXECUTE fail");
}
}
dynarec可以成功重新编译代码。生成代码后,PC通过&#34; mov pc,r4&#34;传递重新编译的代码块的起始地址。在函数new_dyna_start中执行重新编译的代码。变量指向重新编译的代码块,因此r4通过&#34; ldr r4,[r1]&#34;来存储out的值。
EXTERN out
;data section
extra_memory SPACE 33554432
dynarec_local SPACE 64
;code section
|.outptr_offset| DCD out-(|.outptr_pic|+8)
new_dyna_start GLOBAL_FUNCTION_BEGIN
ldr r12, =dynarec_local+28
ldr r1, |.outptr_offset|
|.outptr_pic|
add r1, pc, r1
mov r0, #0xa4000000
stmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
sub fp, r12, #28
ldr r4, [r1]
add r0, r0, #0x40
bl new_recompile_block
ldr r0, [fp, #next_interupt-dynarec_local]
ldr r10, [fp, #g_cp0_regs+36-dynarec_local] ; Count
str r0, [fp, #last_count-dynarec_local]
sub r10, r10, r0
mov pc, r4
FUNCTION_END
每次运行程序时,函数和变量的地址都会动态变化。我只拿一个正在运行的样本作为参考。
在我的测试中,在第一次重新编译过程中,生成了0x2c90字节的代码。重新编译块的起始地址是0x55577000,变量指向。 new_dyna_start的地址是0x537c1648。执行new_recompile_block时,内存地址0xE88C4FF0(0xC0000005:访问冲突执行位置0xE88C4FF0)发生访问失败。通过使用&#34; mov pc,r4&#34;,0x55577000应该已经传递给pc来执行重新编译的代码块。
每次运行应用程序时,它都会在同一地址0xE88C4FF0上崩溃。我想它与重新编译的代码或重新编译的代码无关。
在Windows 10 Mobile之前,从异常或中断处理程序返回后,ARM代码的执行将崩溃,因为在从ARM代码切换到处理程序之前,CPSR的T位被强制设置为1。 KeContextFromKframes根据this post执行此操作。是否已将此更改为允许Windows 10 Mobile中的无问题ARM代码,这一直存在争议。由于每次访问失败地址都没有改变0xE88C4FF0,我怀疑崩溃可能与此有关。
应用程序会在&#34; bl new_recompile_block&#34;之前调用KeContextFromKframes吗?如果是这样的话,应用程序会在返回new_dyna_start时崩溃。
请帮忙。