Assembly allocated memory pointer automatically changed to 0xffffffff in an UWP C++ project

0

I am porting Mupen64plus to UWP. For good performance, I have to port the dynamic recompiler. So I rewrote the file linker_arm.s using MS grammar and gets the project built. But the pointers out and base_addr are automatically changed to 0xffffffff when the nearby variables are modified in new_dynarec_init, which I can see from the watch window while running the release version of the app.

This is the code for allocating space and declaring the variables.

    GLOBAL_VARIABLE extra_memory
    GLOBAL_VARIABLE dynarec_local
    GLOBAL_VARIABLE next_interupt
    GLOBAL_VARIABLE cycle_count
    GLOBAL_VARIABLE last_count
    GLOBAL_VARIABLE pending_exception
    GLOBAL_VARIABLE pcaddr
    GLOBAL_VARIABLE stop
    GLOBAL_VARIABLE invc_ptr
    GLOBAL_VARIABLE address
    GLOBAL_VARIABLE readmem_dword
    GLOBAL_VARIABLE cpu_dword
    GLOBAL_VARIABLE cpu_word
    GLOBAL_VARIABLE cpu_hword
    GLOBAL_VARIABLE cpu_byte
    GLOBAL_VARIABLE FCR0
    GLOBAL_VARIABLE FCR31
    GLOBAL_VARIABLE reg
    GLOBAL_VARIABLE hi
    GLOBAL_VARIABLE lo
    GLOBAL_VARIABLE g_cp0_regs
    GLOBAL_VARIABLE reg_cop1_simple
    GLOBAL_VARIABLE reg_cop1_double
    GLOBAL_VARIABLE rounding_modes
    GLOBAL_VARIABLE branch_target
    GLOBAL_VARIABLE aPC
    GLOBAL_VARIABLE fake_pc
    GLOBAL_VARIABLE ram_offset
    GLOBAL_VARIABLE mini_ht
    GLOBAL_VARIABLE restore_candidate
    GLOBAL_VARIABLE memory_map

    AREA    |.bbs|,DATA,READWRITE,ALIGN=12

padding           DCD   0
dyna_mem          SPACE     33554432+64+4+4+4+4+4+4+4+4+8+8+4+2+2+4+4+256+8+8+128+128+128+16+4+4+132+4+256+512+4194304
                  MAP   dyna_mem
extra_memory      FIELD 33554432
dynarec_local     FIELD 64
next_interupt     FIELD 4
cycle_count       FIELD 4
last_count        FIELD 4
pending_exception FIELD 4
pcaddr            FIELD 4
stop              FIELD 4
invc_ptr          FIELD 4
address           FIELD 4
readmem_dword     FIELD 8
cpu_dword         FIELD 8
cpu_word          FIELD 4
cpu_hword         FIELD 2
cpu_byte          FIELD 2 ;1 byte free
FCR0              FIELD 4
FCR31             FIELD 4
reg               FIELD 256
hi                FIELD 8
lo                FIELD 8
g_cp0_regs        FIELD 128
reg_cop1_simple   FIELD 128
reg_cop1_double   FIELD 128
rounding_modes    FIELD 16
branch_target     FIELD 4
aPC               FIELD 4
fake_pc           FIELD 132
ram_offset        FIELD 4
mini_ht           FIELD 256
restore_candidate FIELD 512
memory_map        FIELD 4194304

This is the function where it automatically changes out and base_addr to 0xffffffff. When memset(mini_ht, -1, sizeof(mini_ht)); is executed out, base_addr is changed to 0xffffffff. When memory_map[n] = ((u_int)g_rdram - 0x80000000) >> 2; is about to be executed, out is changed to 0xffffffff.

void new_dynarec_init()
{
    DebugMessage(M64MSG_INFO, "Init new dynarec");
    protect_readwrite();
    const DWORD size = 100 + 1;
    WCHAR chErrMsg[101];
    DWORD dwErr = GetLastError();
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), chErrMsg, size, NULL);
    char mbcErrMsg[300];
    UnicodeToMByte(chErrMsg, mbcErrMsg, 300);
    DebugMessage(M64MSG_INFO, "new_dynarec_init(): %s", mbcErrMsg);
    base_addr = ((int)(&extra_memory));
    out = (u_char *)base_addr;
    rdword = &readmem_dword;
    fake_pc.f.r.rs = (long long int *)&readmem_dword;
    fake_pc.f.r.rt = (long long int *)&readmem_dword;
    fake_pc.f.r.rd = (long long int *)&readmem_dword;
    int n;
    for (n = 0x80000; n < 0x80800; n++)
        invalid_code[n] = 1;
    for (n = 0; n < 65536; n++)
        hash_table[n][0] = hash_table[n][2] = -1;
    memset(mini_ht, -1, sizeof(mini_ht));
    memset(restore_candidate, 0, sizeof(restore_candidate));
    copy = shadow;
    expirep = 16384; // Expiry pointer, +2 blocks
    pending_exception = 0;
    literalcount = 0;
#ifdef HOST_IMM8
    // Copy this into local area so we don't have to put it in every literal     pool
    invc_ptr = invalid_code;
#endif
    stop_after_jal = 0;
    // TLB
    using_tlb = 0;
    for (n = 0; n < 524288; n++) // 0 .. 0x7FFFFFFF
        memory_map[n] = -1;
    for (n = 524288; n < 526336; n++) // 0x80000000 .. 0x807FFFFF
        memory_map[n] = ((u_int)g_rdram - 0x80000000) >> 2;
    for (n = 526336; n < 1048576; n++) // 0x80800000 .. 0xFFFFFFFF
        memory_map[n] = -1;
    for (n = 0; n < 0x8000; n++) { // 0 .. 0x7FFFFFFF
        writemem[n] = write_nomem_new;
        writememb[n] = write_nomemb_new;
        writememh[n] = write_nomemh_new;
        writememd[n] = write_nomemd_new;
        readmem[n] = read_nomem_new;
        readmemb[n] = read_nomemb_new;
        readmemh[n] = read_nomemh_new;
        readmemd[n] = read_nomemd_new;
    }
    for (n = 0x8000; n < 0x8080; n++) { // 0x80000000 .. 0x807FFFFF
        writemem[n] = write_rdram_new;
        writememb[n] = write_rdramb_new;
        writememh[n] = write_rdramh_new;
        writememd[n] = write_rdramd_new;
    }
    for (n = 0xC000; n < 0x10000; n++) { // 0xC0000000 .. 0xFFFFFFFF
        writemem[n] = write_nomem_new;
        writememb[n] = write_nomemb_new;
        writememh[n] = write_nomemh_new;
        writememd[n] = write_nomemd_new;
        readmem[n] = read_nomem_new;
        readmemb[n] = read_nomemb_new;
        readmemh[n] = read_nomemh_new;
        readmemd[n] = read_nomemd_new;
    }
    tlb_hacks();
    arch_init();
}

The memory pointed to by out is firstly given read and write permissions with below function, which might relates to this issue, but I am not sure.

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");
    }
}

The declarations of out and base_addr are as below.

void *base_addr;
u_char *out;

Basically out and base_addr both intend to point to BASE_ADDR, a label declared in assem_arm.h as below.

#define BASE_ADDR ((int)(&extra_memory))

The dyanrec would have written emitted code into the memory pointed to by out pointer. However the out pointer with value 0xffffffff causes an invalid memory access error so the app crashes. Please help.

c++
assembly
visual-studio-2015
arm
win-universal-app
asked on Stack Overflow Apr 9, 2016 by Jason Geng • edited Apr 9, 2016 by Jason Geng

1 Answer

0

It looks like what you're trying to do with the MAP and FIELD directives won't work. The field definitions aren't meant to be referenced outside of the assembly file they're used in. The linker is treating them as common symbols and allocating only 4 bytes for them in a different section, the .bss section (note the spelling). Since the means memory_map is allocated a total of 4 bytes, when you initialize the first half of the array with -1, it overwrites other variables in the .bss section, like out and base_addr.

Since there doesn't seem to be any point in using the MAP and FIELD directives to define these variables you should allocate them in the normal way:

dyna_mem
extra_memory      SPACE 33554432
dynarec_local     SPACE 64
next_interupt     SPACE 4
cycle_count       SPACE 4
last_count        SPACE 4
pending_exception SPACE 4
pcaddr            SPACE 4
stop              SPACE 4
invc_ptr          SPACE 4
address           SPACE 4
readmem_dword     SPACE 8
cpu_dword         SPACE 8
cpu_word          SPACE 4
cpu_hword         SPACE 2
cpu_byte          SPACE 2 ;1 byte free
FCR0              SPACE 4
FCR31             SPACE 4
reg               SPACE 256
hi                SPACE 8
lo                SPACE 8
g_cp0_regs        SPACE 128
reg_cop1_simple   SPACE 128
reg_cop1_double   SPACE 128
rounding_modes    SPACE 16
branch_target     SPACE 4
aPC               SPACE 4
fake_pc           SPACE 132
ram_offset        SPACE 4
mini_ht           SPACE 256
restore_candidate SPACE 512
memory_map        SPACE 4194304
answered on Stack Overflow Apr 9, 2016 by Ross Ridge

User contributions licensed under CC BY-SA 3.0