[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