[cxx-abi-dev] Function descriptors in vtable

Dennis Handly dhandly at cup.hp.com
Wed Jan 22 09:54:51 UTC 2003


>I just was too lazy to write the code to copy it.

Ok, here is a version that works from C++.  There also a Makefile.

#---------------------------------- 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:51:28 2003
#
# This archive contains:
#	Makefile	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 - Makefile
cat >Makefile <<'@EOF'
CXX=aCC

test_com: cfile.o cppfile.o mainwin_stub.o
	$(CXX) $(CXXFLAGS) -o $@ cfile.o cppfile.o mainwin_stub.o

cppfile.o: cppfile.C
	$(CXX) -c $(CXXFLAGS) cppfile.C

cfile.o: cfile.c host_vtable.h thunkbase.h
	$(CC) -c $(CFLAGS) cfile.c

mainwin_stub.o: mainwin_stub.s
	$(CC) -c $(CFLAGS) mainwin_stub.s

clean: ; rm -f test_com cfile.o cppfile.o mainwin_stub.o
@EOF

chmod 664 Makefile

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
/* convert C++ virtual table to COM style */
typedef struct funcdescriptor {
   unsigned long long codeptr;
#ifdef _ILP32
   int pad;
#endif
   void (*GP)(void);
} funcdescriptor;

void modify_vtable(funcdescriptor *vt, int nfuncs) {
   funcdescriptor *p;
   register uint64_t stub_add;
   stub_add = *(uint64_t*)_mainwin_com_stub;
   if (!nfuncs || vt->codeptr == stub_add)
      return;  /* already done */

   p = (funcdescriptor*)malloc(sizeof(funcdescriptor) * nfuncs);
   for (; nfuncs > 0; nfuncs--, p++, vt++) {
       *p = *vt;
       vt->GP = (void (*)(void))p;
       vt->codeptr = stub_add;
   }
}

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)
};

void modify_vtable(funcdescriptor vt[], int nfuncs) {} /* dummy */
#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>
#include <stdlib.h>

struct aaa {
	virtual int f(int x) {
	   fprintf(stderr, "Inside CPP method - (%p) %d\n",this, 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 modify_vtable(void *vt, int nfuncs);
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 in C++\n");
// can't be defined in C++, without this kludge
        modify_vtable(*(void**)&a, 1);
        
	use_aaa(&a);
	use_aaa2(&a);
	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 664 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.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 664 thunkbase.h


if [ $EXIT_STATUS -eq 1 ];then
	exit 1
fi
exit 0



More information about the cxx-abi-dev mailing list