• Ben Avison's avatar
    Add support for (C++) static constructor and destructor functions · d8b72a18
    Ben Avison authored
    Later versions of the toolchain move on from the CFront model for static
    object construction and destruction (which used symbols called '__link'
    in object files which the linker manipulated into a linked list pointed at
    by the symbol '__head').
    
    Now, global or file-scope constructors are indicated by function pointers
    emitted into the area C$$ctorvec, with the function bodies being emitted
    into the area C$$ctor.
    
    The C library supports the calling of global or file-scope destructors in
    two ways: either they can be registered using atexit() calls from within the
    corresponding constructor (these are issued first) or function pointers can
    be provided in the area C$$dtorvec (with function bodies in the area
    C$$dtor).
    
    Function- or block-scope static-storage-duration destructors are a bit more
    complicated, since they are only constructed when the block in which they
    are declared comes into scope at run-time. For a module client, this means
    that they may be constructed in either USR or SVC mode. However, the
    destruction must be deferred until module finalisation in SVC mode, since
    there is no way for a USR mode constructor to know whether the scope will
    later be re-entered from SVC mode. For this scenario, atexit() will not
    suffice, and new entry _clib_at_destruction() must be used. (It is also
    valid to use this entry from global or file-scope constructors.)
    
    We add this 1 new function to cl_entry5. This chunk has not yet appeared in
    a stable release, nor included in a DDE release. Annotate these events too.
    
    The locations of the C$$ctor, C$$ctorvec, C$$dtor and C$$dtorvec areas are
    not established until client link time, so to convey this information to the
    shared C library, we need to extend its interface with the stubs. This is
    done by adding 8 additional words onto the end of the language description
    struct. Furthermore, so that this information is passed from the shared
    library kernel to the language-specific part (clib), the InitProc() entry
    in the language description struct is now passed a pointer to that struct.
    Similarly, _clib_initialise(), which previously took no arguments, now takes
    that pointer (but performs sanity checks on it and its contents, so that it
    can confidently handle old stubs for which the value of a1 is undefined).
    
    Add test programs to exercise the new functionality, without requiring the
    use of a C++ compiler.
    d8b72a18