DynObj - Dynamic Binary Runtime Plugin Objects Hosted by:
SourceForge.net Logo

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.