[cxx-abi-dev] Function descriptors in vtable

Dennis Handly dhandly at cup.hp.com
Wed Jan 22 09:11:35 UTC 2003


>I'll carry this a bit further, and demonstrate how this proposal could 
>be done in the context of Noam's example:

I've already set this up and ran the example.  The part where it is
defined in C++ aborts.

>As Mark said, every vtable entry can point to the same stub, which can 
>be somewhere in MainWin's runtime library.

>Or dynamically in C:
>    extern int _mainwin_com_stub;
>    extern int bbb_f(void *b, int x);

I used this.

>(Notice we lie and declare the stub as a data symbol.
-cary

No need to lie, just take the value out of the plabel:
   extern void _mainwin_com_stub(void);
   vt.f_stub = *(uint64_t*)_mainwin_com_stub;

>From: "Noam Lampert" <noaml at mainsoft.com>
>However, if the vtable was created by the C++ compiler, using it in C is
>still very hard.

I don't think you mentioned that you created these from normal C++ classes.

>Is there a more elegant way to achieve this?
Noam

No.  Don't create these in normal C++.

>From: "Noam Lampert" <noaml at mainsoft.com>
>It took me too long to figure out that my proposed solution here can't work.
>What could be done is
 	   for (i = 0; i < nfuncs; i++) {
	         void *p = malloc(sizeof(funcdescriptor));
		   *p = vt[i];

It didn't take me long at all.  ;-)
I just was too lazy to write the code to copy it.

#---------------------------------- cut here ----------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Dennis Handly <dhandly at den-bear> on Wed Jan 22 01:07:30 2003
#
# This archive contains:
#	cfile.c		cppfile.C	host_vtable.h	mainwin_stub.s	
#	thunkbase.h	
#

LANG=""; export LANG
PATH=/bin:/usr/bin:/usr/sbin:/usr/ccs/bin:$PATH; export PATH
EXIT_STATUS=0

echo x - cfile.c
cat >cfile.c <<'@EOF'
#include <stdio.h>

#include "host_vtable.h"

// This source files assumes that there is a definition
// struct aaa {
//    virtual int f(int x);
// };
// extern "C" void use_aaa(aaa *a);
// We implement an instance of an inheriting class.
// We also implement use_aaa2(aaa *a);

struct bbb;
typedef struct {
	C_INTERFACE_PROLOGUE(aaa)
	C_STDMETHODEX_(int,f,(void* b, int x))
} bbb_vtable;

typedef struct bbb {
	bbb_vtable *vt;
} bbb;

int bbb_f(void* b, int x) {
	fprintf(stderr, "Inside C method - (%p) %d\n",b, x);
	return 0;
}

#ifdef __ia64
bbb_vtable vt;
#pragma init "B_INIT"
static void B_INIT() {
   vt.f_stub = *(uint64_t*)_mainwin_com_stub;
   vt.f = bbb_f;
}
#else
bbb_vtable vt = {
	C_VTABLE_PROLOGUE
	C_VTABLE_ENTRY2(bbb_f)
};
#endif

bbb b = { &vt };

extern void use_aaa(bbb* b);
void use_aaa2(bbb *b)
{
	b->vt->f(b,3);
}

void ctest()
{
	fprintf(stderr, "Enter C test\n");
	use_aaa(&b);
	use_aaa2(&b);
	fprintf(stderr, "Leave C test\n");
}
@EOF

chmod 664 cfile.c

echo x - cppfile.C
cat >cppfile.C <<'@EOF'
#include <stdio.h>

struct aaa {
	virtual int f(int x) {
	    fprintf(stderr, "Inside CPP method - %d\n",x); return 1;
	}
};
struct bbb {
	virtual int f(int x);
};

extern bbb b;

aaa a;

extern "C" void use_aaa(aaa *a)
{
	a->f(4);
}
extern "C" void use_aaa2(aaa *a);
extern "C" void cpptest()
{
	fprintf(stderr, "Enter CPP test\n");
	use_aaa(reinterpret_cast<aaa*>(&b));
	use_aaa2(reinterpret_cast<aaa*>(&b));
	fprintf(stderr, "  defined C++\n");
#if 0
// can't be defined in C++
	use_aaa(&a);
	use_aaa2(&a);
#endif
	fprintf(stderr, "Leave CPP test\n");
}


extern "C" void ctest();
int main()
{
	cpptest();
	ctest();
}
@EOF

chmod 664 cppfile.C

echo x - host_vtable.h
cat >host_vtable.h <<'@EOF'
#ifndef __HOST_VTABLE_H
#define __HOST_VTABLE_H

#include <inttypes.h>  /* uint64_t */
/*
typedef _method_pointer_layout
{
    void (*method)(void *);
    int vtaboff;
    int thisoff;
} method_pointer_layout;
*/

#ifndef __ia64
enum vtable_layout_consts
{
    VTABLE_PROLOGUE_KEY = 0x12345678
};
#endif

// HP uses the thunkbased vtable format.
#include "thunkbase.h"

#undef  C_STDMETHODEX_
#ifdef __LP64
#define C_STDMETHODEX_(type, method, arglist)   uint64_t method ## _stub; \
                                                type (*method) arglist;
#else
#define C_STDMETHODEX_(type, method, arglist)   uint64_t method ## _stub; \
                                                int method ## _pad; \
                                                type (*method) arglist;
#endif

extern void _mainwin_com_stub(void);

#endif
@EOF

chmod 660 host_vtable.h

echo x - mainwin_stub.s
cat >mainwin_stub.s <<'@EOF'
        .type   _mainwin_com_stub, at function
        .radix  C
        .psr    abi32
        .psr    msb
        .section .text = "ax", "progbits"
        .proc   _mainwin_com_stub
_mainwin_com_stub::
#ifdef _ILP32
         addp4   gp = r0, gp
         ;;
#endif
         ld8     r31 = [gp], 8
         ;;
         ld8     gp = [gp]
         mov     b6 = r31
         ;;
         br.call.dptk.few b6
         ;;
        .endp   bbb_f
@EOF

chmod 664 mainwin_stub.s

echo x - thunkbase.h
cat >thunkbase.h <<'@EOF'
#ifndef VTABLE_THUNkBASE_H
#define VTABLE_THUNkBASE_H

/*
 * Thunk based vtable format.
 * The format is an array of functions. The name thunk comes from the fact
 * that thunk functions are created for managing the necessary adjustments of
 * the 'this' value because of multiple inheritence semantics.
 * Every entry is:*/

#ifndef __ia64
typedef struct _vtable_entry_layout { 
   void (*method) ();
} vtable_entry_layout;
#endif

/* The vtable is:
 * struct vtable {
 *   vtable_entry_layout prologue [???]; // The number of reserved entries varies.
 *   vtable_entry_layout entries [];
 * };
 */
 
#define C_INTERFACE_PROLOGUE(iface)             /* Nothing */
#define C_STDMETHOD_(type, method)              type (*method)
#define C_STDMETHODEX_(type, method, arglist)   type (*method) arglist;
 
/* structured vtable entries */
#define C_VTABLE_PROLOGUE                       /* Nothing. */
#define C_VTABLE_ENTRY(method)                  method
 
/* unstructured ((void *) array) vtable entries and sizes.
 * For thunk based vtables this is the same as the previous. */
#define C_VTABLE_PROLOGUE2                      C_VTABLE_PROLOGUE
#define C_VTABLE_ENTRY2(method)                 C_VTABLE_ENTRY((void*)method)
#define C_VTABLE_PROLOGUE_SIZE2                 0
#define C_VTABLE_ENTRY_SIZE2                    1
#define C_VTABLE_FUNC2(ind)                     C_VTABLE_SIZE2(ind)
 
/* The thunk based compilers don't need to adjust the 'this' pointer. */
#define C_ADJUST_THIS_(iface, This, member)     (This)
 
#endif
@EOF

chmod 660 thunkbase.h
if [ $EXIT_STATUS -eq 1 ];then
	exit 1
fi
exit 0



More information about the cxx-abi-dev mailing list