|
The Problem
Supporting conditions
The DynObj library depends on some conditions from the compiler and OS:
- There must be an API for loading shared modules/libraries and resolve symbols in them.
- There must be a shared calling convention for ordinary functions available
(such as __cdecl). There usually is, since C level linking would not
work otherwise.
- The calling convention for virtual member function invocation must be
the same. (On GCC platforms this is so, and on Windows, one can explicitely
specify the one to use [we use the define docall for this]).
- The pointer to the table of virtual functions must be located first in
any plugin object. On modern C++ compilers this is usually the case. (C-front
based compilers from long ago typically did put it last).
Cross-Compiler Type Information
The interface query function T* do_cast<T>( U* pu ) is a key point
[this template function is a C++ wrapper around a C API]. It is what allows host
and plugins to use objects from other binaries in safe and useful ways.
To implement it, we must be able to:
- Have access to type information from the source compiler:
- We need some means of verifying that source and plugin compiler
agree on what functions an interface contains.
- We need to know where sub objects are located inside compound objects.
- We also need ways to determine the type of an arbitrary object of
which we only know that it is an object with 1 or more virtual functions.
The solution to the first points above is to have the plugin library generate
the required type information and make it avaialable at plugin load time.
The last point above is the subject of the next section.
VPTR and Virtual function tables
The VPTR is the first member of a binary object with virtual functions, pointing
to its virtual function table. And, if a type implements some methods on its
own, it must have its very own VTable. So, in effect, the VPTR is then a valid
type identifier value. This is quite a useful feature.
Virtual tables are built on loading code, so values of VPTR:s are not known
beforehand. We must rather discover them, and then store the VPTR:s into a
type table. Later in a do_cast operation, we can consult this table and
know what type we're dealing with.
|