Question

I have this code block:

void CallAnyFunc(void *pfn, const std::vector<char> &arguments, CLR_DataType returnType, AnyFuncReturn &returnValue)
{
    int i4;
    float r4;
    double r8;
    long int i8;

    char* pStack;
    const char* i = arguments.empty() ? NULL : &*arguments.begin();
    const char* end = i + arguments.size();

    // Reserve the space on the stack
    // This is equivalent (in some sense) to 'push' all the parameters into the stack.
    // NOTE: Don't just subtract the stack pointer, better to call _alloca, because it also takes
    // care of ensuring all the consumed memory pages are accessible
#ifdef PLATFORM_WINDOWS
    _alloca(arguments.size());
#else
    alloca(arguments.size());
#endif

    _asm {
        mov pStack, esp
    };

    // Copy all the parameters into the stack
    // NOTE: Don't use the memcpy function. Because the call to it
    // will overwrite the stack (which we're currently building)
    while (i != end)
        *pStack++ = *i++;

    switch (returnType)
    {
        case DATATYPE_R4:
        {
            // Call your function
            _asm {
                call pfn
                fstp r4
            }

            returnValue.r4 = r4;
        } break;

        case DATATYPE_R8:
        {
            // Call your function
            _asm {
                call pfn
                fstp r8
            }

            returnValue.r8 = r8;
        } break;

        case DATATYPE_U8:
        case DATATYPE_I8:
        {
            // Call your function
            _asm {
                call pfn
                mov i8, eax
            }

            returnValue.i8 = i8;
        } break;

        default:
        {
            _asm {
                call pfn
                mov i4, eax
            };

            returnValue.i4 = i4;
        }
    }
}

Basically it is a bridge into calling CLR micro dot net.

When I compile with gcc provided with xcode I get:

nmfi/nmf_call.cpp:153:no such instruction: `movlq %esp, -96(%rbp)'
nmfi/nmf_call.cpp:164:indirect call without `*'
nmfi/nmf_call.cpp:175:indirect call without `*'
nmfi/nmf_call.cpp:187:indirect call without `*'
nmfi/nmf_call.cpp:190:no such instruction: `movlq %eax, -88(%rbp)'
nmfi/nmf_call.cpp:197:indirect call without `*'

where line 153 = line after mov pStack, esp and line 190 = line after returnValue.i8 = i8 which is prob actually mov i8, eax

...

this code use to work just fine. I'm figuring the change is because of x86_64 but am having problems figuring out how to write the "mov" properly so that it can be assembled.

...

related compiler flags:

CC := g++
CFLAGS := -c -DLITTLE_ENDIAN=1 -DGCC_V4_2 -fasm-blocks  \
        -DVERSION_MAJOR="4" -DVERSION_MINOR="2" -DVERSION_BUILD="1" -DVERSION_REVISION="0" \
        -DOEMSYSTEMINFOSTRING='"OSXBOI"'

# -DMAC -fvisibility=hidden -fvisibility-inlines-hidden
AR := ar
ARFLAGS := rs

ifeq (,$(findstring Debug,$(CONFIG)))
    CFLAGS += -O3 -DNDEBUG
else
    CFLAGS += -g -D_DEBUG
endif

any hints?

Here is the revised code, this is untested, but it compiles.

void CallAnyFunc(void *_pfn, const std::vector<char> &arguments, CLR_DataType returnType, AnyFuncReturn &returnValue)
{
    int i4;
    float r4;
    double r8;
    long int i8;
    typedef void (*PFN)();
    PFN pfn = (PFN)_pfn;

    char* pStack;
    const char* i = arguments.empty() ? NULL : &*arguments.begin();
    const char* end = i + arguments.size();

    // Reserve the space on the stack
    // This is equivalent (in some sense) to 'push' all the parameters into the stack.
    // NOTE: Don't just subtract the stack pointer, better to call _alloca, because it also takes
    // care of ensuring all the consumed memory pages are accessible
#ifdef PLATFORM_WINDOWS
    _alloca(arguments.size());
#else
    alloca(arguments.size());
#endif

#ifdef X86_64
    _asm {
        mov pStack, rsp
    };
#else
    _asm {
        mov pStack, esp
    };
#endif

    // Copy all the parameters into the stack
    // NOTE: Don't use the memcpy function. Because the call to it
    // will overwrite the stack (which we're currently building)
    while (i != end)
        *pStack++ = *i++;

    switch (returnType)
    {
        case DATATYPE_R4:
        {
            // Call your function
            _asm {
                call *pfn
                fstp r4
            }

            returnValue.r4 = r4;
        } break;

        case DATATYPE_R8:
        {
            // Call your function
            _asm {
                call *pfn
                fstp r8
            }

            returnValue.r8 = r8;
        } break;

        case DATATYPE_U8:
        case DATATYPE_I8:
        {
#ifdef X86_64
            // Call your function
            _asm {
                call *pfn
                mov i8, rax
            }
#else
            _asm {
                call *pfn
                mov i8, eax
            }
#endif
            returnValue.i8 = i8;
        } break;

        default:
        {
#ifdef X86_64
            // Call your function
            _asm {
                call *pfn
                mov i4, eax
            }
#else
            _asm {
                call *pfn
                mov i4, eax
            }
#endif

            returnValue.i4 = i4;
        }
    }
}
Was it helpful?

Solution

If you're building 64-bit code the size of a pointer and long int will both be 64 bits. You'll probably want to use rsp rather than esp for the pointer, in order to get all bits of the address.

For the i8 variable you have some options: keep it as an long int (or better yet, int64_t) and use rax instead of eax. Or make it an int32_t and keep using eax.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top