DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
Writing drivers in C++

Static objects with constructors or destructors

Static objects requiring construction or destruction must not be used within a device driver for SCO SVR5 2.X or SCO OpenServer 5 and are not recommended for SVR5. This refers to usages such as the following at file scope.:

   class A {
   public:
           A(int);
           ~A();
   };
   

A a(22);

``Static'' also includes objects within namespace scope and destructable objects that are static locals, such as:
   void f() {
           static A a(33);
   }
This restriction is necessary because, in the normal C++ environment, start-up and termination runtime routines execute these constructors and destructors before and after main( ) executes. In the static local case, only the destructor has this behavior. These runtime routines (Crti.o and Crtn.o) are not present in the kernel environment.

In SCO SVR5 2.X, these runtime routines work in conjunction with a post-linker editing tool named patch which is not available and would not work in the kernel build environment. patch is not used in SVR5.

Ideally, you should avoid declaring such static objects. If you need objects with a static allocation, a simple alternate approach is to declare them with a null constructor and no destructor, then define member functions that do the appropriate initialization and finalization. Call these member functions from the driver's _load( ) and _unload( ) entry point routines.

C++ drivers that need really static objects can implement them by supplying replacements for the required runtime routines as follows:

  1. Use the ld -r command to prepend an assembly section such as the following to the beginning of the driver object code:
       .section        .ctor,"aw"
       .long   0
       .previous
    
    Each translation unit that needs static initialization puts the address of its initialization routine in this .ctor section. These are coalesced by the linker to form a vector of addresses. These are traversed in reverse order; this code serves to define the end of this vector.

  2. Use the ld -r command to append an assembly section such as the following to the end of the driver object code:
               .section        .ctor,"aw"
       __ctor_head:
               .long   0
               .type   __ctor_head,"object"
               .size   __ctor_head,4
               .previous
    
    This code defines the beginning of the initialization routine vector.

  3. The driver's _load(D2) entry point must include logic that calls every initialization routine in the vector, such as:
       void (**pf)() = &__ctor_head;
       for (--pf; *pf; --pf)
               (**pf)();
    

  4. The steps given above handle constructors and other initializations. Destructors are done differently. You must supply the following runtime routine, which will be called from the compiled code whenever a destructable object is created from the static storage duration:
       typedef void (*a_void_function_ptr)();
       typedef struct a_needed_destruction *a_needed_destruction_ptr;
       

    typedef struct a_needed_destruction { a_needed_destruction_ptr next; /* Pointer to the next entry in the list. */ void *object;/* Don't need to know about this. */ a_void_function_ptr destruction_routine; /* Don't need to know about this. */ } a_needed_destruction;

    extern "C" void __record_needed_destruction(a_needed_destruction_ptr ndp) { /* Called when a static object has been constructed to register a destruction that must be done at program termination. ndp points to a needed destruction entry that is to be added to the front of a list of needed destructions that this routine keeps. */

    ... }

    The a_needed_destruction structure nodes are allocated by the generated code, with the object and destruction pointers filled in. All you have to do is kept the nodes on a list, using the ``next'' field.

  5. Invoke all the destructors put on this ``needed destructions list'' by __record_needed_destruction. Call the following routine, founc, within the dtor_list.o runtime object file, to avoid the complexities involved when invoking destructors, passing in the head of the list that you kept in Step #4.:
       extern "C" __process_needed_destructions(a_needed_destruction_ptr *ndp);
    
    You will need to extract dtor_list.o from LibC.a and link it into the driver, as explained below.

© 2005 The SCO Group, Inc. All rights reserved.
OpenServer 6 and UnixWare (SVR5) HDK - June 2005