home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / SOURCE / STARTUP / DOS / CRT0.AS_ / CRT0.AS
Encoding:
Text File  |  1993-02-08  |  14.0 KB  |  623 lines

  1.     page    ,132
  2.     title    crt0 - C start up routine
  3. ;***
  4. ;crt0.asm - C start up routine
  5. ;
  6. ;    Copyright (c) 1985-1992, Microsoft Corporation.  All rights reserved.
  7. ;
  8. ;Purpose:
  9. ;    How startup works in a few words -
  10. ;
  11. ;    The startup and termination is performed by a few modules
  12. ;
  13. ;        crt0.asm    DOS 2.x/3.x specific init/term
  14. ;        crt0msg.asm    DOS 2.x/3.x error messages
  15. ;        (winstart.asm)    Windows specific init/term (not included)
  16. ;
  17. ;        crt0dat.asm    remainder of shared DOS 3.x init/term
  18. ;
  19. ;    *************  IMPORTANT  *****************************************
  20. ;
  21. ;    The "DOSSEG" directive in this module must not be removed or else
  22. ;    the user will have to link with the "/DOSSEG" linker switch in
  23. ;    order to get proper segment ordering.
  24. ;
  25. ;    See the C documentation for more information about the /DOSSEG switch.
  26. ;
  27. ;    All assembler modules must be assembled with the /Mx switch, i.e.
  28. ;
  29. ;        masm -Mx crt0,;
  30. ;
  31. ;    .COM Files:
  32. ;    (1) Start at location 0x100
  33. ;    (2) No stack segment
  34. ;    (3) All segments grouped together
  35. ;    (4) All seg registers the same at _astart.
  36. ;
  37. ;*******************************************************************************
  38.  
  39. ;*******************************;*
  40.     DOSSEG            ;* specifies DOS SEGment ordering *
  41. ;*******************************;*
  42.  
  43. ?DF=    1            ; this is special for c startup
  44.  
  45. .xlist
  46. include version.inc
  47.  
  48. include cmacros.inc
  49. include msdos.inc
  50. include defsegs.inc
  51. include heap.inc
  52. include rterr.inc
  53. .list
  54.  
  55.     _DEBUGSCREEN equ 1    ; debug screen swapping
  56.     _FATALHOOK equ 1        ; enable fatal hook code
  57.  
  58. ifdef FARSTACK
  59. ife sizeD
  60.     error <You cannot have a far stack in Small or Medium memory models.>
  61. endif
  62. endif
  63.  
  64. ifdef    _COM_
  65.     if sizeC or sizeD
  66.     error <Must use Small memory model for .COM files.>
  67.     endif
  68. endif    ;_COM_
  69.  
  70.     page
  71. ;===========================================================================
  72. ;
  73. ;    Segment definitions
  74. ;
  75. ;    The segment order is essentially the same as in XENIX.
  76. ;    This module is edited after assembly to contain a dosseg comment
  77. ;    record for the linker.
  78. ;
  79. ;===========================================================================
  80.  
  81. CrtDefSegs <code,etext,data>
  82. CrtDefSegs <xiqcseg>
  83.  
  84. ifndef _COM_
  85. CrtDefSegs <stack>
  86. else
  87. DefGrpCom            ; Group all segments in DGROUP
  88. endif
  89.  
  90. codeOFFSET equ    offset _TEXT:
  91. dataOFFSET equ    offset DGROUP:
  92.  
  93.  
  94. page
  95.  
  96. public    __acrtused        ; trick to force in startup
  97.     __acrtused = 9876h    ; funny value not easily matched in SYMDEB
  98.  
  99.  
  100. extrn    __acrtmsg:abs        ; trick to pull in startup messages
  101.  
  102.  
  103. _STACK_SIZE = 2048        ; Default stack size = 2K
  104.  
  105. ifndef _COM_
  106. sBegin    stack
  107. assumes ds,data
  108.     db    _STACK_SIZE dup (?)    ; stack space
  109. sEnd
  110. endif    ;_COM_
  111.  
  112. ifdef FARSTACK
  113. ; Set up the first entry in the near heap
  114. ; (see defsegs.inc definition of <stack>)
  115. sBegin stubheap
  116.       stubheap_size    dw    1        ; 0-length free entry
  117.       stubheap_next    dw    _HEAP_END    ; mark end of heap
  118. sEnd
  119. endif ;FARSTACK
  120.  
  121. page
  122.  
  123. externP main            ; C main program
  124.  
  125. externP exit            ; exit ( code )
  126.  
  127. if    sizeC
  128. extrn    __exit:far        ; _exit ( code) (cmacros name conflict)
  129. else
  130. extrn    __exit:near
  131. endif
  132.  
  133.  
  134. ifdef _DEBUGSCREEN
  135. CrtDefSegs <dbdata>
  136. sBegin    dbdata            ; Debugger Screen swap setup segment
  137. assumes ds,data
  138. globalW  __aDBswpflg,0            ; Flag == __aDBswpyes if should attempt swapping
  139. globalW  __aDBswpchk,___aDBretaddr    ; By default points to a model dependent ret
  140. globalW  __aDBrterr,___aDBretaddr    ;
  141. globalW  __aDBexit,___aDBretaddr    ; (Report we are exiting)
  142. staticD  __aDBcallbk,0            ; Call back address to debugger
  143. sEnd
  144.     public    __aDBdoswp
  145. __aDBdoswp    =    0d6d6h
  146. endif    ; _DEBUGSCREEN
  147.  
  148. sBegin    xiqcseg
  149. externW    __qczrinit            ;* QC -Zr initializer call address
  150. sEnd
  151.  
  152. sBegin    data
  153.  
  154. extrn    __edata:byte        ; end of data (start of bss)
  155. extrn    __end:byte        ; end of bss (start of stack)
  156.  
  157. externW _psp            ; psp:0 (paragraph #)
  158. externW __argc
  159. externDP __argv
  160. externDP _environ
  161. externW _osversion        ; byte-swapped OS version 
  162. externW _osver            ; OS version (usable byte order)
  163.  
  164. ;    these are used by DOS C memory management (not used in Windows)
  165.  
  166. globalW _atopsp,0        ; top of stack (heap bottom)
  167. globalW _aexit_rtn,<codeoffset __exit> ; NEAR pointer
  168.  
  169. ;*
  170. ;*    The following (_asizds and _nheap_desc) must be in this order!
  171. ;*
  172.  
  173. globalW _asizds,0        ; DGROUP size - 1 (in bytes)
  174.  
  175. labelW    <PUBLIC,_nheap_desc>    ; near heap descriptor
  176. _heap_seg_desc <0,_HEAP_NEAR OR _HEAP_MODIFY, 0,0,0,0,0,0>
  177. .ERRE    flags    eq    2    ; flags better be second word
  178.  
  179. .ERRE    offset _asizds+2 EQ offset _nheap_desc    ; make sure!
  180.  
  181. ; Heap segment limits (for use with QC)
  182.  
  183. globalW _aseghi,0        ; highest heap segment so far
  184. globalW _aseglo,0        ; lowest allowable heap segment
  185.  
  186. ;
  187. ; DOS Extender Flag
  188. ;
  189. globalW _fDosExt,0        ; 0 = no DOS Extender
  190.  
  191.  
  192.  
  193.  
  194. sEnd
  195.  
  196.     page
  197.  
  198.  
  199. externP _cinit            ; run-time initializers
  200.  
  201. externP _NMSG_WRITE        ; pascal - write error message to stdout
  202. externP _FF_MSGBANNER        ; pascal - error message banner
  203.                 ; (includes FORTRAN $DEBUG info)
  204.  
  205. externP _setargv        ; process command line arguments
  206. externP _setenvp        ; process environment
  207.  
  208. ifdef _FATALHOOK
  209. extrn       __farstub:far        ; alternative stub
  210. extrn       __fatalexit(__farstub):far    ; FAR ptr to fatal exit routine
  211. endif
  212.  
  213.  
  214. sBegin    code
  215. ifdef _COM_
  216. assumes cs,DGROUP        ; .com files are all in one segment
  217. else
  218. assumes cs,code
  219. endif
  220.  
  221. assumes ds,nothing
  222.  
  223.  
  224. page
  225. ;***
  226. ;_astart - start of all C programs
  227. ;
  228. ;Purpose:
  229. ;    Startup routine to initialize C run-time environment
  230. ;
  231. ;Entry:
  232. ;
  233. ;Exit:
  234. ;    Exits to DOS via exit().
  235. ;
  236. ;Uses:
  237. ;
  238. ;Exceptions:
  239. ;
  240. ;*******************************************************************************
  241.  
  242. ifdef _COM_
  243.     org    0100h        ; .COM files start at 0100h
  244. endif
  245.  
  246. labelNP <PUBLIC,_astart>    ; start address of all "C" programs
  247.  
  248.  
  249. ;    check MS-DOS version for 2.0 or later
  250.  
  251.     callos    VERSION     ; ax = DOS version
  252.                 ; *** ax gets preserved for a long time ***
  253.     cmp    al,2        ; check for version 2 or later
  254.     jae    setup        ;   yes - continue with setup
  255. ifdef _COM_            ; DOS puts 0 on stack for .COM files
  256.     retn            ; DOS 1.0 exit program (int 20h at psp:0)
  257. else    ; _COM_
  258.     xor    ax,ax
  259.     push    es        ; push warm start vector es:ax = psp:0
  260.     push    ax
  261.     retf            ; DOS 1.0 exit program (int 20h at psp:0)
  262. endif    ; _COM_
  263.  
  264. setup:
  265.  
  266.  
  267. ifdef _COM_
  268.     mov    di,ds        ; di = DGROUP
  269.     mov    si,ds:[DOS_MAXPARA] ; get max. paragraph
  270. else
  271.     mov    di,DGROUP    ; di = DGROUP
  272.     mov    si,ds:[DOS_MAXPARA] ; get max. paragraph
  273. endif    ;_COM_
  274.  
  275. ifdef  _COM_
  276.     mov    cs:[_dataseg],di ; save dgroup for future
  277. endif
  278.  
  279.     sub    si,di        ; si = # para in data area
  280.     cmp    si,1000h    ; if more than 64K
  281.     jb    setSP
  282.  
  283.     mov    si,1000H    ; use full 64K (-16)
  284.  
  285. setSP:
  286.  
  287. ifdef _COM_
  288.     ;
  289.     ; .COM files - allocate stack (-2 for _asizds limit)
  290.     ; [Do the calculation in a temp register in case it overflows.]
  291.     ;
  292.     mov    bx,dataoffset __end ; go to end of DGROUP
  293.     add    bx,(_STACK_SIZE-2) ; stack is beyond that
  294.     jnc    SPok        ; jump out if stack ok (ax = new sp)
  295.     ;fall thru        ; error - not enough stack space
  296.  
  297. else    ;!_COM_
  298.  
  299. ifdef FARSTACK
  300.     jmp    short SPok    ; stack can't be too big, if .EXE was loaded
  301. else ;!FARSTACK
  302.     cli            ; turn off interrupts
  303.     mov    ss,di        ; SS = DGROUP
  304.     add    sp,dataoffset __end-2 ; 2 for _asizds limit
  305.     sti            ; turn interrupts back on
  306.     jnc    SPok
  307.  
  308.     push    ss        ; establish DS=DGROUP for
  309.     pop    ds        ; _FF_MSGBANNER -> _NMSG_WRITE -> _NMSG_TEXT
  310. endif ;FARSTACK
  311.  
  312. endif  ;_COM_
  313.  
  314. ;
  315. ; Error - Not enough stack space
  316. ;
  317.  
  318.     callcrt _FF_MSGBANNER    ; for "\r\nrun-time error " banner
  319.     xor    ax,ax        ; stack overflow error message (_RT_STACK=0)
  320.     push    ax
  321.     callcrt _NMSG_WRITE
  322.     mov    ax,DOS_terminate shl 8 + 255
  323.     callos            ; terminate process with 255
  324.     ;*** NEVER RETURNS ***
  325.  
  326. ;
  327. ; ax = os version
  328. ; es = psp
  329. ;
  330.  
  331. SPok:
  332.  
  333. ifdef _COM_
  334.     ; bx = new sp value
  335.     mov    sp,bx        ; set new sp value
  336. endif
  337.  
  338. ifdef FARSTACK
  339.     mov    ds, di        ; reload dgroup
  340.     assumes ds, data
  341. else
  342.     assumes ss,data
  343. endif
  344.  
  345.  
  346.     mov    [_osversion],ax ;* save byte-swapped OS version number
  347.     xchg    ah,al
  348.     mov    [_osver],ax    ;* save OS version number (usable byte order)
  349.  
  350.  
  351. ; at this point:
  352. ;    COM files:  DS = DI = ES = SS = DGROUP
  353. ;    EXE files:  DI = SS = DGROUP, DS = ES = PSP
  354. ;    FARSTACK:     DI = DS = DGROUP, ES = PSP, SS = STACK
  355.  
  356. ;
  357. ; Save size of dgroup
  358. ;
  359.  
  360. stup10:
  361.     mov    ax,si        ; si = # paragraphs in dgroup
  362.     mov    cl,4
  363.     shl    ax,cl        ; ax = size of dgroup (bytes)
  364.     dec    ax        ; ax = size DGROUP - 1
  365.     mov    [_asizds],ax    ; Size of Global Data Segment
  366.  
  367. ;
  368. ; Carve an initial near heap out of the bottom of the stack
  369. ;
  370.  
  371. ifdef FARSTACK
  372.     ; for far stacks, we use the dummy subheap segment instead
  373.     mov    bx,dataoffset _nheap_desc ; ds:bx = near heap descriptor
  374.     mov    [bx].checksum,ds      ; save dgroup in near heap desc
  375.     mov    [bx].segsize, dataOFFSET(stubheap_next) + 2
  376.     mov    [bx].last, dataOFFSET(stubheap_next)
  377.     mov    [bx].start, dataOFFSET(stubheap_size)
  378.     mov    [bx].rover, dataOFFSET(stubheap_size)
  379.  
  380. else
  381.     mov    bx,dataoffset _nheap_desc ; ss:bx = near heap descriptor
  382.     mov    ss:[bx].checksum,ss ; save dgroup in near heap desc
  383.  
  384.     and    sp,not 1        ; make even (if not)
  385.     mov    ss:[bx].segsize,sp  ; save as segment size
  386.  
  387.     .ERRE    _HEAP_END -2    ; make sure they're equal
  388.     mov    ax,_HEAP_END    ; get end-of-heap flag
  389.     push    ax        ; into place
  390.     mov    ss:[bx].last,sp ; pointer to end-of-heap
  391.     not    ax        ; ax = 1 (0-length free entry)
  392.     push    ax        ; first heap entry
  393.     mov    ss:[bx].start,sp; init start/rover
  394.     mov    ss:[bx].rover,sp
  395. endif
  396.  
  397. ;
  398. ; Now initialize the top of stack location
  399. ;
  400.  
  401.     mov    [_atopsp],sp    ; Top of Stack Region
  402.  
  403. ;    release extra space to DOS
  404.  
  405.  
  406.  
  407.     add    si,di        ; si = DGROUP + # para in DGROUP
  408. ifdef FARSTACK
  409.     ; at this point es still has the psp address
  410.     mov    es:[DOS_MAXPARA],si ; fix psp:2
  411. else
  412.     mov    ds:[DOS_MAXPARA],si ; fix psp:2
  413. endif
  414.  
  415.     mov    bx,es        ; bx = PSP base
  416.     sub    bx,si        ; bx = - # para used
  417.     neg    bx
  418.     callos    setmem        ; set memory block size
  419. ifdef FARSTACK
  420.     ; for FARSTACK, es has the psp address, ds = DGROUP
  421. stup20:
  422.     mov    [_psp],es
  423. else
  424.     ; no FARSTACK, ds = psp, ss = DGROUP
  425. stup20:
  426.     mov    [_psp],ds    ; save psp:0
  427. endif
  428.  
  429. ;    zero data areas (_BSS and c_common)
  430.  
  431. ifdef FARSTACK
  432.     push    ds
  433.     pop    es        ; ES = DGROUP
  434.     assumes es, data
  435. else
  436.  
  437. ifndef _COM_
  438.     push    ss
  439.     pop    es        ; ES = DGROUP
  440. endif    ;_COM_
  441.     assumes es,data
  442.  
  443. endif ;FARSTACK
  444.  
  445. ; at this point:
  446. ;    COM files:  DS = ES = SS = DGROUP
  447. ;    EXE files:  SS = ES = DGROUP, DS = PSP
  448. ;    FARSTACK:     DS = ES = DGROUP, SS = STACK
  449.  
  450.     cld            ; set direction flag (up)
  451.     mov    di,dataOFFSET __edata ; beginning of bss area
  452.     mov    cx,dataOFFSET __end ; end of bss area
  453.     sub    cx,di
  454.     xor    ax,ax
  455.     rep    stosb        ; zero bss
  456.  
  457.  
  458. ;    C segmentation conventions set up here    (DS=SS and CLD)
  459.  
  460. ifndef _COM_
  461. ifndef FARSTACK
  462.     push    ss        ; set up initial DS=ES=SS, CLD
  463.     pop    ds
  464. endif    ;FARSTACK
  465. endif    ;_COM_
  466.     assumes ds,data
  467.  
  468. ; OK, we now have DS = ES = DGROUP for all models, and SS = DGROUP
  469. ; except for the far stack model.
  470.  
  471. ;    Must run this initializer prior to any far heap allocations being
  472. ;    done.  This means that we have hack-ed this in here.  There should
  473. ;    be a better solution for C7
  474.  
  475.     mov    cx,__qczrinit        ;* Get initializer addr
  476.     jcxz    @F            ;* Is it zero?
  477.     call    cx            ;* No -- call indirect through
  478. @@:
  479.  
  480. ;    process command line and environment
  481.  
  482.     call    _setenvp    ; crack environment
  483.     call    _setargv    ; crack command line
  484.  
  485. ;
  486. ; Zero bp for debugging backtrace support (i.e., mark top-of-stack).
  487. ;
  488.  
  489.     xor    bp,bp        ; mark top stack frame for SYMDEB
  490.  
  491. ;    do necessary initialization
  492.  
  493.     call    _cinit        ; shared by DOS and Windows
  494.  
  495. ifndef    _COM_
  496. ifdef FARSTACK
  497.     mov    ax, DGROUP
  498.     mov    ds, ax        ; ds = DGROUP
  499. else
  500.     push    ss
  501.     pop    ds        ; ds = DGROUP
  502. endif ;FARSTACK
  503. endif ;_COM_
  504.     assumes ds,data
  505.  
  506. ;    call main and exit
  507.  
  508. if    sizeD
  509.     push    word ptr [_environ+2] ; the environment is not always in DS
  510. endif
  511.     push    word ptr [_environ]
  512.  
  513. if    sizeD
  514.     push    word ptr [__argv+2] ; the arguments are not always in DS
  515. endif
  516.     push    word ptr [__argv]
  517.  
  518.     push    [__argc]    ; argument count
  519.  
  520.     call    main        ; main ( argc , argv , envp )
  521.  
  522. ; use whatever is in ax after returning here from the main program
  523.  
  524.     push    ax
  525.     callcrt exit        ; exit (AX)
  526.                 ;   _exit will call terminators
  527.  
  528. ifdef _DEBUGSCREEN
  529. ___aDBretaddr:            ; label to appropriate "RET"
  530.     ret            ; Default dbdata address
  531. endif    ; _DEBUGSCREEN
  532.  
  533.  
  534. page
  535. ;***
  536. ;_amsg_exit, _cintDIV - Fast exit fatal errors
  537. ;
  538. ;Purpose:
  539. ;    Exit the program with error code of 255 and appropriate error
  540. ;    message.  cintDIV is used for integer divide by zero, amsg_exit
  541. ;    is for other run time errors.
  542. ;
  543. ifdef _FATALHOOK
  544. ;    Weak extern call through _fatalexit was added so programs
  545. ;    may be notified of imminent termination (e.g., PWB).
  546. endif
  547. ;
  548. ;Entry:
  549. ;    AX    = error message number (amsg_exit only).
  550. ;
  551. ;Exit:
  552. ;    calls exit() [cintDIV] or indirect through _aexit_rtn [amg_exit].
  553. ;
  554. ;Uses:
  555. ;
  556. ;Exceptions:
  557. ;
  558. ;*******************************************************************************
  559.  
  560. labelNP <PUBLIC,_cintDIV>
  561.  
  562.     assumes ds,nothing
  563.  
  564.     mov    ax,cs:[_dataseg]
  565.     mov    ds, ax        ; ds = DGROUP
  566.     assumes ds, data
  567.  
  568.     mov    ax,_RT_INTDIV    ; Integer divide by zero interrupt
  569.     mov    [_aexit_rtn],codeoffset _exit ; call high-level exit()
  570.                 ; to cause file buffer flushing
  571.  
  572. labelNP <PUBLIC,_amsg_exit>
  573.  
  574.     assumes ds,nothing
  575.  
  576.     push    ax        ; message number for _NMSG_WRITE
  577.                 ; save around call to __fatalexit
  578. ifdef _FATALHOOK
  579.     ; weak extern call to fatal exit hook
  580.     ; ax = error code
  581.     mov    bx,cs:[_dataseg]
  582.     mov    ds, bx        ; ds = DGROUP
  583.     assumes ds, data
  584.     call    __fatalexit
  585. endif
  586.                 ; error code already on stack
  587.     callcrt _FF_MSGBANNER    ; run-time error message banner
  588.     callcrt _NMSG_WRITE    ; write error message to stdout
  589.  
  590. ifdef _DEBUGSCREEN
  591.     cmp    __aDBswpflg,__aDBdoswp    ; Aware debugger as parent?
  592.     jne    @F            ; No -- skip
  593.     pop    ax
  594.     push    ax
  595.     call    __aDBrterr        ; Yes -- report a runtime error
  596. @@:
  597. endif    ; _DEBUGSCREEN
  598.  
  599.     assumes ds,data
  600.  
  601.     mov    ax,255
  602.     push    ax
  603. if    sizeC
  604.     push    cs                ; _exit is compiled far
  605.                         ;    but called near
  606. endif
  607.     call    word ptr [_aexit_rtn] ; _exit(255) ordinarily
  608.                 ; (or exit(255) for div by 0)
  609.                 ; NEAR routine pointer
  610.  
  611. ; Location that holds DGROUP segment (necessary for .COM file support)
  612.  
  613. ifdef  _COM_
  614. globalW _dataseg,0        ; will hold DGROUP
  615.  
  616. else    ;not _COM_
  617. globalW _dataseg,DGROUP
  618.  
  619. endif    ;not _COM_
  620.  
  621. sEnd
  622.     end    _astart     ; start address
  623.