2

After trying to replace the offset keyword with __offsetof while trying to compile with Apple GCC 4.2.1 using the -fasm-blocks argument (which enables Intel style assembly syntax) inline assembly code which worked in MSVC, I get an error: Cannot apply offsetof to member function MyClass::MyFunction

class MyClass
{
    void MyFunction(void* pData)
    {

    }
};

void test()
{
    _asm
    {
        //mov eax, offset MyClass::MyFunction - this works in MSVC
        mov eax, offsetof(class MyClass, MyFunction) //error: Cannot apply offsetof to member function MyClass::MyFunction
        mov eax, __offsetof(class MyClass, MyFunction) //error: Invalid cast from type 'void (MyClass::*)(void*)' to type size_t
    };
}


Can somebody please tell me, what should I do? It seems that the whole structure of the application I'm porting is based on this damn offset macro...

Ryan
  • 1,451
  • 2
  • 27
  • 36
  • What is the address of the member function used for? – Xeo Jun 03 '11 at 12:50
  • Well, it is stored in a C++ variable and is called from another inline assembly blocks when needed... Presonally, I would never even think of implementing something so ugly and perverse. – Ryan Jun 03 '11 at 12:57
  • Do you have to hardcode it in assembly? – Xeo Jun 03 '11 at 13:00
  • Well, if there is absolutely no other way, I would have to rewrite all this logic, but I really hope there is an easier solution... – Ryan Jun 03 '11 at 13:03
  • Can you calculate the offset in C++ and store it in a local variable which you access from the ASM code? – David Winant Jun 03 '11 at 13:04
  • Also, what the `offset` macro does is taking the offset from the beginning, not from a particular class or something. – Xeo Jun 03 '11 at 13:10

4 Answers4

2

offsetof gets the offset of a member from the start of a structure, but functions are not members in that sense (not even virtual functions). what you are probably after is the offset keyword:

class A
{
    int Func1()
    {
        return 1;
    }
};

__declspec(naked) int GetAddress()
{
    __asm
    {
        mov eax, offset A::Func1
        retn
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    printf("0x%08X\n",GetAddress());
    return 0;
}

To get the same effect under GCC (I'm using -masm=intel, as -fasm-blocks is apple only) we would do (32bit exe, tested under windows 7 64bit, using GCC 4.4):

class A
{
public:
    int Func1() __attribute__((noinline))
    {
        return 1;
    }
};

int a = 0; //this is bad, but it works for this demo
int GetAddress()// __attribute__((noinline))
{
    __asm("mov dword ptr[_a], offset __ZN1A5Func1Ev");
    return a;
}

int main()
{
    A a;
    printf("%d\n",a.Func1());
    system("pause");
    printf("0x%08X\n",GetAddress());
    return 0;
}

The problem with GCC is that:

  1. you can't bind to auto-inlined functions, as no symbol is generated (hence the noinline).
  2. you need to bind to decorated symbols unless you force undecorated symbols (and even then there will still be some decoration)
Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • Uhm, yes, but that keyword doesn't exist in GCC. I think you misunderstood the direction. – Xeo Jun 03 '11 at 13:11
  • @Xeo: I didn't misunderstand the direction, I was just pointing out that the MSVC assembler that this came from was using that. as for GCC not supporting `offset`, it does, you just need to bind to a decorated symbol, see my updated example – Necrolis Jun 03 '11 at 14:03
  • Thank you very much, Necrolis and Xeo! – Ryan Jun 03 '11 at 14:19
1

Try this:

mov eax, MyClass::MyFunction

What does it say?

PS: In old Intel syntax, this would have to be something like

mov eax, DWORD PTR MyClass::MyFunction

I don't know whether the gcc asm-block feature requires this or not.

TonyK
  • 16,761
  • 4
  • 37
  • 72
  • Meh, I tried all kinds of variations of this, but my error wasn't with the `mov` but with my `call [eax]` test to see if it worked... +1, works atleast on MSVC – Xeo Jun 03 '11 at 13:34
0

Since you said you don't need to hardcode it, just fetch the address in C++ code:

void test(){
  typedef void (MyClass::*memfun)(void*);
  memfun f = &MyClass::MyFunction;
  __asm{
    // I don't know why lea, but all forms of mov where failing. :|
    lea eax, dword ptr [x];
    call dword ptr [eax]; // test call, if the jump succeeds, you're done. :)
  }
}
Xeo
  • 129,499
  • 52
  • 291
  • 397
0

You cannot use offsetof with member functions, only with data members. It makes no sense. Member functions are not actually stored in the class.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243