News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Newbie need advice about mixing C++ and x64

Started by ateneo, August 26, 2015, 02:59:19 AM

Previous topic - Next topic

ateneo

Well, i earlier post something like "problems with a 256 entries jump table".

Now, im using Visual Studio 2010 professional and i had set up it fine for MASM. I have made a NES emulator which you are welcomed to try if you want at www.yanese.com.. It's really done in the "C" that C++ has.

I want to emulate 8 BIT NES 6502 cpu in x64. So i have a file called "cpu.asm".
That's why i post the jump table thing, to jmp to and opcode table.

This thing about x64 dev is confusing me and getting me crazy.

I have a C++ func defined:


u8 ReadCpuMem(u16 addr)
{
u8 data;
       data = CpuMemMap.pReadMem[addr >> 12](addr);
return data;
}


"CpuMemMap" is structure holding an array of 16 function pointers. You may be asking whay that "addr >> 12", simple the 6502 can address up to 64k, so shifting by 12 gives me the correct number between 0-15 and calls the correct function.

I use it this way becouse it's easier to map memory, since this old consoles had ranges on the CPU address bus that were used in a specially way. And most of all some NES cartridags had "mappers" chips to extend limitations of memory, etc.

Anyway back to my question:

I must call the ReadCpuMem function, so what i did in cpu.asm was:


ReadCpuMem PROTO :word
...
.data
     dq BRK_IMPLIED
     dq ORA_INDIRECT_X
     dq OP_NOTFOUND
...
.code
    RunCpu PROC LEAF
            mov cx, Cpu.PC ;opcodes jump table
            call ReadCpuMem                    ;this first C++ func call it's fine (read below)
    mov Cpu.opcode, al
    inc word ptr Cpu.PC ;INC PC
    mov rcx, offset opcodes_jump
    mov rcx, [rcx + rax * 8]
    jmp rcx

        ;jump labales opcodes
         BRK_IMPLIED::
         ORA_INDIRECT_X::
        ;etc...
        LDA_INMEDIATE::
            call ResolveInmediate     ;again: read below please!!
            mov Cpu.A, al
    jmp return
       ;etc...
       return:
       
    RunCpu ENDP

    ResolveInmediate PROC LEAF
movzx rcx, Cpu.PC
call ReadCpuMem             ;HERE MY PROBLEM!!!
inc word ptr Cpu.PC
ret
    ResolveInmediate ENDP


That ResolveInmediate PROC is the emulated 6502 part. It's like saying "LDA #$05", or "load the Accumulator with inmediate 05h" Same as x86 or x64 architecture that has inmediate addressing... mov al, 05h.

That's not my point the thing i have read that a LEAF PROC can't CALL other procs?? When RunCpu PROC endsthe VS2010 debugger sends me to a full 0x00000000 and of course execution "CRASH".

The first c++ ReadCpuMem it's fine doesn't crash the app, but the second (the one inside ResolveInmediate PROC) is causing the problem.

Please be aware that im a newbie and all i can figure out is that something is going on wrong with the stack.
I have read too that "FRAME" procs can be made in x64, maybe that solves my problem making them FRAME, but i'm still to noob to make a FRAME PROC and MSDN is not the best source...

Btw, im using extern "C" and __cdecl in the functions that my c++ code calls to the .asm code.

help!!

TouEnMasm

To made thing as simple as possible you need to work with the object (compiled) of your source file.
Then you have to declare the asm proc you want to use in the c one:

int  __stdcall ReadCpuMem(WORD truc);      //

If not __stdcall,the c create a cdecl proto by defaut and cannot be found by the  c prog
You can use dumpbin /ALL to verify that the compiled name of the proc and the call are correct.
Then at compile you add the obj

Fa is a musical note to play with CL

ateneo

Quote from: ToutEnMasm on August 26, 2015, 03:28:08 AM
To made thing as simple as possible you need to work with the object (compiled) of your source file.

The .obj file is generated sucesfully and included by vs2010. Not problems with that.

Quote from: ToutEnMasm on August 26, 2015, 03:28:08 AM
Then you have to declare the asm proc you want to use in the c one:

int  __stdcall ReadCpuMem(WORD truc);      //

If not __stdcall,the c create a cdecl proto by defaut and cannot be found by the  c prog
You can use dumpbin /ALL to verify that the compiled name of the proc and the call are correct.
Then at compile you add the obj

i tryied with __stdcall, but the problem persist.
Any clue??

rrr314159

Quote from: ateneothe thing i have read that a LEAF PROC can't CALL other procs??

- I've never seen that option PROC LEAF, where is the documentation for it? I only have this JWasm documentation which doesn't mention LEAF. Still I can guess what the problem might be.

- A "leaf" function by definition is one that doesn't call any more procs. It doesn't reserve shadow space, or need to align the stack, etc. Obviously PROC LEAF must tell compiler to skip such steps, so u should only use it when it really is a leaf function. Now, when RunCpu calls ReadCpuMem, presumably there's enough room on the stack that it still works in spite of this - you get away with it. But ResolveInmediate is called from RunCpu, and then calls ReadCpuMem - 3 levels - evidently that's too many. If you don't (incorrectly) tell JWasm that RunCpu is a leaf, then ResolveInmediate will probably work, same as RunCpu works now - the one extra level will still be OK.

- No doubt, right thing to do is, don't use PROC LEAF unless it really is a leaf - apparently you can sometimes "get away with it" but it's not a good idea. Use FRAME instead, or (since there are no LOCALs) no option at all should be OK

- Sorry to have to guess like this, if u give me a link to documentation about "PROC LEAF" option be happy to review it
I am NaN ;)

TouEnMasm

With the LEAF proc ,it seems there is a mistake.
It refer to the GCC compiler.
Perhaps could you say which asm  compileryou are using ?.
This will avoid a big vast of time.
A bad thing is also to put a word in the declaration of the proto,change it to DWORD for x86
and QWORD for X64
If the word can create a misalignment of the stack.
Fa is a musical note to play with CL

qWord

ReadCpuMem is a fastcall function (stdcall is not used for x64) andyou must setup the stack corresponding. ML64 does not do that for you, thus you must do that by hand: allocate 8+4*8 byte (alignment + shadow space for register arguments) of stack space before calling the function.
    ResolveInmediate PROC
sub rsp,8+4*8
movzx rcx, Cpu.PC
call ReadCpuMem             ;HERE MY PROBLEM!!!
inc word ptr Cpu.PC
add rsp,8+4*8
ret
    ResolveInmediate ENDP


You must also correct the other PROCs (to keep the alignment). For more details see x64 Software Conventions
MREAL macros - when you need floating point arithmetic while assembling!

TouEnMasm

Fa is a musical note to play with CL