Overlapping memory addresses in x64 C function from PInvoke

-1

We have a PInvoke as follows:

[DllImport(DllName, EntryPoint = "ExternalName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ExternalFunction(IntPtr state, IntPtr inputData, int inputIndex, int inputLength, int tailLength);

With the C declaration as follows:

void * __cdecl ExernalName(void* state, void* inputData, int32_t inputIndex, int32_t inputLength, int32_t tailLength);

When running the .NET application as x86, it works fine. However, when run in AnyCPU on a x64 machine, the memory addresses of the function arguments are off.

For example purposes, lets assume state = 1, inputData = 2, inputIndex = 3, and inputLength = 4. Both State and InputData are void*, so they should be 8 bytes long whereas the rest should be 4 bytes.

If I set a breakpoint in the function, the value is state is 2. Lets assume the memory address of state is determined to be 0x00000008.

The memory address of inputData comes back as 0x0000000C, inputIndex as 0x00000010, and inputLength as 0x00000014.

First problem, why is the memory address of inputData 4 bytes after state and inputIndex 4 bytes after inputData? Shouldn't state and inputData be 8 bytes each?

Second problem, if I actually check the memory addresses of where the values should be, they're there, but where is 1? 1 is at 0x00000000.

How does this even happen? What are my bad assumptions and what am I doing wrong?

c#
c
pinvoke
asked on Stack Overflow Jan 12, 2017 by Josh Mackey • edited Jan 12, 2017 by John Alexiou

1 Answer

1

This is caused by calling conventions in x64 mode. Actually, there is no cdecl, no stdcall, no fastcall in x64 - these directives are ignored.

In Windows, there is the only one calling convention in x64 mode - Microsoft x64 calling convention. In this convention, the first four parameters are passed in registers rather than by stack if the size of each parameter is 1, 2, 4 or 8 bytes. At the same time, 32 bytes is reserved for debugging purpose.

It means that taking the addresses of input parameters and reading its values directly from the stack is meaningless.

Try printing the values on console instead of watching its values in the debugger. Also check the compiler options that may force using cdecl instead of default x64 calling convention.

answered on Stack Overflow Jan 12, 2017 by Andrey Nasonov

User contributions licensed under CC BY-SA 3.0