home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / LordLucifer / win32asm / files / win32asm.exe / Win32ASM / ASMInc / InitExit.mac < prev    next >
Encoding:
Text File  |  1997-09-02  |  10.1 KB  |  217 lines

  1. ; Macros to handle initialization and exit routines. Ph.A., 03 Jan 97.
  2.  
  3. ; $Id: InitExit.mac 1.1 1997/09/02 09:50:35 Philippe Exp $
  4.  
  5. ; $Log: /Win32Equ/InitExit.mac $
  6. ; 1     18/09/97 14:24 Philippe
  7. ; Initial checkin into SourceSafe.
  8. ; Revision 1.1  1997/09/02 09:50:35  Philippe
  9. ; Initial revision
  10. ;
  11.  
  12.  
  13.  
  14. ; These macros allow the definition of initialization routines in multiple
  15. ; library modules. The $InitRoutine is used in any module containing an
  16. ; initialization routine that must be executed before the main logic of
  17. ; a program can be started.
  18. ; A typical use for an initialization routine is to create resources, such
  19. ; as critical sections, semaphores, etc... that will be required later by
  20. ; routines called in a multithreaded context.
  21. ; The resources must obviously be created and initializated before the
  22. ; threads that use them are created, and must be released before the
  23. ; program exits. One can of course invoke the initialization routines
  24. ; explicitely in the startup code of the application, but this is tedious
  25. ; and error prone: one could call a library routine and forget to add
  26. ; the code to init/exit the the package. Or one could stop using the
  27. ; library routine and forget to remove the call to the init and/or exit
  28. ; routines, resulting in the library module still being (needlessly)
  29. ; linked in.
  30. ; The $InitRoutine, $ExitRoutine, $RunInitRoutines and $RunExitRoutines
  31. ; are designed to help handling this problem.
  32. ; $InitRoutine and $ExitRoutine are used to declare initialization and
  33. ; exit routines.
  34. ; $InitRoutine declares a segment, naming it @Init$<module name>.
  35. ; $ExitRoutine declares a segment, naming it @Exit$<module name>.
  36. ; So if invoked in .ASM module FOO, $InitRoutine and $ExitRoutine will
  37. ; create segments named @Init$FOO and @Exit$FOO respectively.
  38. ; Both macros are called with the name of a routine. The macro will
  39. ; generate a DWORD pointer to the routine, and place this pointer in the
  40. ; @Init$ (or @Exit$) segment/section.
  41. ; The following is en excerpt from the PE object definition in the
  42. ; document "Microsoft Portable Executable and Common Object File Format
  43. ; Specification 4.1". When a section (segment) name contains a '$' sign,
  44. ; a PE linker processes it specially:
  45. ; "The "$" character (dollar sign) has a special interpretation in section
  46. ; names in object files. When determining the image section that will
  47. ; contain the contents of an object section, the linker discards the "$"
  48. ; and all characters following it. Thus, an object section named .text$X
  49. ; will actually contribute to the .text section in the image. However, the
  50. ; characters following the "$" determine the ordering of the contributions
  51. ; to the image section. All contributions with the same object-section
  52. ; name will be allocated contiguously in the image, and the blocks of
  53. ; contributions will be sorted in lexical order by object-section name.
  54. ; Therefore, everything in object files with section name .text$X will end
  55. ; up together, after the .text$W contributions and before the .text$Y
  56. ; contributions.
  57. ; The section name in an image file will never contain a "$" character."
  58.  
  59. ; As a result, the contents of all "@Init$" segments will be concatenated
  60. ; in the "Init" section and the contents of all "@Exit$" sections will be
  61. ; concatenated in the "@Exit" section.
  62. ; So the @$InitRoutine macros of all modules contribute to the construction
  63. ; of a global table containing all the addresses of the initialization
  64. ; routines and located in section "@Init", and the $ExitRoutine contribute
  65. ; to the construction of a global table containing all the addresses of
  66. ; the Exit routines and located in section "@Exit".
  67. ; The $RunInitRoutines and $RunExitRoutines put all of this together:
  68. ; they create the "@Init$" and "@Exit$" segments (that will endup ahead of
  69. ; all other @Init and @Exit segments in collating sequence and contain the
  70. ; table label), and "@Init$zzzzzzzz" / "@Exit$zzzzzzzz" (that will hopefully
  71. ; endup after all other @Init and @Exit segments and contain a DWORD 0 as
  72. ; an end of table marker).
  73. ; Finally, each macro generates a short loop that goes down its associated
  74. ; list and calls the addresses in the list.
  75. ; So at the point in code where the $RunInitRoutines macro will be
  76. ; inserted, there will be a loop that will call all init routines
  77. ; belonging to the modules that have been linked in.
  78. ; Ditto for $RunExitRoutines.
  79. ; The Init/Exit routines will automatically be invoked at the right time
  80. ; if the library module that contains them is pulled in by the linker,
  81. ; and only then. In case the Init and/or Exit routines must be ordered
  82. ; somehow, it is possible to pass a second parameter to the $????Routine
  83. ; declaration. This second parm is concatenated in the segment name
  84. ; ahead after the @Init$ (@Exit$) and before the <module name>.
  85. ; It allows one to change the linking order and force the Init (Exit)
  86. ; routines to execute in any requested order. For instance, a "Console Log"
  87. ; routine might need initialization before any other routine so the
  88. ; other initialization routines might use the Console Log procs to
  89. ; log what they did. Passing a second parameter of "0" might force the
  90. ; console log init routine to move up the list (if no other module uses
  91. ; this and no module is named "0.ASM").
  92.  
  93.  
  94. ; Call all initialization routines declared through the $InitRoutine macro.
  95. ; This macro should be inserted in the .CODE section.
  96.  
  97. ; If one of the initialization routine fails badly enough to prevent the
  98. ; program to run, it should return with the Carry flag set.
  99. ; This will abort the init loop.
  100. ; The code invoking the $RunInitRoutine should test the Carry condition
  101. ; and directly jump to some abort / exit code if it is set.
  102.  
  103. ; The FirstRoutine label shouldn't need to be made public, specially since
  104. ; it's a local macro symbol.
  105. ; Unfortunately, MASM/LINK generate a 0000000000 offset in the subsequent
  106. ; MOV ESI,OFFSET instruction if we don't make it public!
  107. ; Owell.
  108.  
  109. $RunInitRoutines MACRO
  110.     LOCAL FirstRoutine
  111.                 ;DO NOT REMOVE THIS NOP!
  112.                 ;This macro will reveal a MASM bug where MASM will generate
  113.                 ;a scrogged prologue code sequence, when $RunINitRoutines
  114.                 ;used as the first code generating instruction
  115.                 ;in a PROC *and* the PROC has a local variable.
  116.     NOP         ;Adding this NOP cures the bug...
  117.  
  118.                 ;Declare the first section in the @Init group.
  119. @Init$          SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
  120. FirstRoutine    LABEL NEAR
  121.                 PUBLIC FirstRoutine     ;Head of Init pointer table.
  122. @Init$          ENDS
  123.                 ;Declare the last section in the @Init group.
  124. @Init$zzzzzzzz  SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
  125.                 DWORD 0                 ;Define the terminator of the
  126. @Init$zzzzzzzz  ENDS                    ;@Init table.
  127.  
  128.     .CODE
  129.  
  130.     MOV ESI,OFFSET FirstRoutine         ;Point to first entry in Init
  131.                                         ;routines table.
  132.       .REPEAT
  133.       MOV EAX,[ESI]                     ;Get first Init address,
  134.       .BREAK .IF EAX == 0               ;exit at end of table.
  135.       SAVE ESI                          ;Save table pointer,
  136.       CALL EAX                          ;call current Init routine,
  137.       RESTORE ESI                       ;restore init table pointer,
  138.       .BREAK .IF CARRY?                  ;Exit init loop if init routine failed.
  139.       LEA ESI,[ESI]+(SIZEOF DWORD)      ;Bump to next init routine pointer,
  140.       .FOREVER                          ;loop again.
  141.  
  142.     ENDM
  143.  
  144.  
  145. ; Call all exit routines declared through the $ExitRoutine macro.
  146. ; This macro should be inserted in the .CODE section.
  147. ; We ignore any error condition in the termination routines, as we
  148. ; are terminating anyway.
  149.  
  150. $RunExitRoutines MACRO
  151.  
  152.                 ;Declare the first section in the @Exit group.
  153. @Exit$          SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
  154. FirstRoutine    LABEL NEAR
  155.                 PUBLIC FirstRoutine     ;Head of Exit pointer table.
  156. @Exit$          ENDS
  157.                 ;Declare the last section in the @Exit group.
  158. @Exit$zzzzzzzz  SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
  159.                 DWORD 0                 ;Define the terminator of the
  160. @Exit$zzzzzzzz  ENDS                    ;@Exit table.
  161.  
  162.  
  163.     .CODE
  164.  
  165.     MOV ESI,OFFSET FirstRoutine         ;Point to first entry in Init
  166.                                         ;routines table.
  167.       .REPEAT
  168.       MOV EAX,[ESI]                     ;Get first Init address,
  169.       .BREAK .IF EAX == 0               ;exit at end of table.
  170.       SAVE ESI                          ;Save table pointer,
  171.       CALL EAX                          ;call current Init routine,
  172.       RESTORE ESI                       ;restore init table pointer,
  173.       LEA ESI,[ESI]+(SIZEOF DWORD)      ;Bump to next init routine pointer,
  174.       .FOREVER                          ;loop again.
  175.  
  176.     ENDM
  177.  
  178.  
  179. ; Declare a routine as an Init routine.
  180. ; Its address is placed in the special @Init segment.
  181. ; The Prefix parm can be used to force order of init routines: the prefix
  182. ; parm is inserted after the Init$ root and before the module name.
  183. ; An Init routine that fails should give any relevant diagnostic and
  184. ; return with the Carry flag set. This will abort the execution of Init
  185. ; routines (NOT any following Init routine will be executed).
  186.  
  187. $InitRoutine MACRO Address:REQ,Prefix
  188.     LOCAL Address,SegInitName,Prefix
  189.  
  190. ;SegInitName TEXTEQU @CatStr(@Init$,%Prefix,%@FileName)
  191. SegInitName TEXTEQU @CatStr(@Init$,&Prefix,%@FileName)
  192.  
  193. %SegInitName SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
  194.     DWORD Address
  195. %SegInitName ENDS
  196.     ENDM
  197.  
  198.  
  199. ; Declare a routine as an Exit routine.
  200. ; Its address is placed in the special @Exit segment.
  201. ; The Prefix parm can be used to force order of init routines: the prefix
  202. ; parm is inserted after the Init$ root and before the module name.
  203.  
  204. $ExitRoutine MACRO Address:REQ,Prefix
  205.     LOCAL Address,SegExitName,Prefix
  206.  
  207. ;SegExitName TEXTEQU @CatStr(@Exit$,%Prefix,%@FileName)
  208. SegExitName TEXTEQU @CatStr(@Exit$,&Prefix,%@FileName)
  209.  
  210. %SegExitName SEGMENT DWORD READONLY PUBLIC USE32 'DATA'
  211.     DWORD Address
  212. %SegExitName ENDS
  213.     ENDM
  214.  
  215.  
  216.