[cxx-abi-dev] Function descriptors in vtable
Noam Lampert
noaml at mainsoft.com
Wed Jan 22 09:58:08 UTC 2003
Hi Dennis,
> >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.
I did mention in my original email "Calling a C++ virtual method from
within C code". In addition, the sample I sent does this (takes a C++
class and sends it to a C function that calls a virtual method).
Noam
> -----Original Message-----
> From: Dennis Handly [mailto:dhandly at cup.hp.com]
> Sent: Wednesday, January 22, 2003 11:12 AM
> To: cxx-abi-dev-return-1622-cxx-abi-
> hp=adlmail.cup.hp.com at codesourcery.com; mark at codesourcery.com
> Cc: amckale at cup.hp.com; cxx-abi-dev at codesourcery.com;
gomathi at cup.hp.com;
> kerch at cup.hp.com; noaml at mainsoft.com; sassan at cup.hp.com
> Subject: Re: [cxx-abi-dev] Function descriptors in vtable
>
> >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