动态生成的代码在错误的地址中执行

这是一个UWP应用程序。 我在ARM / Release版本中遇到此问题。

变量指向extra_memory,其中每次在重新编译之前由protect_readwrite更改内存的保护,并且每次在执行重新编译的代码之前由protect_exec更改。 基本上extra_memory是我们重新编译代码的地方。

首先,在调用new_dynarec_init以将extra_memory的保护更改为读取和写入之后,输出指向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通过函数new_dyna_start中的“mov pc,r4”传递重新编译的代码块的起始地址,以执行重新编译的代码。 变量指向重新编译的代码块,因此r4通过“ldr r4,[r1]”存储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字节的代码。 重新编译块的起始地址是变量out指向的0x55577000。 new_dyna_start的地址是0x537c1648。 执行new_recompile_block时,内存地址0xE88C4FF0(0xC0000005:访问冲突执行位置0xE88C4FF0)发生访问失败。 通过使用“mov pc,r4”,0x55​​577000应该已经传递给pc来执行重新编译的代码块。

每次我运行应用程序时,它都会在同一地址0xE88C4FF0上崩溃。 我想这与重新编译的代码或重新编译的代码无关。

在Windows 10 Mobile之前,从exception或中断处理程序返回后,ARM代码的执行将崩溃,因为在从ARM代码切换到处理程序之前,CPSR的T位被强制设置为1。 KeContextFromKframes根据这篇文章做到这一点 。 是否已将此更改为允许Windows 10 Mobile中无问题的ARM代码,这一直存在争议。 由于每次访问失败地址都没有改变0xE88C4FF0,我怀疑崩溃可能与此有关。

应用程序会在“bl new_recompile_block”之前调用KeContextFromKframes吗? 如果是这种情况,应用程序将在返回new_dyna_start时崩溃。

请帮忙。

好像是| .outptr_offset | DCD out-(| .outptr_pic | +8)根本不起作用,这导致r1存储指令“stmia r12,{r4,r5,r6,r7,r8,r9,sl,fp,lr}”的地址。

删除| .outptr_offset |的定义。 将变量的地址直接加载到r1可以解决问题。 工作代码在这里。

 new_dyna_start GLOBAL_FUNCTION_BEGIN ldr r12, =dynarec_local+28 ldr r1, =out ......