home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / STRTUP10.ZIP / STARTUP.ZIP / STARTUP / STARTUP2.ASM < prev    next >
Encoding:
Assembly Source File  |  1997-02-28  |  13.2 KB  |  450 lines

  1.     page 60,132
  2.     title Start_Up2 -- Advanced Start Up Code for .COM/.EXE Programs
  3.     name Start_Up2
  4.  
  5. comment ÷
  6.         START_UP2                                               V1.06
  7. --------------------------------------------------------------------------
  8. NAME
  9.     Start_Up2    Advanced start up code for .com and .exe programs
  10.  
  11. SYNOPSIS
  12.     extern Start_Up2
  13.     or
  14.     extern Start_Up2S
  15.  
  16.     See Programming Notes below for difference.
  17.  
  18. DESCRIPTION
  19.     This is the startup code for all .exe and .com assembly language
  20.     programs.  Just use the SYNOPSIS above in the main function to
  21.     include this startup code in the .exe file from a .lib.    For .com
  22.     assembly language programs, this source code must be the first
  23.     assembled so that this code is the linked first.
  24.  
  25.     This procedure parses the command line into argc and *argv[] similar
  26.     to C.  Argv[0] is the process name as in C.
  27.     
  28.     This procedure performs the following functions in addition to above
  29.     - Initializes the following global variables:
  30.       -- DGRP, segment address of DGROUP
  31.       -- STACK_BOTTOM, offset to stack bottom in DGROUP
  32.       -- PSP, segment address of PSP
  33.       -- ENVIRON, segment address of passed copy of the ENVIRONMENT
  34.       -- NEXTPARA, segment address of next memory paragraph
  35.       -- OSMAJOR, integer part of OS system
  36.       -- OSMINOR, decimal part of OS system
  37.     - If DOS version is less than 2.0, aborts with error message
  38.     - Initializes DS and ES segment registers to DGROUP
  39.     - Shrinks memory down to size of program by releasing all memory
  40.       above program
  41.  
  42. RETURNS
  43.     If main returns to startup code.  The program terminiates with the 
  44.     return code in AL.
  45.  
  46. PROGRAMING NOTES
  47.     Assembled with Microsoft MASM V6.11d.
  48.  
  49.     Written to link with any memory model.
  50.     
  51.     Use MEMMOD to specify the memory model.
  52.     /dMEMMOD=TINY|SMALL|COMPACT|MEDIUM|LARGE|HUGE
  53.  
  54.     Written using the FORTRAN/PASCAL/BASIC calling convention so passed
  55.     parameters are pushed in the order of appearance in the proc 
  56.     declaration.
  57.  
  58.     This procedure can pass argc and argv on stack two ways.   The proc
  59.     declaration in the MAIN procedure will differ depending upon the 
  60.     choice.
  61.     
  62.     The default requires the following proc declaration:
  63.     
  64.         MAIN proc ARGC:word, ARGV:ptr
  65.     
  66.     If SIMPLE is defined, an alternate proc declaration is required:
  67.     
  68.         MAIN proc ARGV:ptr, ARGC:word
  69.     
  70.     Here, ARGV is not a pointer to an array of pointers but the location
  71.     of the 1st pointer.
  72.  
  73.     In Huge memory model, the pointers passed in ARGV are long pointers
  74.     vice huge pointers.
  75.  
  76. MEMORY REQUIREMENTS    (using 286 instructions set)
  77.     (in bytes)    Tiny   Small   Medium    Compact  Large    Huge
  78.     Code:         221    242    244     245      247    247
  79.     Code (SIMPLE):     218    239    241     241      243    243
  80.     _Data:           0      0      0       0        0      0
  81.     Const:           0      0      0       0        0      0
  82.     _BBS:          12     12     12      12       12     12
  83.     Stack:           ?      ?      ?       ?        ?      ?
  84.  
  85.     The first code size is for when SIMPLE not defined.  The Code
  86.     (SIMPLE) size is for when SIMPLE is defined.
  87.  
  88.     Stack usage is determined by the size of and the number of arguments
  89.     in the command line.
  90.  
  91.     Note:  The 12 bytes in _BSS are from sudata.asm which is used so that
  92.     all startup code can reside in the same .lib file.
  93.  
  94. CAUTION
  95.     Startup2 defines a 1K byte stack.  This should be enough for programs
  96.     that make moderate use of the stack.  If automatic variables are used
  97.     extensively, more stack space should be defined in the main module
  98.     unless using the tiny memory model.  In this case, the startup code
  99.     must be the first souce file in the build, change the size of the
  100.     STACK_SIZE define.
  101.  
  102.     Linker option, NO IGNORE CASE, is not used so that the linker will
  103.     handle __end properly.
  104.  
  105. EXTERNAL LIBRARIES
  106.     sudata        alib?
  107.  
  108. EXTERNAL PROCEDURES
  109.     main        user defined
  110.  
  111. INTERUPTS CALLED
  112.     Int 21h 30h - Get Version Number
  113.     Int 21h 4ah - Set Memory Block Size
  114.     Int 21h 4ch - Terminate program with return code
  115.  
  116. GLOBAL NAMES
  117.     Startup_2 or Startup_2S
  118.  
  119. AUTHOR
  120.     Raymond Moon - 7 Sep 87
  121.  
  122.         Copyright (c) 1987, 1988, 1994, 1995, 1996 - MoonWare
  123.     ALL RIGHTS RESERVED
  124.  
  125. VERSION
  126.     Version    - Date        - Remarks
  127.     1.00    -  7 Sep 87    - Original
  128.     1.01    - 13 Feb 88    - Updated to program name as argv[0]
  129.     1.02    - 13 Aug 88    - Updated to MASM 5.1
  130.     1.03    - 10 Oct 88    - Added STACK_BOTTOM & ZZ_PRGM_TOP segment
  131.                   to determine end of data.
  132.     1.04    - 30 Oct 94    - Moved ZZ_PRGM_TOP segment position in file.
  133.                 - Removed increment in program size in paras
  134.                     as ZZ_PRGM_TOP is aligned on a para.
  135.     1.05    - 20 Apr 95    - Added TINY Model capability
  136.                 - Converted to .dosseg using __end vice
  137.                   ZZ_PRGM_TOP for end of data
  138.                 - Removed checking for DOS Ver 1.0 and
  139.                   terminating with error message
  140.                 - Removed checking for DOS Ver 2.0 or earlier
  141.                   and substituting .asm for the filename.
  142.         1.06    - 29 Dec 96     - Optimized the .com coding
  143. ==========================================================================
  144.     ÷  Commend End
  145.  
  146. ;-----------------------------
  147. ; A    Make the small memory model the default
  148.  
  149. ifndef    memmod
  150. memmod    equ    <small>
  151. endif
  152.  
  153. ;-----------------------------
  154. ; B    Include the processor, memory model, associate ES register with
  155. ;    DGROUP, and specify DOS segment order.
  156.  
  157.     include procesor.inc
  158. %    .MODEL    memmod,FORTRAN
  159.     assume    es:DGROUP
  160.     .dosseg
  161.  
  162. ;----------------------------
  163. ; C    Required includes
  164.  
  165.     include startup.inc
  166.  
  167. ;----------------------------
  168. ; D    Define any required equates
  169.  
  170. STACK_SIZE    equ    1024
  171.  
  172. ;=========================================================================
  173. ;    DATA
  174. ;=========================================================================
  175. ; E    Define the stack if required
  176.  
  177. if    @Model    NE  1
  178.     .STACK    STACK_SIZE    ; Define a nominal stack
  179. endif
  180.  
  181. ;----------------------------
  182. ; F    Define __end which is defined when using .dosseg directive.
  183. ;    Remember not to use the NO IGNORE CASE linker option.
  184.  
  185. externdef    __end:byte
  186.  
  187. ;----------------------------
  188. ; G    Define segment for addressing information in the PSP.
  189.  
  190. PSP_SEG    segment at 00h
  191.     
  192.     org    2h
  193. NEXTPARA_PTR    dw    ?        ; Segment address of next memory para
  194.  
  195.     org    2ch
  196. ENVIRON_PTR    dw    ?        ; Segment address of Environment
  197.  
  198.     org     80h
  199. PARM_LEN     db    ?        ; Number of bytes in Command Line tail
  200. PARMS       db    127 dup(?)    ; Start of Command Line tail
  201. PSP_SEG    ends
  202.  
  203. ;=========================================================================
  204. ;    CODE
  205. ;=========================================================================
  206. ; H    Put the called main procedure in the proper relationship to the
  207. ;    startup code.
  208.  
  209. if @CodeSize
  210. extrn    Main:far
  211. .CODE
  212. else
  213. .CODE
  214. extrn    Main:near
  215. endif
  216.  
  217. ;-----------------------------
  218. ; I    Include org statement if tiny model
  219.  
  220. if    @Model    EQ 1
  221.  
  222.     org    100h
  223. endif
  224.  
  225. ;-----------------------------
  226. ; J    Start the Start_Up2 code.  Make it a far procedure so error return
  227. ;    will work.  If SIMPLE is defined, redefined Start_Up2 as Start_Up2S.
  228.  
  229. ifdef SIMPLE
  230. Start_Up2    equ    <Start_Up2S>
  231. endif
  232.  
  233. % Start_Up2    proc    far
  234.  
  235. ;-----------------------------
  236. ; K     First, initialize global variables.  Set DS to DGROUP.
  237. ;    Skip DGROUP code for .com(Tiny) memory models
  238.  
  239. if    @Model    NE 1
  240.  
  241.     mov    ax, DGROUP        ; Get seg address of DGROUP
  242.     mov    ds, ax            ; Initialize DS segment register
  243.     mov    DGRP, ax        ; Initialize DGRP
  244. assume    es:PSP_SEG
  245. else
  246.     mov    DGRP, ds        ; Initialize DGRP
  247. endif
  248.     mov    PSP, es            ; Initialize PSP
  249. if    @Model    eq 1
  250. assume    ds:PSP_SEG
  251. endif
  252.     mov    bx, ENVIRON_PTR     ; Get segment address of environment
  253.     mov    cx, NEXTPARA_PTR    ; Get segment address of next memory
  254. if    @Model    eq 1
  255. assume    ds:DGROUP
  256. endif
  257.     mov    ENVIRON, bx        ; Initialize ENVIRON
  258.     mov    NEXTPARA, cx        ; Initialize NEXTPARA
  259.     mov    ah, 30h            ; Get DOS version number
  260.     int    21h            ; Call DOS
  261.     mov    OSMAJOR, al        ; Save major version number
  262.     mov    OSMINOR, ah        ; Save minor version number
  263.  
  264. ;----------------------------
  265. ; L    Combine the stack into DGROUP so that it is addressable from DGROUP.
  266. ;    Initialize STACK_BOTTOM.
  267.  
  268.     lea    bx, __end        ; Get pointer to end of data
  269.  
  270. if    @Model    eq    1        ; Ensure that Stack bottom at paragraph
  271.     and    bx, 0fff0h        ; Truncate to lower paragraph
  272.     add    bx, 16            ; Add one paragraph
  273. endif
  274.  
  275.     mov    STACK_BOTTOM, bx    ; Save it
  276.  
  277. if    @Model    eq    1        ; Get stack size
  278.     add    bx, STACK_SIZE        ; DI = stack size
  279. else
  280.     add    bx, sp            ; DI = stack size
  281. endif
  282.  
  283.     mov    dx, ds            ; Get DGROUP segment address
  284.     mov    ss, dx            ; Reset SS
  285.     mov    sp, bx            ; Reset SP
  286.  
  287. ;----------------------------
  288. ; M    Release all memory above program.  Calculate the size of the program
  289. ;    in paragraphs (16 bits).  BX starts with Stack Top
  290.  
  291.     mov    cl, 4            ; Convert to #para by dividing by 16
  292.     shr    bx, cl            ; Do division by bit shifting
  293.  
  294. if    @Model    ne    1        ; Needed in non-Tiny memory models
  295.     mov    ax, ds            ; AX => DGROUP
  296.     sub    ax, PSP            ; AX = # para for code
  297.     add    bx, ax            ; BX = # para in program
  298. endif
  299.  
  300.     mov    ah, 4ah            ; Request DOS set block
  301.     int    21h            ; Call DOS
  302.  
  303. ;----------------------------
  304. ; N    See if there are any command line arguments.  If not, all command
  305. ;    line processing is skipped and execution jumps to loading the
  306. ;    process name onto the stack.
  307.  
  308.     xor    dx, dx            ; Ensure DX is null
  309.     push    dx            ; Ensure null on top of stack
  310.     mov    bp, sp            ; BP = top of stack
  311. if @Model NE 1
  312.     cmp    es:PARM_LEN, 0        ; Are there any Command Line arguments
  313. else
  314. assume    ds:PSP_SEG
  315.     cmp    PARM_LEN, 0        ; Are there any Command Line arguments
  316. assume    ds:DGROUP
  317. endif
  318.     je    SU1            ; No, go load filename
  319.  
  320. ;----------------------------
  321. ; O    There are command line arguments.  Parse them onto the stack and
  322. ;    build ARGC and ARGV.  Start this by transferring the entire command
  323. ;    line tail onto the stack.  Make room for them by moving SP.
  324.  
  325. if @Model NE 1
  326.     mov    ds, PSP            ; DS => PSP
  327. endif
  328. assume ds:PSP_SEG
  329.     mov    cl, PARM_LEN        ; Get # of bytes in Command Line
  330.     inc    cx            ; increase by one
  331.     and    cx, 0feh        ; Force an even count
  332.     mov    ax, sp            ; Get SP
  333.     sub    ax, cx            ; Subtract PARM_LEN
  334.     mov    sp, ax            ; Reset SP, room on Stack
  335.     lea    si, PARMS        ; Load source addr in SI
  336.     mov    di, sp            ; Load destin addr in DI
  337. if @Model NE 1
  338.     mov    es, DGRP        ; ES => DGROUP
  339. endif
  340. assume    es:DGROUP
  341.     rep    movsb            ; Move Command Line onto the Stack
  342. if @Model NE 1
  343.     mov    ds, es:DGRP        ; Restore DS
  344. endif
  345. assume    ds:DGROUP
  346.     
  347. ;----------------------------
  348. ; P    Move the entire d:path\filename.ext onto the stack as *argv[0].
  349.  
  350. SU1:    mov    es, ENVIRON        ; ES => ENVIRON seg
  351.     xor    di, di            ; ES:DI => 1st char in environment
  352.     mov    cx, -1            ; Make cx arbitarily large
  353.     mov    ax, di            ; AL = null
  354. SU2:    repne    scasb            ; Find null
  355.     cmp    al, es:[di]        ; Is next byte a null also?
  356.     jne    SU2            ; No, continue search
  357.     add    di, 3            ; ES:DI => 1st char in filename
  358.     mov    si, di            ; SI => 1st char in filename
  359.     mov    cx, -1            ; CX = max count
  360.     xor    al, al            ; AL = null
  361.     repne    scasb            ; Find the terminating null
  362.     neg    cx            ; CX = length + null + 1
  363.     dec    cx            ; CX = length + null
  364.     and    cx, 0feh        ; Force an even count
  365.     mov    es, DGRP        ; ES => STACK
  366. assume    es:DGROUP
  367.     mov    ds, ENVIRON        ; DS:SI => 1st char in filename
  368.     sub    sp, cx            ; Make room for it
  369.     mov    di, sp            ; ES:DI => where to put it
  370.     rep    movsb            ; Move it onto the stack
  371.     mov    ds, es:DGRP        ; Reset DS
  372.  
  373. ;-----------------------------
  374. ; Q    Convert all blanks, not within double quotes, in the Command Line
  375. ;    to Nulls.  CX is used as IN_LITERAL_FLAG.  Build ARGV at the same
  376. ;    time.
  377.  
  378.     xor    di, di            ; DI set to zero, DI = arg count
  379.     mov    bx, bp            ; BX points to last byte in stack
  380.     mov    bp, sp            ; BP is the stop point
  381.     xor    cx, cx            ; Clear IN_LITERAL_FLAG
  382. SU3:    mov    al, [bx]        ; Get byte
  383.     cmp    al, '"'            ; Is it a literal?
  384.     jne    SU4            ; No, go to next test
  385.     inc    cx            ; Set IN_LITERAL_FLAG
  386.     and    cx, 1            ; Ensure only 0, & 1 valid
  387.     jmp    short SU5        ; Continue, and blank '"'
  388. SU4:    cmp    al,' '            ; Is it a blank?
  389.     ja    SU7            ; No, go set up to get another
  390.     or    cx, cx            ; Is IN_LITERAL_FLAG clear?
  391.     jne    SU7            ; No, do not null blank
  392. SU5:    mov    byte ptr [bx], 0    ; Store Nul in [BX]
  393. SU6:    or    byte ptr [bx + 1], 0    ; Was the previous char null?
  394.     jz    SU7            ; Yes, do not push pointer
  395. if @datasize
  396.     push    ss            ; Push segment address
  397. endif
  398.     mov    ax, bx            ; AX => Null
  399.     inc    ax            ; AX => 1st char
  400.     push    ax            ; Push the offset
  401.     xor    cx, cx            ; Clear in literal flag
  402.     inc    di            ; Account for another arg
  403. SU7:    dec    bx            ; BX point to next byte
  404.     cmp    bx, bp            ; Are we through yet?
  405.     jnb    SU3            ; No, go one mo' 'gin
  406.  
  407. ;----------------------------
  408. ; R    Account for the last argrument.
  409.  
  410. if @datasize
  411.     push    ss            ; Push segment address
  412. endif
  413.     inc    bx            ; Adjust BX to the last char
  414.     push    bx            ; Push the offset
  415.     inc    di            ; Account for another arg
  416.  
  417. ;-----------------------------
  418. ; S    Have finished building *argv[].    SP => argv[], and DI = argc.
  419. ;    Create argc and argv on the stack using the FORTRAN calling
  420. ;    convention.  If SIMPLE is defined, push only argc.  See documentation
  421. ;    above for structure of proc declaration in MAIN procedure
  422.  
  423. ifndef SIMPLE
  424.     mov    bx, sp            ; BX = **argv[]
  425.     push    di            ; Push argc
  426. if @DataSize
  427.     push    ss            ; Long pointer
  428. endif
  429.     push    bx            ; Push **argv[]
  430. else
  431.     push    di            ; Push argc
  432. endif
  433.     
  434. ;-----------------------------
  435. ; T    call MAIN
  436.  
  437. SU8:    call    Main            ; Call MAIN procedure
  438.  
  439. ;----------------------------
  440. ; U    If main returns, the program is to terminate with the control code
  441. ;    returned in AL
  442.  
  443.     mov    ah, 4ch            ; End process
  444.     int    21h            ; Call DOS
  445.  
  446. % Start_Up2    endp
  447.  
  448. %    end    Start_Up2        ; Indicate that Start_Up2 is the start
  449.                     ; of the program
  450.