[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