M
M
Mikhail Mironov2015-11-12 11:19:20
C++ / C#
Mikhail Mironov, 2015-11-12 11:19:20

What is stored in a pointer to a virtual class method in C++Builder (content of __thunk__ )?

Actually, the main question is why the content of pointers to a virtual method that returns a custom class is different from other pointers to virtual methods?

class Bar{
};

struct Baz {
    int a;
    int b;
    int c;
};

class Foo {
    public:
    	virtual void 	VirtualVoid(){}
        virtual int 	VirtualInt(){}
        virtual char*	VirtualCharPtr(){}
        virtual double	PureVirtualDouble() = 0;
        virtual Bar	VirtualEmptyClass() {}
        virtual Baz    VirtualNotEmptyClass(){}
        virtual long long  PureVirtualLongLong() = 0;
};

Debugger:
foo_ptr_0: void        (Foo::*)() :0018FF48 __thunk__ [B,0,1,0]{0,0}
foo_ptr_1: int         (Foo::*)() :0018FF3C __thunk__ [B,0,5,0]{4,0}
foo_ptr_2: char*       (Foo::*)() :0018FF30 __thunk__ [B,0,9,0]{8,0}
foo_ptr_3: double      (Foo::*)() :0018FF24 __thunk__ [B,0,D,0]{12,0}
foo_ptr_4: Bar         (Foo::*)() :0018FF18 __thunk__ [B,0,11,4]{16,0}
foo_ptr_5: Baz    (Foo::*)() :0018FF0C __thunk__ [B,0,15,4]{20,0}
foo_ptr_6: long long (Foo::*)() :0018FF00 __thunk__ [B,0,19,0]{24,0}

compiler, flags are all standard;
bcc32 --version
Embarcadero C++ 6.60 for Win32 Copyright (c) 1993-2013 Embarcadero Technologies, Inc.
Revision 6.60.4846.33249

From what I dug up:
The first field that all "B" have is, it seems, the index of the calling agreement.
When compiled with different flags for the foo_ptr_4 pointer:
Pascal (__pascal) (-p) 
foo_ptr_4 __thunk__ [C,0,11,0]{16,0}
C (__cdecl) (-pc)
foo_ptr_4 __thunk__ [B,0,11,4]{16,0}
_msfastcall (__msfastcall) (-pm)
foo_ptr_4 __thunk__ [I,0,11,4]{16,0}
Fastcall(register)  (__fastcall) (-pr)
foo_ptr_4 __thunk__ [D,0,11,0]{16,0}
stdcall (__stdcall) (-ps)
foo_ptr_4 __thunk__ [F,0,11,4]{16,0}

This shows that the fourth field is null when __pascal and __stdcall are called.
The third field is probably the offset from the beginning of the object to the function pointer:
Borland compilers add an offset of 1 to data member pointers in order to distinguish a
pointer to the first data member from a NULL pointer, represented by 0. The other compilers
have no offset , but represent a NULL data member pointer by the value -1.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Mercury13, 2015-11-12
@Mercury13

This is how many stack bytes are needed. In the case of void*, nothing needs to be returned. In the case of int, char*, the return value is in eax. In the case of double, at the top of the coprocessor stack. And in the case of a custom class, somewhere in the call stack. The Baz class is empty, only a pointer to TVM - that's why 4 bytes. For the Bar class, look at sizeof for the sake of interest - I'm almost sure that the same 4 bytes.
Perhaps when we add local variables, this figure will also increase.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question