home *** CD-ROM | disk | FTP | other *** search
- ; Macros to handle initialization and exit routines. Ph.A., 03 Jan 97.
-
- ; $Id: InitExit.mac 1.1 1997/09/02 09:50:35 Philippe Exp $
-
- ; $Log: /Win32Equ/InitExit.mac $
- ;
- ; 1 18/09/97 14:24 Philippe
- ; Initial checkin into SourceSafe.
- ; Revision 1.1 1997/09/02 09:50:35 Philippe
- ; Initial revision
- ;
-
-
-
- ; These macros allow the definition of initialization routines in multiple
- ; library modules. The $InitRoutine is used in any module containing an
- ; initialization routine that must be executed before the main logic of
- ; a program can be started.
- ; A typical use for an initialization routine is to create resources, such
- ; as critical sections, semaphores, etc... that will be required later by
- ; routines called in a multithreaded context.
- ; The resources must obviously be created and initializated before the
- ; threads that use them are created, and must be released before the
- ; program exits. One can of course invoke the initialization routines
- ; explicitely in the startup code of the application, but this is tedious
- ; and error prone: one could call a library routine and forget to add
- ; the code to init/exit the the package. Or one could stop using the
- ; library routine and forget to remove the call to the init and/or exit
- ; routines, resulting in the library module still being (needlessly)
- ; linked in.
- ; The $InitRoutine, $ExitRoutine, $RunInitRoutines and $RunExitRoutines
- ; are designed to help handling this problem.
- ; $InitRoutine and $ExitRoutine are used to declare initialization and
- ; exit routines.
- ; $InitRoutine declares a segment, naming it @Init$<module name>.
- ; $ExitRoutine declares a segment, naming it @Exit$<module name>.
- ; So if invoked in .ASM module FOO, $InitRoutine and $ExitRoutine will
- ; create segments named @Init$FOO and @Exit$FOO respectively.
- ; Both macros are called with the name of a routine. The macro will
- ; generate a DWORD pointer to the routine, and place this pointer in the
- ; @Init$ (or @Exit$) segment/section.
- ; The following is en excerpt from the PE object definition in the
- ; document "Microsoft Portable Executable and Common Object File Format
- ; Specification 4.1". When a section (segment) name contains a '$' sign,
- ; a PE linker processes it specially:
- ; "The "$" character (dollar sign) has a special interpretation in section
- ; names in object files. When determining the image section that will
- ; contain the contents of an object section, the linker discards the "$"
- ; and all characters following it. Thus, an object section named .text$X
- ; will actually contribute to the .text section in the image. However, the
- ; characters following the "$" determine the ordering of the contributions
- ; to the image section. All contributions with the same object-section
- ; name will be allocated contiguously in the image, and the blocks of
- ; contributions will be sorted in lexical order by object-section name.
- ; Therefore, everything in object files with section name .text$X will end
- ; up together, after the .text$W contributions and before the .text$Y
- ; contributions.
- ; The section name in an image file will never contain a "$" character."
-
- ; As a result, the contents of all "@Init$" segments will be concatenated
- ; in the "Init" section and the contents of all "@Exit$" sections will be
- ; concatenated in the "@Exit" section.
- ; So the @$InitRoutine macros of all modules contribute to the construction
- ; of a global table containing all the addresses of the initialization
- ; routines and located in section "@Init", and the $ExitRoutine contribute
- ; to the construction of a global table containing all the addresses of
- ; the Exit routines and located in section "@Exit".
- ; The $RunInitRoutines and $RunExitRoutines put all of this together:
- ; they create the "@Init$" and "@Exit$" segments (that will endup ahead of
- ; all other @Init and @Exit segments in collating sequence and contain the
- ; table label), and "@Init$zzzzzzzz" / "@Exit$zzzzzzzz" (that will hopefully
- ; endup after all other @Init and @Exit segments and contain a DWORD 0 as
- ; an end of table marker).
- ; Finally, each macro generates a short loop that goes down its associated
- ; list and calls the addresses in the list.
- ; So at the point in code where the $RunInitRoutines macro will be
- ; inserted, there will be a loop that will call all init routines
- ; belonging to the modules that have been linked in.
- ; Ditto for $RunExitRoutines.
- ; The Init/Exit routines will automatically be invoked at the right time
- ; if the library module that contains them is pulled in by the linker,
- ; and only then. In case the Init and/or Exit routines must be ordered
- ; somehow, it is possible to pass a second parameter to the $????Routine
- ; declaration. This second parm is concatenated in the segment name
- ; ahead after the @Init$ (@Exit$) and before the <module name>.
- ; It allows one to change the linking order and force the Init (Exit)
- ; routines to execute in any requested order. For instance, a "Console Log"
- ; routine might need initialization before any other routine so the
- ; other initialization routines might use the Console Log procs to
- ; log what they did. Passing a second parameter of "0" might force the
- ; console log init routine to move up the list (if no other module uses
- ; this and no module is named "0.ASM").
-
-
- ; Call all initialization routines declared through the $InitRoutine macro.
- ; This macro should be inserted in the .CODE section.
-
- ; If one of the initialization routine fails badly enough to prevent the
- ; program to run, it should return with the Carry flag set.
- ; This will abort the init loop.
- ; The code invoking the $RunInitRoutine should test the Carry condition
- ; and directly jump to some abort / exit code if it is set.
-
- ; The FirstRoutine label shouldn't need to be made public, specially since
- ; it's a local macro symbol.
- ; Unfortunately, MASM/LINK generate a 0000000000 offset in the subsequent
- ; MOV ESI,OFFSET instruction if we don't make it public!
- ; Owell.
-
- $RunInitRoutines MACRO
- LOCAL FirstRoutine
- ;DO NOT REMOVE THIS NOP!
- ;This macro will reveal a MASM bug where MASM will generate
- ;a scrogged prologue code sequence, when $RunINitRoutines
- ;used as the first code generating instruction
- ;in a PROC *and* the PROC has a local variable.
- NOP ;Adding this NOP cures the bug...
-
- ;Declare the first section in the @Init group.
- @Init$ SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
- FirstRoutine LABEL NEAR
- PUBLIC FirstRoutine ;Head of Init pointer table.
- @Init$ ENDS
- ;Declare the last section in the @Init group.
- @Init$zzzzzzzz SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
- DWORD 0 ;Define the terminator of the
- @Init$zzzzzzzz ENDS ;@Init table.
-
- .CODE
-
- MOV ESI,OFFSET FirstRoutine ;Point to first entry in Init
- ;routines table.
- .REPEAT
- MOV EAX,[ESI] ;Get first Init address,
- .BREAK .IF EAX == 0 ;exit at end of table.
- SAVE ESI ;Save table pointer,
- CALL EAX ;call current Init routine,
- RESTORE ESI ;restore init table pointer,
- .BREAK .IF CARRY? ;Exit init loop if init routine failed.
- LEA ESI,[ESI]+(SIZEOF DWORD) ;Bump to next init routine pointer,
- .FOREVER ;loop again.
-
- ENDM
-
-
- ; Call all exit routines declared through the $ExitRoutine macro.
- ; This macro should be inserted in the .CODE section.
- ; We ignore any error condition in the termination routines, as we
- ; are terminating anyway.
-
- $RunExitRoutines MACRO
-
- ;Declare the first section in the @Exit group.
- @Exit$ SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
- FirstRoutine LABEL NEAR
- PUBLIC FirstRoutine ;Head of Exit pointer table.
- @Exit$ ENDS
- ;Declare the last section in the @Exit group.
- @Exit$zzzzzzzz SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
- DWORD 0 ;Define the terminator of the
- @Exit$zzzzzzzz ENDS ;@Exit table.
-
-
- .CODE
-
- MOV ESI,OFFSET FirstRoutine ;Point to first entry in Init
- ;routines table.
- .REPEAT
- MOV EAX,[ESI] ;Get first Init address,
- .BREAK .IF EAX == 0 ;exit at end of table.
- SAVE ESI ;Save table pointer,
- CALL EAX ;call current Init routine,
- RESTORE ESI ;restore init table pointer,
- LEA ESI,[ESI]+(SIZEOF DWORD) ;Bump to next init routine pointer,
- .FOREVER ;loop again.
-
- ENDM
-
-
- ; Declare a routine as an Init routine.
- ; Its address is placed in the special @Init segment.
- ; The Prefix parm can be used to force order of init routines: the prefix
- ; parm is inserted after the Init$ root and before the module name.
- ; An Init routine that fails should give any relevant diagnostic and
- ; return with the Carry flag set. This will abort the execution of Init
- ; routines (NOT any following Init routine will be executed).
-
- $InitRoutine MACRO Address:REQ,Prefix
- LOCAL Address,SegInitName,Prefix
-
- ;SegInitName TEXTEQU @CatStr(@Init$,%Prefix,%@FileName)
- SegInitName TEXTEQU @CatStr(@Init$,&Prefix,%@FileName)
-
- %SegInitName SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
- DWORD Address
- %SegInitName ENDS
- ENDM
-
-
- ; Declare a routine as an Exit routine.
- ; Its address is placed in the special @Exit segment.
- ; The Prefix parm can be used to force order of init routines: the prefix
- ; parm is inserted after the Init$ root and before the module name.
-
- $ExitRoutine MACRO Address:REQ,Prefix
- LOCAL Address,SegExitName,Prefix
-
- ;SegExitName TEXTEQU @CatStr(@Exit$,%Prefix,%@FileName)
- SegExitName TEXTEQU @CatStr(@Exit$,&Prefix,%@FileName)
-
- %SegExitName SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
- DWORD Address
- %SegExitName ENDS
- ENDM
-
-
-