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

  1.     page 60,132
  2.     title Start_Up3 -- Complete Start Up Code for .EXE Programs
  3.     name START_UP3
  4.  
  5. comment ÷
  6.         Start_UP3                                               V1.07
  7. --------------------------------------------------------------------------
  8. NAME
  9.     startup3    Complete start up code for .com and .exe programs
  10.  
  11. SYNOPSIS
  12.     extern Start_Up3
  13.     or
  14.     extern Start_Up3S
  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 the 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.     The environment is parced and *envp[] is made available to main.
  29.     
  30.     This procedure performs the following functions in addition to above
  31.     - Initializes the following global variables:
  32.       -- PSP, segment address of PSP
  33.         -- DGRP, segment address of DGROUP
  34.       -- ENVIRON, segment address of passed copy of the ENVIRONMENT
  35.       -- NEXTPARA, segment address of next memory paragraph
  36.       -- STACK_BOTTOM, offset of stack bottom in DGROUP
  37.       -- OSMAJOR, integer part of OS system
  38.       -- OSMINOR, decimal part of OS system
  39.       -- ENV_BRK, Offset to the end of the environmental strings
  40.       -- ENV_STR_LEN, Length of environmental strings
  41.     - Initializes DS and ES segment registers to DGROUP
  42.     - Shrinks memory down to size of program by releasing all memory
  43.       above program
  44.     - If moving the environmental strings onto the stack, will case
  45.       DGROUP to exceed 64K bytes, abort with error message
  46.  
  47. RETURNS
  48.     If main returns to startup code.  The program terminiates with the 
  49.     return code in AL.
  50.  
  51. PROGRAMING NOTES
  52.     Requires Microsoft MASM V6.11d.
  53.  
  54.     Written to link with any memory model.    If using the Tiny Memory
  55.     Model, this source code must the first linked because execution must
  56.     begin in this source code.
  57.  
  58.     Use MEMMOD to specify the memory model.
  59.     /dMEMMOD=TINY|SMALL|COMPACT|MEDIUM|LARGE|HUGE
  60.  
  61.     Written using the FORTRAN/PASCAL/BASIC calling convention so passed
  62.     parameters are pushed in the order of appearance in the proc 
  63.     declaration.
  64.  
  65.     This procedure can pass argc and argv on stack two ways.   The proc
  66.     declaration in the MAIN procedure will differ depending upon the 
  67.     choice.
  68.     
  69.     The default requires the following proc declaration:
  70.     
  71.         MAIN proc ARGC:word, ARGV:ptr
  72.     
  73.     If SIMPLE is defined, an alternate proc declaration is required:
  74.     
  75.         MAIN proc ARGV:ptr, ARGC:word
  76.     
  77.     Here, ARGV is not a pointer to an array of pointers but the location
  78.     of the 1st pointer.
  79.  
  80.     In Huge memory model, the pointers passed in ARGV are long pointers
  81.     vice huge pointers.
  82.  
  83. MEMORY REQUIREMENTS    (using 286 instructions set)
  84.     (in bytes)    Tiny   Small   Medium  Compact     Large    Huge
  85.     Code:         366    395    397      403      405    405
  86.     Code (SIMPLE):     365    394    396      401      403    403
  87.     _Data:           0      0      0        0        0      0
  88.     Const:          60     60     60       60       60     60
  89.     _BBS:          14     14     14       14       14     14
  90.     Stack:           ?      ?      ?        ?        ?      ?
  91.  
  92.     Note:  The 14 bytes in _BSS are from sudata.asm and sudata3.asm
  93.     which is used so that all startup code can reside in the same
  94.     .lib file.
  95.  
  96.     The first code size is for when SIMPLE not defined.  The Code
  97.     (SIMPLE) size is for when SIMPLE is defined.
  98.  
  99.     Stack usage is determined by the size of and the number of arguments
  100.     in the command line.
  101.  
  102. CAUTION
  103.     Startup3 defines a 2K byte stack.  This should be enough for programs
  104.     that make moderate use of the stack.  If automatic variables are used
  105.     extensively, more stack space should be defined in the main module
  106.     unless using the tiny memory model.  In this case, the startup code
  107.     must be the first souce file in the build, change the size of the
  108.     STACK_SIZE define.
  109.  
  110.     Linker option, NO IGNORE CASE, is not used so that the linker will
  111.     handle the __end reference properly.
  112.  
  113. EXTERNAL LIBRARIES
  114.     sudata        alib?
  115.     sudata3     alib?
  116.  
  117. EXTERNAL PROCEDURES
  118.     main        user defined
  119.  
  120. INTERUPTS CALLED
  121.     Int 21h 30h - Get Version Number
  122.     Int 21h 4ah - Set Memory Block Size
  123.     Int 21h 4ch - Terminate program with return code
  124.  
  125. GLOBAL NAMES
  126.     Startup_3 or Startup_3S
  127.  
  128. AUTHOR
  129.     Raymond Moon - 7 Sep 87
  130.  
  131.         Copyright (c) 1987, 1988, 1994, 1995, 1996 - MoonWare
  132.     ALL RIGHTS RESERVED
  133.  
  134. VERSION
  135.     Version    - Date        - Remarks
  136.     1.00    -  7 Sep 87    - Original
  137.     1.01    - 13 Feb 88    - Updated to program name as argv[0]
  138.     1.02    - 13 Aug 88    - Updated to MASM 5.1
  139.     1.03    - 10 Oct 88    - Added STACK_BOTTOM & ZZ_PRGM_TOP segment
  140.                   to determine end of data.
  141.     1.04    - 30 Oct 94    - Moved ZZ_PRGM_TOP segment position in file.
  142.                 - Removed increment in program size in paras
  143.                     as ZZ_PRGM_TOP is aligned on a para.
  144.     1.05    - 20 Apr 95    - Added TINY Model capability
  145.                 - Converted to .dosseg using __end vice
  146.                   ZZ_PRGM_TOP for end of data
  147.     1.06    - 15 Dec 95    - Removed checking for DOS 1.X and earlier
  148.                   for adding ".asm" if DOS is earlier than
  149.                   3.0.
  150.         1.06    - 29 Dec 96     - Optimized the .com coding
  151. ==========================================================================
  152.     ÷  Commend End
  153.  
  154. ;-----------------------------
  155. ; A    Make the small memory model the default
  156.  
  157. ifndef memmod
  158. memmod    equ    <small>
  159. endif
  160.  
  161. ;----------------------------
  162. ; B    Include the processor, memory model, associate ES register with
  163. ;    DGROUP, and specify DOS segment order
  164.  
  165.     include procesor.inc
  166. %    .MODEL    memmod,FORTRAN
  167.     assume    es:DGROUP
  168.     .dosseg
  169.  
  170. ;----------------------------
  171. ; C    Required includes
  172.  
  173.     include startup.inc
  174.  
  175. ;----------------------------
  176. ; D    Define any required equates.  Change this value if a larger
  177. ;    stack is needed in the Tiny memory model
  178.  
  179. STACK_SIZE    equ    2048
  180. STDERR        equ       2
  181.  
  182. ;=========================================================================
  183. ;    DATA
  184. ;=========================================================================
  185. ; E    Define storage for the various global and system variables and
  186. ;    constants.
  187.  
  188.     .CONST
  189.  
  190. DG_OVRFL    db    'DGROUP exceeds 64K bytes'
  191. DG_OVRFL_LEN    equ    $ - DG_OVRFL
  192. LIM_MEM        db    'Insufficient memory to expand DGROUP'
  193. LIM_MEM_LEN    equ    $ - LIM_MEM
  194.  
  195.     .DATA?
  196.  
  197. if    @Model    NE  1
  198.     .STACK    STACK_SIZE    ; Define a nominal stack
  199. endif
  200.  
  201. @CurSeg ends
  202.  
  203. ;----------------------------
  204. ; F    Define __end which is defined when using .dosseg directive.
  205. ;    Remember not to use the NO IGNORE CASE linker option.
  206.  
  207. externdef    __end:byte
  208.  
  209. ;----------------------------
  210. ; G    Define segment for addressing information in the PSP.
  211.  
  212. PSP_SEG    segment at 00h
  213.     
  214.     org    2h
  215. NEXTPARA_PTR    dw    ?        ; Segment address of next memory para
  216.  
  217.     org    2ch
  218. ENVIRON_PTR    dw    ?        ; Segment address of Environment
  219.  
  220.     org     80h
  221. PARM_LEN     db    ?        ; Number of bytes in Command Line tail
  222. PARMS       db    127 dup(?)    ; Start of Command Line tail
  223. PSP_SEG    ends
  224.  
  225. ;=========================================================================
  226. ;    CODE
  227. ;=========================================================================
  228. ; H    Put the called main procedure in the proper relationship to the
  229. ;    startup code.
  230.  
  231. if @CodeSize
  232. extrn    Main:far
  233. .CODE
  234. else
  235. .CODE
  236. extrn    Main:near
  237. endif
  238.  
  239. ;-----------------------------
  240. ; I    Include org statement if tiny model
  241.  
  242. if    @Model    EQ 1
  243.     org    100h
  244. endif
  245.  
  246. ;-----------------------------
  247. ; J    Start the Start_Up2 code.  Make it a far procedure so error return
  248. ;    will work.  If SIMPLE is defined, redefined Start_Up2 as Start_Up2S.
  249.  
  250. ifdef SIMPLE
  251. Start_Up3    equ    <Start_Up3S>
  252. endif
  253.  
  254. % Start_Up3    proc    far
  255.  
  256. ;-----------------------------
  257. ; K     First, initialize global variables.  Set DS to DGROUP.
  258. ;    Skip DGROUP code for .com(Tiny) memory models
  259.  
  260. if    @Model    NE 1
  261.  
  262.     mov    ax, DGROUP        ; Get seg address of DGROUP
  263.     mov    ds, ax            ; Initialize DS segment register
  264.     mov    DGRP, ax        ; Initialize DGRP
  265. assume    es:PSP_SEG
  266. else
  267.     mov    DGRP, ds        ; Initialize DGRP
  268. endif
  269.     mov    PSP, es            ; Initialize PSP
  270. if    @Model    eq 1
  271. assume    ds:PSP_SEG
  272. endif
  273.     mov    bx, ENVIRON_PTR     ; Get segment address of environment
  274.     mov    cx, NEXTPARA_PTR    ; Get segment address of next memory
  275. if    @Model    eq 1
  276. assume    ds:DGROUP
  277. endif
  278.     mov    ENVIRON, bx        ; Initialize ENVIRON
  279.     mov    NEXTPARA, cx        ; Initialize NEXTPARA
  280.     mov    ah, 30h            ; Get DOS version number
  281.     int    21h            ; Call DOS
  282.     mov    OSMAJOR, al        ; Save major version number
  283.     mov    OSMINOR, ah        ; Save minor version number
  284.  
  285. ;----------------------------
  286. ; L    Combine the stack into DGROUP so that it is addressable from DGROUP.
  287. ;    Initialize STACK_BOTTOM.
  288.  
  289.     lea    bx, __end        ; Get pointer to end of data
  290.  
  291. if    @Model    eq    1        ; Ensure that Stack bottom at paragraph
  292.         add     bx, 15                  ; Add to ensure next para if necessary
  293.         and     bx, 0fff0h              ; Truncate to a paragraph boundary
  294. endif
  295.  
  296.     mov    STACK_BOTTOM, bx    ; Save it
  297.  
  298. if    @Model    eq    1        ; Get stack size
  299.     add    bx, STACK_SIZE        ; DI = stack size
  300. else
  301.     add    bx, sp            ; DI = stack size
  302. endif
  303.  
  304.     mov    dx, ds            ; Get DGROUP segment address
  305.     mov    ss, dx            ; Reset SS
  306.     mov    sp, bx            ; Reset SP
  307.  
  308. ;-----------------------------
  309. ; M    Find the end of the environmental strings.  Save the length for
  310. ;    later.    Ensure that length is multiple of word length.    Since
  311. ;    the string is double null terminated, the string length saved will
  312. ;    end with one or two nulls.
  313.  
  314.     mov    es, ENVIRON        ; ES => ENVIRON seg
  315.     xor    di, di            ; ES:DI => 1st char in environment
  316.     mov    cx, -1            ; Make cx arbitarily large
  317.     mov    ax, di            ; AL = null
  318. SU1:    repne    scasb            ; Find null
  319.     cmp    al, es:[di]        ; Is next byte a null also?
  320.     jne    SU1            ; No, continue search
  321.     inc    di            ; Pad string for next op
  322.     and    di, 0fffeh        ; Force to an even boundary
  323.     mov    ENV_STR_LEN, di        ; Save it
  324.     add    di, 15            ; Add to ensure next para if necessary
  325.     and    di, 0fff0h        ; Truncate to a paragraph boundary
  326.  
  327. ;----------------------------
  328. ; N    Release all memory above program.  Include room for the environmental
  329. ;    variables by adjusting SP.  Check to see if adding environmental
  330. ;    strings increases DGROUP size to greater than 64K.  If so, tell user
  331. ;    and terminate with error return
  332.  
  333.     mov    es, PSP            ; ES => PSP
  334.     add    bx, di            ; Add room for environmental variables
  335.     jnc    SU2            ; No overflow, DGROUP < 64K
  336.     lea    dx, DG_OVRFL        ; DX => message
  337.     mov    cx, sizeof DG_OVRFL    ; CX => # bytes
  338.     mov    bx, STDERR        ; To console
  339.     mov    ah, 40h            ; DOS write to file/device
  340.     int    21h            ; Call DOS
  341.     mov    al, 80h            ; Error return code
  342.     jmp    SU14
  343. SU2:    mov    sp, bx            ; Adjust SP
  344.     shr    bx, 4            ; Convert to #para by dividing by 16
  345. if    @Model    ne    1
  346.     mov    ax, ds            ; AX => DGROUP
  347.     sub    ax, PSP            ; AX = # para for code
  348.     add    bx, ax            ; BX = # para in program
  349. endif
  350.     mov    ah, 4ah            ; Request DOS set block
  351.     int    21h            ; Call DOS
  352.     jnc    SU3            ; No error
  353.     lea    dx, LIM_MEM        ; Tell user, DX => message
  354.     mov    cx, sizeof LIM_MEM    ; Message length
  355.     mov    bx, STDERR        ; To console
  356.     mov    ah, 40h            ; DOS write to file/device
  357.     int    21h            ; Call DOS
  358.     mov    al, 81h            ; Error return code
  359.     jmp    SU14            ; Go to the exit code
  360.         
  361. ;----------------------------
  362. ; O    Transfer the environmental strings onto the stack.  Ensure that the
  363. ;    last string ends with a null by pushing a null word onto the stack.
  364.  
  365. SU3:    mov    cx, ENV_STR_LEN        ; CX = count
  366.     mov    di, sp            ; DI => top of stack
  367.     sub    di, cx            ; DI => new SP
  368.     mov    sp, di            ; Make room for environmental strings
  369. assume    es:DGROUP
  370. if @Model NE 1
  371.     mov    es, DGRP        ; ES:DI => top of stack
  372. endif
  373.     xor    si, si            ; SI => start of environmental strings
  374.     mov    ds, ENVIRON        ; DS:SI => start of environ strings
  375.     rep    movsb            ; Move them
  376.     mov    ds, es:DGRP        ; Restore DS
  377.     mov    bx, di            ; Save for later
  378.     push    0            ; Push Null address
  379. if    @DataSize
  380.     push    0            ; Null Pointer
  381. endif
  382.  
  383. ;----------------------------
  384. ; P    DI points to the top of the environmental strings. Build *enpr[]
  385. ;    by pushing pointers to the start of each string onto the stack.
  386. ;    The last pointer in the array must be a null to signify the end of
  387. ;    the array.
  388.  
  389.     mov    cx, ENV_STR_LEN        ; CX = count
  390.     dec    di            ; Adjust DI to point to last char
  391. SU4:    or    byte ptr [di], 0    ; Is it a null?
  392.     jnz    SU5            ; No, have reached a char
  393.     dec    di            ; Yes, decrement DI
  394.     dec    cx            ; Account for char checked
  395.     jmp    SU4            ; Check next char
  396. SU5:    or    byte ptr [di], 0    ; Is it a null?
  397.     jnz    SU6            ; No, continue
  398.     mov    ax, di            ; AX => null
  399.     inc    ax            ; AX => 1st char
  400. if    @DataSize
  401.     push    ss            ; Large data models, push seg addr
  402. endif
  403.     push    ax            ; Push offset
  404. SU6:    dec    di            ; DI => next char
  405.     loop    SU5            ; Not at the end, continue
  406. if    @DataSize
  407.     push    ss            ; Large data models, push seg addr
  408. endif
  409.     inc    di            ; Point to last char
  410.     push    di            ; Push offset
  411.     mov    dx, sp            ; Save the pointer to the *envp[]
  412.  
  413. ;----------------------------
  414. ; Q    See if there are any command line arguments.  If not, all command
  415. ;    line processing is skipped.
  416.  
  417. if @Model NE 1
  418. assume    es:PSP_SEG
  419.     mov    es, PSP            ; ES => PSP
  420. endif
  421.     xor    ax, ax            ; Ensure AX is null
  422.     push    ax            ; Ensure null on top of stack
  423.     mov    bp, sp            ; BP = top of stack
  424. if @Model NE 1
  425.     cmp    es:PARM_LEN, 0        ; Are there any Command Line arguments
  426. else
  427. assume    ds:PSP_SEG
  428.     cmp    PARM_LEN, 0        ; Are there any Command Line arguments
  429. assume    ds:DGROUP
  430. endif
  431.     je    SU7            ; Yes, go process what is on the stack
  432.  
  433. ;----------------------------
  434. ; R    There are command line arguments.  Transferring the entire command
  435. ;    line tail onto the stack. 
  436.  
  437. if @Model NE 1
  438.     mov    cl, es:PARM_LEN        ; Get # of bytes in Command Line
  439. else
  440. assume    ds:PSP_SEG
  441.     mov    cl, PARM_LEN        ; Get # of bytes in Command Line
  442. assume    ds:DGROUP
  443. endif
  444.     inc    cx            ; increase by one
  445.     and    cx, 0feh        ; Force an even count
  446.     mov    ax, sp            ; Get SP
  447.     sub    ax, cx            ; Subtract PARM_LEN
  448.     mov    sp, ax            ; Reset SP, room on Stack
  449. if @Model NE 1
  450.     lea    si, es:PARMS        ; Load source addr in SI
  451. else
  452. assume    ds:PSP_SEG
  453.     lea    si, PARMS        ; Load source addr in SI
  454. assume    ds:DGROUP
  455. endif
  456.     mov    di, sp            ; Load destin addr in DI
  457. if @Model NE 1
  458.     mov    es, DGRP        ; ES => DGROUP
  459. assume    es:DGROUP
  460.     mov    ds, PSP            ; DS => PSP
  461. endif
  462.     rep    movsb            ; Move Command Line onto the Stack
  463. if @Model NE 1
  464.     mov    ds, es:DGRP        ; Restore DS
  465. endif
  466.     
  467. ;----------------------------
  468. ; S    Move the entire d:path\filename.ext onto the stack as *argv[0].
  469.  
  470. SU7:    mov    es, ENVIRON        ; ES => ENVIRON seg
  471.     mov    di, ENV_STR_LEN        ; ES:DI => end of environment
  472.     or    byte ptr es:[di + 1], 0 ; Is there another null byte?
  473.     jnz    SU8            ; No, continue
  474.     inc    di            ; ES:DI => true end of environment
  475. SU8:    add    di, 3            ; ES:DI => 1st char in filename
  476.     mov    si, di            ; SI => 1st char in filename
  477.     mov    cx, -1            ; CX = max count
  478.     xor    al, al            ; AL = null
  479.     repne    scasb            ; Find the terminating null
  480.     neg    cx            ; Convert to positive number
  481.     sub    cx, 2            ; Correct for starting @ -1 and neg
  482.     and    cx, 0fffeh        ; Force an even count
  483.     mov    es, DGRP        ; ES => STACK
  484. assume    es:DGROUP
  485.     mov    ds, ENVIRON        ; DS:SI => 1st char in filename
  486.     sub    sp, cx            ; Make room for it
  487.     mov    di, sp            ; ES:DI => where to put it
  488.     rep    movsb            ; Move it onto the stack
  489.     mov    ds, es:DGRP        ; Reset DS
  490.     
  491. ;-----------------------------
  492. ; T    Convert all blanks, not within double quotes, in the Command Line
  493. ;    to Nul.  CX is LITERAL_FLAG.  Build argv[] at the same time.
  494.  
  495.     xor    di, di            ; DI set to zero, DI = arg count
  496.     mov    bx, bp            ; BX points to last byte in stack
  497.     dec    bx            ; Start on the second character
  498.     mov    bp, sp            ; BP is the stop point
  499.     xor    cx, cx            ; Clear LITERAL FLAG
  500. SU9:    mov    al, [bx]        ; Get byte
  501.     cmp    al, '"'            ; Is it a literal?
  502.     jne    SU10            ; No, go to next test
  503.     inc    cx            ; Set LITERAL_FLAG
  504.     and    cx, 1            ; Ensure only 0, & 1 valid
  505.     jmp    short SU11        ; Continue, and blank '"'
  506. SU10:    or    al, al            ; Is it a null?
  507.     je    SU12
  508.     cmp    al, ' '            ; Is it a blank?
  509.     ja    SU13            ; No, go set up to get another
  510.     or    cx, cx            ; Is LITERAL_FLAG clear?
  511.     jnz    SU13            ; No, do not null blank
  512. SU11:    mov    byte ptr [bx], 0    ; Store Nul in [BX]
  513. SU12:    or    byte ptr [bx + 1], 0    ; Was the previous char null?
  514.     jz    SU13            ; Yes, do not push pointer
  515. if @datasize
  516.     push    ss            ; Push segment address
  517. endif
  518.     mov    ax, bx            ; AX => Null
  519.     inc    ax            ; AX => 1st char
  520.     push    ax            ; Push the offset
  521.     xor    cx, cx            ; Clear in literal flag
  522.     inc    di            ; Account for another arg
  523. SU13:    dec    bx            ; BX point to next byte
  524.     cmp    bx, bp            ; Are we through yet?
  525.     jnb    SU9            ; No, go one mo' 'gin
  526.  
  527. ;----------------------------
  528. ; U    Account for the last argrument.
  529.  
  530. if @datasize
  531.     push    ss            ; Push segment address
  532. endif
  533.     inc    bx            ; Adjust BX to the last char
  534.     push    bx            ; Push the offset
  535.     inc    di            ; Account for another arg
  536.  
  537. ;-----------------------------
  538. ; V    Have finished building *envp[].  DX => envp[0], SP => argv[], and
  539. ;    DI = argc.  Create argc and argv on the stack using the FORTRAN
  540. ;    calling convention.  If SIMPLE is defined, push only argc.  See
  541. ;    documentation above for structure of proc declaration in MAIN
  542. ;    procedure
  543.  
  544.     mov    ax, dx            ; AX = **envp
  545.     mov    dx, sp            ; DX = *argv[]
  546. ifndef    SIMPLE                ; SIMPLE NOT selected
  547.     push    di            ; Push argc
  548. if @DataSize
  549.     push    ss            ; Push segment register if required
  550. endif
  551.     push    dx            ; Put **argv onto the stack
  552. else                    ; SIMPLE selected
  553.     push    di            ; Push argc
  554. endif
  555.  
  556. ;----------------------------
  557. ; W    The last thing to do is push envpr onto the stack
  558.  
  559. if @DataSize
  560.     push    ss            ; Push segment register if required
  561. endif
  562.     push    ax            ; Push envp onto stack
  563.  
  564. ;-----------------------------
  565. ; X    call MAIN
  566.  
  567.     call    MAIN            ; Call MAIN procedure
  568.  
  569. ;----------------------------
  570. ; Y    If main returns, the program is to terminate with the control code
  571. ;    returned in AL
  572.  
  573. SU14:    mov    ah, 4ch            ; End process
  574.     int    21h            ; Call DOS
  575.  
  576. % Start_Up3    endp
  577.  
  578. %    end    Start_Up3        ; Indicate that START_UP3 is the start
  579.                     ; of the program
  580.