Dynamic Dynamic Loader logo

Dynamic Dynamic Loader (DDL) Project

NMSU

HOME

EVENT TOOL FRAMEWORK

DOCUMENTATION

DOWNLOAD

WRAPPER REDIRECTION

TABLE BASED REDIRECTION

REDIRECTION USING TCL

C++ REDIRECTION

FAQ

RESEARCH GROUP

PUBLICATIONS

FUTURE DIRECTIONS



Back to PLEASE Lab



C++ Redirection

We can use DDL for redirection c++ methods, but while doing this we face some interesting issues like name mangling, constructors, destructors and virtual functions.

When C++ is compiled, the compiler does name mangling to convert the class and method name into a single unique symbol. Because C++ allows method overloading (same name but different parameters), the types of the parameters are also used in the name mangling to produce a unique name for each method, overloaded or not, in a class. In this way, C++ is  invisible to the dynamic linker, and class methods are only related in that their mangled names all include the same class name.

It is possible to create wrappers in C for methods in a C++ class. Our redirection mechanism can map a request for the mangled symbol into the symbol for our C function. In C, we can directly call the mangled symbol as another C function, with an explicit "this" pointer as the first argument. The mechanism is even typesafe when compiled with a C++ compiler and using the extern C syntax. However, it is not very convenient. Here is an example for this kind of wrapper :

//Sample Class
class A
{
public:
    void foo();
    void bar();
private:
    int x;
};

//sample C function wrapper for method foo() of class A
void wrapper_A_foo(A *this)
{


 // turn off redirection for my wrapper code
  do_redirect = 0;

  //
  // put my pre-call monitoring/logging/whatever code in here
  //

  // now be sure not to redirect the call to the original method foo
  // foo__1A is the mangled string for A::foo()
  redirect_ignore_next("foo__1A","libWrapper");

  // turn redirection back on
  do_redirect = 1;

  // call the real method
  this->foo();

  // turn off redirection again, for the rest of my wrapper
  do_redirect = 0;

  // turn off skipping redirection of A::foo()
  redirect_ignore_next("","");

  //
  // put my post-call monitoring/logging/whatever code here
  //

  // turn on redirection before we leave
  do_redirect = 1;

  return;
}


With the application coded in an OO methodology, it will be more approperiate to write wrappers as C++ calss methods. With wrappers in C++, our wrapper class(es) ought to mirror our application class(es). Moreover, the wrappers will need to know about (and invoke methods on) the application classes. To wrap any non-virtual method of a C++ class, we need to intercept the call to the that method and redirect it to our own wrapper class method. Our wrapper class should be a subclass of the target class (the class whose method(s) we want to wrap), and the wrapper method should have same type signature as the method which we want to wrap.

 Following figure shows the relationship between the application class A and the wrapper classwrap A.


In practice, we need to translate the declaration of A into a class declaration A' where all private members have been made public. We do not create an implementation of A'. This translation is done so that the wrapper class can have access to the data and methods. Note that A' is only used in compiling the wrapper, and we assume that this translation does not effect the binary layout of the class. Thus, the encapsulation defined for the class still holds for the rest of the application it is only for the wrapper that we allow the compiler to give us full access. As shown in the figure above , we can inherit from A' and redefine both methods to have wrapped versions. Although we have related the two methods (wrapped and wrapper) through inheritance, we can not use the relationship to cause an automatic invocation of the wrapper method, since the application is not necessarily available for modification (it may only exist in binary form). Rather, at runtime we use the DDL capabilities to redirect the calls to the method of the original class to the method of the wrapper class.

The code for the wrapper for foo() looks like:

returnType wrap_A::foo()
{
    returnType result;

    // ops before actual call

    result = A::foo(); // actual call

.    // ops after actual call

    return result;
}

With this approach we do not need any special handling for the object reference itself. It is important to note that no object of the wrapper class is ever instantiated. The application creates
objects of type A, calls methods on type A, and is compiled as such. At runtime, the calls to the methods which we want to wrap are redirected to the methods of the wrapper class. Although our wrapper is a subtype of A' (which we consider equivalent to A for our purposes), it does not add anything  new  in its class definition and the explicit superclass call correctly succeeds because the this pointer refers to an object of type A anyways.

Wrapping constructors and destructors


Constructors and destructors are special case methods that require special handling by our wrapping mechanisms. We can not simply redirect a constructor call to the constructor of our wrapper class because when the constructor of the wrapper class is called the constructor of the parent class is called implicitly, which is again redirected to our wrapper method. This ends up in an infi- nite loop. To resolve this problem we write a new (nonconstructor) method in our wrapper class and redirect the call to the constructor to this method. Inside this method, we would like to make an explicit constructor call, but C++ language semantics demand that an explicit constructor call should create a temporary object of the class, which is not what we need. Our solution to this issue is solved by reverting to using the "extern C" capability and calling the mangled symbol of the parent class constructor, passing the "this" pointer as an explicit parameter. Although not elegant, it does work.

There is one more thing which should be taken care of while wrapping constructors, the assembly code generated by compilers for constructors and other functions is slightly different. As we are redirecting the constructor to a normal function, we need to add some assembly code in our function so that the final assembly code generated is same as the assemble code of a normal constructor.

With destructors we face a similar problem. If we redirect the destructor call to the destructor of our wrapper class, the destructor of the parent class is implicitly called after returning from the destructor of the wrapper class. Another restriction that we have in the case of destructors is that some compilers mangle the symbol of a destructor in such a way that it cannot be explicitly called, even using the "extern C" mechanism. Thus, similarly to constructors, we redirect the destructor call to a regular method of the wrapper class; however, we do not need to call the destructor through a mangled C function call. Rather, C++ allows us to call the destructor of our own class (the wrapper class), and when we call the destructor of the wrapper class the destructor of parent class is called implicitly. The destructor of the wrapper class is an empty method, since no object of the wrapper class exists anyways; it only serves to cause an invocation of the parent class  destructor.

The code for constructor and destructor wrappers look like:

extern "C"
{
  extern void __1A(A *this);
}

class Wrap_A : public A
{
public:

    void wrap_constructor()
    {
          // ops before actual call

        __1A(this); // actual call

         // ops after actual call
        asm("movl %esi,%eax");
    }

    ~Wrap_A()
    {

    }

    void wrap_destructor()
    {

        // ops before actual call

        this->~Wrap_A(); // actual call

        // ops after actual call

    }
}

The destructor wrapper in the above example will only work for non-virtual destructors.

Wrapping Virtual Methods


The process of linking in the case of virtual methods is quite a bit different from non-virtual methods. Every object of a class with virtual methods has a pointer to the class vtable. The entries in the vtable point to the actual methods for the class, no matter where they are in the class hierarchy. To wrap virtual methods we need to intercept the binding of the entries stored in the virtual method table.

Generally, C++ compilers optimize away some of the vtable use on calls of virtual functions. For example, if an object variable is declared rather than an object pointer, any calls to virtual methods made on that variable (using the o.foo() syntax rather than the p->foo() syntax as on a pointer call) can be resolved at compile time, since the object type is known and is static. These calls will look like nonvirtual method calls to the linker, and will use normal symbol resolution and can easily be handled by DDL as previously explained.

For virtual method calls on object pointers that might point to a variety of object types,however, the vtable must be used. When supporting calls through a vtable, the mangled method names are not even referenced, and will not appear as externally required symbols for the linking process to resolve.

The object vtable pointer is initialized by the constructor(s), and these are (generally)in the same object code as the vtable itself, which is (generally) a static list of symbols that are resolved at load-time, not runtime. The effect of this is that the basic mechanisms of DDL run-time linking interception are completely bypassed, and thus without some new capability, virtual method calls can not in general be supported.

One way of wrapping virtual functions is to overwrite vtable pointer of the target class by out wrapper class vtable pointer, in this way when ever any virtual function is called through vtable, the virtual function of our wrapper calss will be called.  This can be done in the constructor wrapper, in the constructor wrapper method we can call the constructor of the wrapper calss and pass "this" pointer to it. The constructor of the wrapper class will initialize this object and will add its own vtable pointer to it.

There is an entry of run time type information (RTTI) in the vtable which should be restored (as this entry of wrapper class vtable will point to the type information of wrapper class). The code for constructor for this type of wrapping will look like this:

extern "C" {
  void __6Wrap_A(A *p); // mangled string of wrapper constructor (Wrap_A::Wrap_A())
}

typedef void (*void_fptr)(void);

void Wrap_A::wrap_constructor()
{
    do_redirect =0;

    // ops before actual call to constructor

    __6Wrap_A(this); // call constructor of wrapper class (to get the vtable of wrapper class)

    //Restore the RTTI entry
    static int rttiRestored = 0;
    if(rttiRestored == 0)
    {
        A *tempA;
        tempA = new A;

        void_fptr ** ppfuncptr1 = (void_fptr **)this;
        void_fptr ** ppfuncptr2 = (void_fptr **)tempA;


        //overwrite RTTI entry
        *((*(ppfuncptr1+1))+1) = *((*(ppfuncptr2+1))+1);
        delete tempA;
        rttiRestored = 1;
    }

    // ops after actual call to constructor

    do_redirect =1;

    asm("movl %esi,%eax");

}

We can not use this technique if we there is no constructor in our target class. We have solved this problem by building into DDL a hook for watching load-time symbol resolutions. At this point we do not allow manipulation of this step, because we have not yet considered all of its ramifications, but we can record the information about symbols other than dynamically linked
functions. Since these are resolved early on, by the time our initialization code is called, the vtable symbols are known, and we can over-write the vtable entries with pointers to our wrapper
functions.

Wrapping and inheritance


So far we have concentrated on wrappers for individual methods of C++ classes. When we aim to wrap a compete C++ class we face some more issues. In the object oriented paradigm, a class may inherit methods from one or more base classes. So if we want to wrap a derived class we need to wrap the methods of the base class(es) too. All the calls to these methods will be redirected to the methods of our wrapper class. But in this, all the calls on methods for objects from other subclasses, which also inherit the methods and which we do not want to wrap, will also be redirected to our wrapper class.


Figure above shows our wrapper class in a larger class hierarchy. For example, suppose we have a class B which has a method B :: foo(), and two subclasses are inherited from it, S1 and S2. S1 and S2 will use the method foo() of base class unless it is overridden in them. Here if we want to wrap class S1, we will inherit a our wrapper class from S1 and will override the method foo() in it, as shown in the figure. The problem is that all the calls to B : foo() will be redirected to wrap S1 :: foo(), even if they are made on an object of type S2. This is because we are using symbol redirection on the B :: foo symbol.

To resolve this problem we make use of the Run Time Type Information (RTTI) provided by C++. With this we can find the type of object calling this method at runtime and bypass any wrapper processing of a call that is not made from an object of our target class. The wrapper will still add overhead because it is invoked and needs to pass the invocation on to the real method, but the functionality of the wrapper can be applied to only one subclass, even in the presence of shared  base class methods.