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

时间:2016-04-10 09:07:58

标签: c assembly arm win-universal-app

这是一款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;,0x55​​577000应该已经传递给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时崩溃。

请帮忙。

0 个答案:

没有答案