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