home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 25 / nopv25.iso / 040A / CCDL151L.ZIP / MSDOS / 386 / C0DOS.ASM < prev    next >
Encoding:
Assembly Source File  |  1997-06-14  |  16.9 KB  |  781 lines

  1. ;
  2. ; startup code for the CC386 system.  This code provides the standard
  3. ; startup routines used by the CC386 compiler.  They are prefaced by
  4. ; init code to initialize TRAN's PMODE.
  5. ;
  6. ; This program is designed for use with TASM; in particular it uses
  7. ; the TLINK convention that if two segments are defined for the same
  8. ; class in the first .obj loaded the first is put at the BEGINNING of
  9. ; of the linked segment and the second is placed at the END.  I don't
  10. ; have any idea if MASM or the microsoft linker will deal with this
  11. ; in a way that will allow the code to work.
  12. ;
  13. ; This program:
  14. ;    1) Allocates memory
  15. ;    2) allocates and initializes descriptors
  16. ;    3) copies the C program into the allocated memory
  17. ;    4) runs the C program
  18. ;    5) cleans up
  19. ;    6) exits
  20. ;
  21. ; Copyright (c) 1997 LADsoft
  22. ;
  23. ; David Lindauer, gclind01@starbase.spd.louisville.edu
  24. ;
  25. .386p
  26. locals
  27.  
  28. STACKLEN        = 40h                   ; size of stack in paragraphs
  29. PROGRAM_STACK    = 20*1024        ; stack size of the prog
  30. SELSTOALLOC     = 4
  31. MAXMEM        = 32
  32. GDTENTRY    macro base,limit,type
  33.     dw    limit AND 0ffffh
  34.     dw    base AND 0ffffh
  35.     db    (base SHR 16) AND 0ffh
  36.     dw    type OR ((limit SHR 8) AND 0f00h)
  37.     db    base SHR 24
  38. ENDM
  39.  
  40. STUB_TEXT       segment para public use16 'TRAN'
  41.         extrn spawnblock:word
  42. STUB_TEXT       ends
  43. PMODE_TEXT      segment para public use16 'TRAN'
  44. PMODE_TEXT      ends
  45. EXE_STACK       segment para stack use16 'STACK'
  46. EXE_STACK       ends
  47. _TEXT        segment para public use32 'CODE'
  48.     extrn    __argv_arr:DWORD,__argc:DWORD,__env_arr:DWORD,__cmdline:DWORD
  49.     extrn    _main:PROC, llsignal:proc, llsigdown:proc
  50.     extrn llfpini:proc, llfpdown:proc
  51. _TEXT        ends
  52. cstartup        SEGMENT DWORD PUBLIC USE32 'INITDATA'
  53. InitStart       label dword
  54.                 ENDS
  55. _STARTUPEND_       SEGMENT DWORD PUBLIC USE32 'INITDATA'
  56. InitEnd         label dword
  57.                 ENDS
  58. crundown        SEGMENT DWORD PUBLIC USE32 'EXITDATA'
  59. ExitStart       label dword
  60.                 ENDS
  61. _RUNDOWNEND_       SEGMENT DWORD PUBLIC USE32 'EXITDATA'
  62. ExitEnd         label dword
  63.                 ENDS
  64. _CPP_           SEGMENT DWORD PUBLIC USE32 'CPPDATA'
  65. CppStart        label dword
  66.         dd    cpproutine
  67.                 ENDS
  68. _CPPEND_        SEGMENT DWORD PUBLIC USE32 'CPPDATA'
  69. CppEnd          label dword
  70.         ENDS
  71. _DATA       SEGMENT DWORD PUBLIC USE32 'DATA'
  72.                 ENDS
  73. _BSS            SEGMENT PARA PUBLIC USE32 'BSS'
  74. BssStart    label dword
  75.                 ENDS
  76. _BSSEND            SEGMENT PARA PUBLIC USE32 'BSS'
  77. BssEnd        label dword
  78.                 ENDS
  79.  
  80. DGROUP group _TEXT, cstartup,_STARTUPEND_,crundown,_RUNDOWNEND_,_CPP_,_CPPEND_,_DATA,_BSS,_BSSEND
  81.  
  82. extrn   _pm_info:far, _pm_init:far, _pm_rmstacks:BYTE, _pm_pmstacks:BYTE
  83. extrn    _pm_pagetables:byte, _pm_mode: byte
  84.     public  __rexit, __transferx, __stacktop
  85.     public  __pspseg, __linear, __pmodew,__rmseg
  86.  
  87. STUB_TEXT           segment
  88. assume  cs:STUB_TEXT, ds:STUB_TEXT
  89. org     0
  90. ;═════════════════════════════════════════════════════════════════════════════
  91. ;
  92. ; Header for external debuggers... must be FIRST THING after EXE header
  93. ;
  94. ifndef DEBUG
  95.         dd    'XDBG'            ; signature
  96.         dd    'i386'
  97.         dw    1            ; some Version info
  98.         dw    DGROUP            ; to locate entry + globals
  99.         dd    offset DGROUP:BssEnd    ; to determine memory size
  100.         dd    PROGRAM_STACK        ; yet to add this...
  101.         dd    offset DGROUP:start32    ; true entry point
  102.         dd    offset DGROUP:_main    ; where to set a breakpoint
  103.         dd    offset DGROUP:__pmodew    ; to fake this
  104. endif
  105. ;
  106. ; local vars
  107. ;
  108. banner        db    'Stub-386, Copyright (c) 1997, LADsoft',10,13
  109.         db    'DPMI subsystem Copyright (c) 1994, TRAN (Thomas Pytel)',10,13,'$'
  110. errmsgtbl       dw      errmsg0,errmsg1,errmsg2,errmsg3
  111.                 dw      errmsg4,errmsg5,errmsg6,errmsg7
  112.  
  113. errmsg0         db      'Not enough low memory!',13,10,36
  114. errmsg1         db      '80386 or better not detected!',13,10,36
  115. errmsg2         db      'System already in protected mode and no VCPI or DPMI found!',13,10,36
  116. errmsg3         db      'DPMI host is not 32bit!',13,10,36
  117. errmsg4         db      'Could not enable A20 gate!',13,10,36
  118. errmsg5         db      'Could not enter DPMI 32bit protected mode!',13,10,36
  119. errmsg6         db      'Could not allocate needed DPMI selectors!',13,10,36
  120. errmsg7        db    'MS-DOS 2.0 required for this program',10,13,'$'
  121.  
  122. nomemerr    db    'Not enough extended memory',10,13,36
  123. initerr        db    'Unexpected error while initializing dpmi',10,13,36
  124.  
  125.  
  126. regstruc_edi    label   dword
  127. regstruc_di     dw      ?,?
  128. regstruc_esi    label   dword
  129. regstruc_si     dw      ?,?
  130. regstruc_ebp    label   dword
  131. regstruc_bp     dw      ?,?
  132.                 dd      ?
  133. regstruc_ebx    label   dword
  134. regstruc_bx     label   word
  135. regstruc_bl     db      ?
  136. regstruc_bh     db      ?,?,?
  137. regstruc_edx    label   dword
  138. regstruc_dx     label   word
  139. regstruc_dl     db      ?
  140. regstruc_dh     db      ?,?,?
  141. regstruc_ecx    label   dword
  142. regstruc_cx     label   word
  143. regstruc_cl     db      ?
  144. regstruc_ch     db      ?,?,?
  145. regstruc_eax    label   dword     
  146. regstruc_ax     label   word
  147. regstruc_al     db      ?
  148. regstruc_ah     db      ?,?,?
  149. regstruc_flags  dw      ?
  150. regstruc_es     dw      ?
  151. regstruc_ds     dw      ?
  152. regstruc_fs     dw      ?
  153. regstruc_gs     dw      ?
  154. regstruc_ip     dw      ?
  155. regstruc_cs     dw      ?
  156. regstruc_sp     dw      ?
  157. regstruc_ss     dw      ?
  158.  
  159. sel32        dw    ?
  160. selx        dw    ?
  161. psp        dw    ?
  162. modeval        db    ?
  163. newcodebase    dw    ?
  164. transfersel    dw    ?
  165.     align 4
  166. linearbase    dd    ?
  167. blockhandle    dd    ?
  168. blocksize    dd    ?
  169.  
  170. cdesc    label dword
  171.     GDTENTRY    0,0fffffh,0c09Ah    ; 386 code
  172. ddesc    label dword
  173.     GDTENTRY    0,0fffffh,0c092H    ; 386 data
  174. ;═════════════════════════════════════════════════════════════════════════════
  175. ;
  176. ; program start
  177. ;
  178. start:                                  ; execution starts here
  179.  
  180.         push cs                         ; DS = CS
  181.         pop ds
  182.     mov [psp],es
  183.     mov ax,es:[2ch]
  184.     mov [spawnblock],ax
  185. ifdef    COPYRIGHT            ; Joss
  186.     mov dx,offset banner        ; do the banner
  187.     mov ah,9
  188.     int 21h
  189. endif
  190.  
  191.     mov ah,30h               ; Check for dos 2.0
  192.     int 21h
  193.     cmp al,2
  194.     jnc @@dosok
  195.     mov ax,7            ; err if not
  196.     jmp @@startf1
  197.  
  198. @@dosok:
  199. ;
  200. ; Init to try for VCPI
  201. ;
  202.     mov    [_pm_pagetables],MAXMEM/4    ; Max out at 32 MB
  203.     mov    [_pm_mode],1        ; select VCPI if it exists
  204.     mov    [_pm_rmstacks],6
  205.     mov    [_pm_pmstacks],6
  206.  
  207.         call _pm_info                   ; get information
  208.         jnc short @@startf0             ; if no error, go on
  209.  
  210. @@startf1:
  211.     mov si,ax            ; print error message for code AX
  212.         add si,ax
  213.         mov dx,errmsgtbl[si]
  214.         mov ah,9
  215.         int 21h
  216.         mov ax,4cffh
  217.         int 21h
  218.  
  219. @@startf0:
  220.     call optimize_realmem        ; optimize mem for spawns
  221.     jc nomem
  222.     mov [newcodebase],ax
  223.     mov es,bx
  224.     call _pm_init            ; enter protected mode
  225.     jc @@startf1            ; if error, go to error message
  226.  
  227. ;
  228. ; At this point we are in pmode
  229. ;
  230.     mov [modeval],ch        ; VCPI/DPMI/RAW/XMS flag
  231.                     ; = 3 for DPMI, 2 for VCPI
  232.  
  233.     mov [psp],es            ; save our PSP for later
  234.  
  235.     push ds
  236.     pop es
  237.  
  238.     mov ax,cs               ; fix the priv levels of our descriptors
  239.     and al,3    
  240.     shl al,5
  241.     or  byte ptr [cdesc+5],al
  242.     or  byte ptr [ddesc+5],al
  243. ;
  244. ; Get program size
  245. ;
  246.                      
  247.     mov ecx,offset DGROUP:BssEnd    ; min mem program needs
  248.     add ecx,PROGRAM_STACK        ; later we will make this a link-time
  249.                     ; parameter
  250.     mov [blocksize],ecx
  251.     mov ebx,ecx
  252.     shr ebx,16
  253.     
  254. ;
  255. ; Allocate memory for the program
  256. ;
  257. ; the program WILL run in extended memory
  258. ;
  259.     mov ax,501h            ; allocate memory and save the
  260.     int 31h                ; base address of it
  261.     jc nomem            ; Should not get an error from this
  262.                     ; but get out if we do
  263.     mov ax,bx
  264.     shl eax,16
  265.     mov ax,cx
  266.     mov [linearbase],eax
  267.     mov ax,si
  268.     shl eax,16
  269.     mov ax,di
  270.     mov [blockhandle],eax
  271.  
  272.     mov ax,3            ; Now get the selector increase value
  273.     int 31h
  274.     mov [selx],ax
  275. ;
  276. ; Allocate selectors and initialize the descriptors for
  277. ; 32-bit segments
  278. ;
  279.     mov ax,0            ; Allocate the 32-bit selectors
  280.     mov cx,SELSTOALLOC        ; CODE, DATA/stack, 
  281.     int 31h
  282.     jc initbad
  283.     mov [sel32],ax
  284.  
  285.     mov bx,[sel32]            ; set CS descriptr
  286.     mov edi,offset cdesc        ; 
  287.     mov ax,000ch            ;
  288.     int 31h
  289.     jc initbad            ; Should not get an error from this
  290.  
  291.     mov bx,[sel32]            ; set DS descriptor
  292.     mov edi,offset ddesc        ; 
  293.     add bx,[selx]
  294.     mov ax,000ch
  295.     int 31h
  296.     jc initbad            ; Should not get an error from this
  297.     
  298.     mov bx,[sel32]            ; set ABSOLUTE descriptor
  299.     mov edi,offset ddesc        ; 
  300.     add bx,[selx]
  301.     add bx,[selx]
  302.     mov ax,000ch
  303.     int 31h
  304.     jc initbad            ; Should not get an error from this
  305.  
  306.     mov bx,[sel32]            ; set transfer descriptor
  307.     mov edi,offset ddesc        ; 
  308.     add bx,[selx]
  309.     add bx,[selx]
  310.     add bx,[selx]
  311.     mov [transfersel],bx
  312.     mov ax,000ch
  313.     int 31h
  314.     jc initbad            ; Should not get an error from this
  315. ;
  316. ; Set the base of the code and data segments to the linear address
  317. ; of the memory block
  318. ;
  319.     mov eax,[linearbase]        ; code segment
  320.     mov dx,ax
  321.     shr eax,16
  322.     mov cx,ax
  323.     mov bx,[sel32]
  324.     mov ax,7
  325.     int 31h
  326.     jc initbad
  327.     
  328.     mov eax,[linearbase]        ; data segment
  329.     mov dx,ax
  330.     shr eax,16
  331.     mov cx,ax
  332.     mov bx,[sel32]
  333.     add bx,[selx]
  334.     mov ax,7
  335.     int 31h
  336.     jc initbad
  337.                     ; absolute segment already initted
  338.     sub eax,eax                ; transfer segment
  339.     mov ax,_TEXT
  340.     shl eax,4
  341.     mov dx,ax
  342.     shr eax,16
  343.     mov cx,ax
  344.     mov bx,[transfersel]
  345.     mov ax,7
  346.     int 31h
  347.     jc initbad
  348. ;
  349. ; Set the limit of the code and data segments to the block size
  350. ;
  351.     mov eax,[blocksize]        ; code segment
  352.     dec eax
  353.     mov dx,ax
  354.     shr eax,16
  355.     mov cx,ax
  356.     mov bx,[sel32]
  357.     mov ax,8
  358.     int 31h
  359.     jc initbad
  360.     
  361.     mov eax,[blocksize]        ; data segment
  362.     dec eax
  363.     mov dx,ax
  364.     shr eax,16
  365.     mov cx,ax
  366.     mov bx,[sel32]
  367.     add bx,[selx]
  368.     mov ax,8
  369.     int 31h
  370.     jc initbad
  371.                     ; absolute segment already initted
  372.     mov eax,1023                ; transfer segment
  373.     mov dx,ax
  374.     shr eax,16
  375.     mov cx,ax
  376.     mov bx,[transfersel]
  377.     mov ax,8
  378.     int 31h
  379.     jc initbad
  380. ;
  381. ; blit the program to our memory block
  382. ;
  383.     sub eax,eax            ; calculate source
  384.     mov ax,[newcodebase]
  385.     shl eax,4
  386.     mov esi,eax
  387.  
  388.     mov edi,[linearbase]        ; calculate dest
  389.     mov es,[psp]            ; calculate len
  390.     sub ecx,ecx
  391.     mov cx,es:[2]
  392.     shl ecx,4
  393.     sub ecx,esi
  394.     cmp ecx,[blocksize]
  395.     jc  takeprog
  396.     mov ecx,[blocksize]
  397. takeprog:
  398.     shr ecx,2            ; guranteed to be paragraph multiple
  399.     
  400.     push ds                ; switch to abs seg and do blit
  401.     mov ax,[sel32]
  402.     add ax,[selx]
  403.     add ax,[selx]
  404.     mov ds,ax
  405.     mov es,ax
  406.     db  67h                ; shift us to 32 bits...
  407.     rep movsd            ; do the blit
  408.     pop ds
  409.     
  410. ;
  411. ; now call the 32-bit C0 routine
  412. ;
  413. ; must return with a RETF
  414. ;
  415.     push ds
  416.  
  417.     push 0              ; return address... returning from
  418.     push cs                ; a 32 bit segment so two dwords
  419.     sub eax,eax
  420.     mov ax,offset retpos
  421.     push eax
  422.  
  423.     push [sel32]            ; address of 32-bit code
  424.                     ; returning from this seg to 
  425.     mov eax,offset DGROUP:start32         ; a 32-bit seg, two words
  426.     push ax
  427.  
  428.     mov ax,[sel32]            ; set up selectors
  429.     add ax,[selx]
  430.     mov es,[psp]                ; ES: PSP
  431.     mov ebx,[blocksize]        ; EBX
  432.     mov ecx,[linearbase]        ; ECX
  433.     mov dx,[transfersel]
  434.     mov ds,ax
  435.     mov ax,_TEXT
  436.     
  437.     retf
  438.  
  439. retpos:                    ; when 32-bit code exits with a retf
  440.     pop ds                ; we come here
  441.     
  442.         
  443. getout:
  444.     push ax                ; save return code
  445.     mov bx,[sel32]
  446.     or bx,bx
  447.     mov cx,SELSTOALLOC
  448.     mov ax,1
  449. selfrlp:
  450.     pusha
  451.     int 31h
  452.     popa
  453.     add bx,[selx]
  454.     loop selfrlp
  455.  
  456. releasemem:
  457.     mov eax,[blockhandle]        ; Free the program block
  458.     or eax,eax
  459.     jz endprog
  460.     mov di,ax
  461.     shr eax,16
  462.     mov si,ax
  463.     mov ax,502h
  464.     int 31h
  465.  
  466. endprog:
  467.     pop ax
  468.         mov ah,4ch                      ; exit to DOS
  469.         int 21h
  470. nomem:
  471.         mov regstruc_dx,offset nomemerr
  472.     jmp puterr
  473. initbad:
  474.         mov regstruc_dx,offset initerr
  475. puterr:
  476.     call message
  477.     mov al,0ffh            ; error 255
  478.     jmp getout
  479.  
  480. message:
  481.         mov edi,offset regstruc_edi     ; offset of register structure
  482.         xor cx,cx                       ; no parameters on stack
  483.         mov bx,21h                      ; call interrupt 21h
  484.         mov ax,300h                     ; INT 31h function 0300h
  485.  
  486.         mov regstruc_ah,9               ; function code 9, put string
  487.         mov regstruc_ds,STUB_TEXT           ; set DS:DX for DOS string put
  488.         mov regstruc_ss,0               ; SS:SP = 0, PMODE will provide stack
  489.         mov regstruc_sp,0
  490.  
  491.     push ds
  492.     pop es
  493.         int 31h                         ; do the call to real mode
  494.     ret
  495.  
  496. ;─────────────────────────────────────────────────────────────────────────────
  497. ;
  498. ; real mode subroutines
  499. ;
  500. optimize_realmem proc
  501. ;
  502. ; check if we have space for the pmode data seg
  503. ;
  504.     mov ax,es:[2]
  505.     mov ecx,offset DGROUP:BssStart
  506.     shr ecx,4
  507.     sub ax,cx
  508.     push ax
  509.     jc or_err
  510.     sub ax,bx
  511.     jc or_err
  512.     sub ax,STACKLEN + 1024/16
  513.     jc or_err
  514.     sub ax,_TEXT
  515.     jc or_err
  516. ;
  517. ; now relocate the pmode program to end of real memory
  518. ;
  519.     std
  520.     push ds
  521.     push es
  522.     mov ax,es:[2]
  523.     sub ax,1000h
  524.     mov es,ax
  525.     mov di,0fffeh
  526.     mov si,di
  527.     mov eax,offset DGROUP:BssStart
  528.     shr eax,4
  529.     add ax,_TEXT
  530.     sub ax,1000h
  531.     mov ds,ax
  532.     shl ecx,3
  533. or_lp:
  534.     cmp ecx,8000h
  535.     jbe lastmv
  536.     push ecx
  537.     mov cx,8000h
  538.     rep movsw
  539.     pop ecx
  540.     sub ecx,8000h
  541.     mov ax,ds
  542.     sub ax,1000h
  543.     mov ds,ax
  544.     mov ax,es
  545.     sub ax,1000h
  546.     mov es,ax
  547.     jmp or_lp
  548. lastmv:
  549.     rep movsw
  550.     cld
  551.     pop es
  552.     pop ds
  553. ;
  554. ; calculate address of pmode data struct
  555. ;
  556.     mov ax,_TEXT
  557.     add ax,1024/16+STACKLEN
  558.     push ax
  559. ;
  560. ; resize memory
  561. ;
  562.     add bx,ax
  563.     sub bx,[psp]
  564.     mov es,[psp]
  565.     mov ah,4ah
  566.     int 21h
  567.     pop bx
  568.     jc or_err
  569.     clc
  570. or_err:
  571.     pop ax
  572.     ret
  573. optimize_realmem endp
  574.  
  575. STUB_TEXT           ends
  576.  
  577. ;─────────────────────────────────────────────────────────────────────────────
  578. EXE_STACK       segment para stack use16 'STACK'
  579.                 db      STACKLEN*10h dup(?)
  580. EXE_STACK       ends
  581.  
  582.  
  583.  
  584. _DATA       SEGMENT DWORD PUBLIC USE32 'DATA'
  585.         db    "Copyright (c) 1997 LADsoft C runtime library"
  586.         db    " (i386/DOS)"
  587.     align 4
  588. __linear    dd    0
  589. __stacktop    dd    0
  590. stackpos    df    0
  591. __transferx    dw    0
  592. __pspseg    dw    0
  593. __pmodew    dw    0
  594. __rmseg        dw    0
  595. filename    db    128 dup (0)
  596. dcml        db    128 dup (0)
  597.                 ENDS
  598. _TEXT        SEGMENT
  599.         assume cs:DGROUP,ds:DGROUP
  600. ;
  601. ; C startup procedures
  602. ;
  603. start32:
  604. ;
  605. ; save DTA and PSP
  606. ;
  607.         push ebx        ; save TOM for stack init
  608.         mov [__transferx],dx    ; disk transfer address
  609.         mov [__pspseg],es        ; program psp segment
  610.         mov [__linear],ecx
  611.                mov [__rmseg],ax
  612. ;
  613. ; Init fs and gs in case someone needs them
  614. ;
  615.         mov     eax,ds
  616.         mov     fs,eax
  617.         mov    gs,eax
  618. ;
  619. ; Clear BSS
  620. ;
  621.         push    ds
  622.         pop     es
  623.         mov    edi,offset DGROUP:BssStart
  624.         mov    ecx,offset DGROUP:BssEnd
  625.         sub    ecx,edi
  626.         sub    eax,eax
  627.         cld
  628.         rep    stosb
  629. ;
  630. ; Initialize the signal system
  631. ;
  632.         call llfpini
  633.         call llsignal
  634. ;
  635. ; Set up command line for RTL
  636. ;
  637.         mov    es,[__pspseg]
  638.         mov edi,offset DGROUP:dcml
  639.         mov [__cmdline],edi
  640.         inc [__cmdline]
  641.         push ds
  642.         push ds
  643.         push es
  644.         pop ds            ; blit the command line into our mem
  645.         pop es
  646.         mov esi,80h
  647.         mov ecx,128
  648.         rep movsb
  649.         pop ds
  650.                     ; turn into C string form
  651.         sub ebx,ebx
  652.         mov bl,[dcml]
  653.         mov byte ptr [dcml + ebx + 1],0
  654. ;
  655. ; initialize stack
  656. ;
  657.         pop    ebx            ; get TOM back
  658.         mov dword ptr [stackpos],esp    ; save old stack for later
  659.         mov word ptr [stackpos+4],ss
  660.         cli
  661.         push ds                ; set up stack
  662.         pop ss                ;
  663.         and ebx,0fffffffch        ;
  664.         sub ebx,4
  665.         mov esp,ebx            ;
  666.         mov    [__stacktop],ebx
  667.         sti
  668. ;
  669. ; Execute startup routines
  670. ;
  671.         push     ds            ; reset es to ds
  672.         pop     es
  673.         mov    ecx,offset DGROUP:InitStart
  674.         mov    edx,offset DGROUP:InitEnd
  675.         call    sexproc
  676.  
  677. ;
  678. ; Now we are going to patch the name of the file into argv[0]
  679. ;
  680.         mov     es,[__pspseg]        ; get environment        
  681.         mov    es,es:[2ch]
  682.         sub    eax,eax            ; set up for scan
  683.         mov     edi,eax
  684.         mov     ecx,-1
  685.         mov    esi,offset DGROUP:filename
  686. lp:
  687.         repnz    scasb            ; scan for end of environment
  688.         test    byte ptr es:[edi],0ffh
  689.         jnz     lp
  690.         add    edi,3            ; got it, index to command line
  691. lp1:        
  692.         mov    al,es:[edi]        ; now transfer the file name
  693.         mov    [esi],al        ; to a local buffer
  694.         inc    esi
  695.         inc    edi
  696.         or    al,al
  697.         jnz    lp1
  698.         
  699.         mov    eax,[__argv_arr]
  700.         mov    dword ptr [eax],offset DGROUP:filename
  701.  
  702.         push ds
  703.         pop es
  704. ;
  705. ;
  706. ; Call main
  707. ;
  708.         push    __env_arr
  709.         push    __argv_arr
  710.         push    __argc
  711. ifdef DEBUG
  712.         extrn monitor_init:proc
  713.         call monitor_init
  714. endif
  715.         call    _main
  716.         add    esp,12
  717.  
  718. ; exit/abort comes here
  719. ;
  720. __rexit:
  721. ;
  722. ; Execute rundown routines
  723. ;
  724.         push    eax        ; saving C return code
  725.         mov    ecx,offset DGROUP:ExitStart
  726.         mov    edx,offset DGROUP:ExitEnd
  727.         call    sexproc
  728. ;
  729. ; rundown signal handler
  730. ;
  731.         call    llsigdown
  732.         call    llfpdown
  733. ;
  734. ; get original stack
  735. ;
  736. exitpos:
  737.         pop    eax        ; return code in EAX
  738.         lss    esp,stackpos
  739.         retf            ; exit back to the 16-bit seg
  740. ;
  741. ; Handle startup/rundown routines
  742. ;
  743. sexproc:
  744.         cmp    ecx,edx        
  745.         jz    short sexpdone    
  746.         mov    edi,ecx
  747.         sub    ebx,ebx
  748.         sub    eax,eax
  749. spl2:
  750.         cmp    edi,edx
  751.         jz    short spo
  752.         test    dword ptr [edi+4],-1
  753.         jz    short spl3
  754.         cmp    eax,[edi+4]
  755.         jnc    short spl3
  756.         mov    ebx,edi
  757.         mov    eax,[edi+4]
  758. spl3:
  759.         add    edi,8
  760.         jmp    spl2
  761. spo:
  762.         or    ebx,ebx
  763.         jz    short sexpdone
  764.         mov    dword ptr [ebx+4],0
  765.         push    edx
  766.         push    ecx
  767.         call    [ebx]
  768.         pop    ecx
  769.         pop    edx
  770.         jmp    sexproc
  771. sexpdone:
  772.         ret
  773.  
  774. ; This is called as the first thing from the C++ main routine
  775. cpproutine:
  776.         ret
  777. ;
  778. ; Put a message out on the console
  779. ;
  780. _TEXT        ends
  781. end     start