home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CASM.ARJ / C.ASM < prev    next >
Encoding:
Assembly Source File  |  1988-08-31  |  18.6 KB  |  812 lines

  1. ;_ c.asm   Fri Feb 12 1988   Modified by: Walter Bright */
  2. ; Copyright (C) 1985-1988 by Northwest Software
  3. ; All rights reserved.
  4. ; Written by Walter Bright
  5. ; C startup file
  6.  
  7. ;I8086T      equ    1    ;defined to create a .COM version (CT.OBJ)
  8.  
  9.     DOSSEG        ;have linker fix ordering of segments
  10.     .286C        ;disable automatic FWAIT generation
  11.  
  12. ;*********************************************
  13.  
  14. ; Determine which memory model we are assembling for. For .COM files,
  15. ; force S model.
  16.     ifdef I8086T
  17. I8086S equ    1
  18.     else
  19.     ifndef I8086S
  20.     ifndef I8086M
  21.     ifndef I8086C
  22.     ifndef I8086L        ;if none of the memory models are defined
  23. I8086S equ    1        ;default to S model
  24.     endif
  25.     endif
  26.     endif
  27.     endif
  28.     endif
  29.  
  30. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  31. ; Macros specific to each memory model in an attempt to make it easier
  32. ; to write memory model independent code.
  33. ;    P            Offset on BP to first argument on stack
  34. ;    SPTR            1 if small data model
  35. ;    LPTR            1 if large pointers (large data)
  36. ;    LCODE            1 if large code model
  37. ;    SIZEPTR            # of bytes in a pointer
  38. ;    func            Declare a function as NEAR or FAR
  39.  
  40. ;;;;;;;;;;;;;; SMALL MEMORY MODEL ;;;;;;;;;;;;;;;;;
  41.  
  42. ifdef I8086S
  43.  
  44. P    equ    4    ; Offset of start of parameters on the stack frame
  45. SPTR    equ    1
  46. LPTR    equ    0
  47. LCODE    equ    0
  48. SIZEPTR    equ    2    ; Size of a pointer
  49.  
  50. func    macro    name
  51. name    proc    near
  52.     endm
  53.  
  54. endif
  55.  
  56. ;;;;;;;;;;;;;;;;; MEDIUM MEMORY MODEL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  57.  
  58. ifdef I8086M
  59.  
  60. P    equ    6    ; Offset of start of parameters on the stack frame
  61. SPTR    equ    1
  62. LPTR    equ    0
  63. LCODE    equ    1
  64. SIZEPTR    equ    2
  65.  
  66. func    macro    name
  67. name    proc    far
  68.     endm
  69.  
  70. endif
  71.  
  72. ;;;;;;;;;;;;;;;;; COMPACT MEMORY MODEL ;;;;;;;;;;;;;;
  73.  
  74. ifdef I8086C
  75.  
  76. P    equ    4    ; Offset of start of parameters on the stack frame
  77. SPTR    equ    0
  78. LPTR    equ    1
  79. LCODE    equ    0
  80. SIZEPTR    equ    4
  81.  
  82. func    macro    name
  83. name    proc    near
  84.     endm
  85.  
  86. endif
  87.  
  88. ;;;;;;;;;;;;;;;; LARGE MEMORY MODEL ;;;;;;;;;;;;;;;;;;;
  89.  
  90. ifdef I8086L
  91.  
  92. P    equ    6    ; Offset of start of parameters on the stack frame
  93. SPTR    equ    0
  94. LPTR    equ    1
  95. LCODE    equ    1
  96. SIZEPTR    equ    4
  97.  
  98. func    macro    name
  99. name    proc    far
  100.     endm
  101.  
  102. endif
  103.  
  104. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  105. ; Other more or less useful macros
  106.  
  107. callm    macro    func
  108.     if LCODE
  109.     call    far ptr func
  110.     else
  111.     call    near ptr func
  112.     endif
  113.     endm
  114.  
  115. .if    macro    arg1,cond,arg2,lbl
  116.     cmp    arg1,arg2
  117.     j&cond    lbl
  118.     endm
  119.  
  120. bdos    macro    func
  121.     ifnb    <func>
  122.      mov    AH,func
  123.     endif
  124.     int    21h
  125.     endm
  126.  
  127. .retf    macro    val        ;force assembler to build a far return
  128.     ifnb    <val>
  129.      db    0CAh
  130.      dw    val
  131.     else
  132.      db    0CBh
  133.     endif
  134.     endm
  135.  
  136.     public    __BASE,__exit,__dos,_errno
  137.     public    __datapar,__pastdata,__progpar,__heapbottom
  138.     public    __psp,__doserrno,__oserr,__chkstack,__chkstk,__osmajor,__osminor
  139.     public    __8087
  140.     if LPTR
  141.     public    __totalpar
  142.     endif
  143.  
  144.     extrn    __stack:word        ;default stack size
  145.     extrn    __okbigbuf:word
  146.     if LCODE
  147.     extrn    _exit:far, _sbrk:far, _free:far, __main:far, __entry:far
  148.     else
  149.     extrn    _exit:near, _sbrk:near, _free:near, __main:near, __entry:near
  150.     endif
  151.  
  152.     public    __acrtused
  153. __acrtused equ    1234            ;cause linker to pull in this module
  154.  
  155. ARGMAX    =    32            ;max # of command line args
  156. CR    =    13
  157. LF    =    10
  158.  
  159. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  160. ;The code segment must be lower in memory than the data segment
  161. ;(so we can add to the top of the data segment).
  162.  
  163.     if LCODE
  164. C_TEXT    segment word public 'CODE'
  165.     assume CS:C_TEXT 
  166.     else
  167. _TEXT    segment word public 'CODE'
  168.     assume CS:_TEXT 
  169.     endif
  170.  
  171.     ifdef    I8086T
  172.     ;Note that this is not 100h! This is because the DOSSEG directive
  173.     ;causes LINK to move everything up 10h bytes! Why, I dunno.
  174.     org    0F0h
  175.  
  176. start:
  177.     jmp    begin
  178.     else
  179.     mov    DX,offset DGROUP:nullfp        ;NULL function pointer
  180.     jmp    fatmsg
  181.     endif
  182.  
  183.     if LCODE
  184. C_TEXT    ends
  185.     else
  186. _TEXT    ends
  187.     endif
  188.  
  189. ;Define a segment so we can find the end of the code
  190. C_ETEXT    segment    word public 'ENDCODE'
  191. C_ETEXT    ends
  192.  
  193.     ifdef I8086T
  194. CGROUP    group    _TEXT,C_ETEXT        ;code must all fit in 1 segment
  195.     endif
  196.  
  197. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  198. ; Set up segments for data
  199.  
  200. ;Segment so we can find the start of DGROUP
  201.  
  202. NULL    segment    para public 'BEGDATA'        ;note PARAGRAPH alignment
  203. NULL    ends
  204.  
  205. ;Regular initialized data goes in _DATA
  206.  
  207. _DATA    segment    word public 'DATA'
  208. _DATA    ends
  209.  
  210. ;Constant data, such as switch tables, go here.
  211.  
  212. CONST    segment    word public 'CONST'
  213. CONST    ends
  214.  
  215. ;Segment for uninitialized data. This is set to 0 by the startup code,
  216. ;so it does not consume room in the executable file.
  217.  
  218. _BSS    segment    word public 'BSS'
  219. _BSS    ends
  220.  
  221. ;Segment to provide an initial stack so DOS can fire up the program.
  222. ;We'll set up our own stack later. Use the space later for the
  223. ;program arguments.
  224. ;Our stack in large data models is in its own segment, not part of
  225. ;DGROUP. This is different than MSC.
  226.  
  227.     ifdef    I8086T
  228. STACK    segment    word public 'STACK'        ;no stack for .COM files
  229. bssend equ    $
  230.     else
  231. STACK    segment    para stack 'STACK'
  232.     endif
  233.  
  234. cmdline      equ    $        ;where the command line will be placed.
  235.     ifndef I8086T
  236.     org    $+128        ;a 128 byte stack is necessary to fire
  237.                 ;up .EXE programs, even if a CLI is the
  238.                 ;first instruction!
  239. dummy    equ    $
  240.     endif
  241. STACK    ends
  242.  
  243.  
  244. ;Stuff all these segments into one group so they can call be accessed by DS
  245. ; DOSSEG should do this, but who trusts it?
  246. DGROUP    group    NULL,_DATA,CONST,_BSS,STACK        ;data segment
  247.  
  248. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  249. ;Form the start of DGROUP
  250.  
  251. NULL    segment
  252.  
  253.     ;for programs that dereference NULL string pointers
  254.     db    'ERROR: NULL pointer', 0
  255.  
  256.     ;Put baggage here where it can be safely stomped by NULL pointer
  257.     ;assignments. Should do a checksum of this to detect these.
  258.     db    'Zortech C 4.00 library, Copyright (C) 1988 '
  259.     ifdef I8086S
  260.     db    'S'
  261.     endif
  262.     ifdef I8086M
  263.     db    'M'
  264.     endif
  265.     ifdef I8086C
  266.     db    'C'
  267.     endif
  268.     ifdef I8086L
  269.     db    'L'
  270.     endif
  271.     db    ', written by Walter Bright',0
  272.  
  273. NULL    ends
  274.  
  275. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  276. ; Initialized data globals
  277.  
  278. _DATA    segment
  279.  
  280.     ;These symbols are created by the linker (DOSSEG switch)
  281.     extrn    _edata:byte        ;first location in first BSS segment
  282.     ifndef I8086T
  283.     extrn    _end:byte        ;first location in first STACK segment
  284.     endif
  285.  
  286. prgnam    db    0            ;dummy program name (null string)
  287. argc    dw    ?            ;number of args
  288. argv    dw    offset DGROUP:prgnam    ;which is the program name
  289.     if LPTR
  290.     dw    seg DGROUP
  291.     endif
  292.     db    (ARGMAX+1)*SIZEPTR dup (0)    ;the rest of the arguments
  293.                     ;(this area doubles as the
  294.                     ;initial stack, so no initialized
  295.                     ;data here!)
  296.                     ;The +1 is so argv[] is always
  297.                     ;followed by a NULL.
  298. __BASE        dw    ?    ;pointer to stack overflow check word
  299.                 ;(if this word changes, we have a stack
  300.                 ;overflow)
  301. __datapar    dw    ?    ;# of paragraphs currently in data segment
  302.                 ; (max is 0FFFh)
  303. __pastdata    dw    ?    ;address of 1 past data segment
  304. __heapbottom    dw    ?    ;lowest address in heap (used to detect
  305.                 ; free() errors)
  306. __progpar    dw    ?    ;# of paragraphs in PSP + code segment
  307.     if LPTR
  308. __totalpar    dw    ?    ;total # of paragraphs in program
  309.     endif
  310.  
  311. __8087    dw    -1            ;1 means we have an 8087 on board
  312. __psp    dw    ?            ;segment of program segment prefix
  313. __osmajor label    byte            ;MSC compatibility
  314. __dos        db    ?        ;MS-DOS major version number
  315. __osminor label    byte            ;MSC compatibility
  316.         db    ?        ;MS_DOS minor version number
  317. __oserr label    word            ;Lattice C compatibility
  318. __doserrno label    word            ;DOS error number (for compatibility
  319.                     ; with MSC). It is the same as errno.
  320. _errno    dw    0            ;global error number
  321. ovrflw    db    CR,LF,'Stack Overflow',CR,LF,'$'
  322. nomem    db    CR,LF,'Not enough memory',CR,LF,'$'
  323. badstk    db    CR,LF,'Bad stack size parameter',CR,LF,'$'
  324. baddos    db    CR,LF,'DOS 1.xx not supported',CR,LF,'$'
  325. badcmd    db    CR,LF,'Only 32 args allowed',CR,LF,'$'
  326. nullfp    db    CR,LF,'NULL function pointer',CR,LF,'$'
  327.  
  328.     even
  329. _DATA    ends
  330.  
  331. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  332. ; Program segment prefix:
  333. ;    00h        int 20h instruction
  334. ;    02h        top of memory in paragraphs
  335. ;    80h        number of bytes in command line
  336. ;    81h        the command line
  337. ; Input (for .EXE files):
  338. ;    DS,ES        segment of program segment prefix
  339. ;    CS        segment of prog (CS = DS + 10h)
  340. ;    IP        offset of $start from prog
  341. ;    SS        right after end of stack segment
  342. ;    SP        100h (the stack grows negative)
  343.  
  344.     if LCODE
  345. C_TEXT    segment    word 'CODE'
  346.     assume    cs:C_TEXT
  347.     else
  348. _TEXT    segment    word 'CODE'
  349.     assume    cs:_TEXT
  350.     endif
  351.  
  352.     assume DS:DGROUP
  353.  
  354.     ifdef    I8086T
  355. begin:
  356.     ;Monkey around because the assembler won't give us
  357.     ;the data segment start. We have to compute it.
  358.     cli
  359.     mov    AX,offset CGROUP:C_ETEXT
  360.     add    AX,15        ;round up to next paragraph
  361.     mov    CX,4
  362.     shr    AX,CL        ;convert offset to paragraphs
  363.     mov    CX,CS
  364.     add    AX,CX        ;now AX = segment of DGROUP
  365.     else
  366. start:                ;program entry point
  367.     cli            ;turn off till we get stack fixed up
  368.     mov    AX,seg DGROUP    ;start of data segment (in paragraphs)
  369.     endif
  370.  
  371.     fninit            ;initialize 8087 (no WAITs, so do it early)
  372.  
  373.     mov    DS,AX        ;now we have the correct data segment
  374.     mov    __psp,ES        ;save segment of PSP
  375.     mov    BX,AX
  376.     sub    BX,__psp        ;# of paragraphs in PSP + code
  377.     mov    __progpar,BX    ;and save that
  378.  
  379.     mov    BX,ES:2        ;top of memory (in paragraphs)
  380.     sub    BX,AX        ;BX = # of paragraphs we have in data seg
  381.     .if    BX b 1000h, L10    ;if less than 64k
  382.     mov    BX,0FFFh    ;round down
  383. L10:    mov    DX,AX
  384.     add    DX,BX
  385.     inc    DX        ;DX = # of paragraphs of code + data + round
  386.     mov    CL,4
  387.     shl    BX,CL
  388.     mov    SS,AX        ;set SS to data segment
  389.     mov    SP,BX        ;set SP to that too
  390.  
  391.     ;See if we have enough stack space before we turn interrupts back on.
  392.     sub    BX,offset DGROUP:cmdline ;max of allocated addresses
  393.     .if    BX a 512, L11         ;should be enough for the moment
  394.     mov    DX,offset nomem
  395.     jmp    fatmsg
  396.  
  397. L11:    sti
  398.  
  399.     ;Figure out what version of MS-DOS we're running under.
  400.     bdos    30h
  401.     mov    word ptr __dos,AX
  402.     .if    AL ae 2, L7    ;if 2.00 or later
  403.     mov    DX,offset baddos
  404.     jmp    fatmsg
  405.  
  406. L7:
  407.  
  408.     ;Transfer the command line to cmdline, as the PSP is not
  409.     ;necessarilly in the data segment.
  410.  
  411.     mov    AX,ES
  412.     mov    DS,AX        ;DS points to PSP
  413.     mov    AX,SS
  414.     mov    ES,AX        ;ES points to data segment
  415.  
  416.     mov    SI,80h
  417.     cld
  418.     lodsb            ;AL = # of bytes in command line
  419.     xor    AH,AH
  420.     mov    CX,AX        ;# of bytes to copy
  421.     mov    DI,offset DGROUP:cmdline
  422.     rep    movsb        ;transfer to stack
  423.     xor    AL,AL
  424.     stosb            ;and a terminating 0
  425.  
  426.     ;Now set DS to be the same as ES and SS
  427.  
  428.     mov    AX,SS
  429.     mov    DS,AX
  430.  
  431.     ;Round up DI, which will form the bottom of the stack
  432.     inc    DI
  433.     and    DI,0FFFEh
  434.     mov    __BASE,DI
  435.     if SPTR
  436.     mov    word ptr [DI],55AAh    ;stack overflow check word
  437.     endif
  438.  
  439.     ifndef    INTONLY
  440.     fnstsw    __8087        ;store status word
  441.                 ;(do it early to be sure it is done
  442.                 ;by the time we read __8087)
  443.     endif
  444.  
  445.     ;Set up argc and argv
  446.  
  447.     mov    SI,offset DGROUP:cmdline    ;SI -> start of command line
  448.     mov    BX,SIZEPTR    ;number of args * SIZEPTR
  449. L1:    lodsb            ;get char from command line
  450.     .if    AL ne '=', L5
  451.     .if    __stack e 0, L5    ;if ignore '=nnnn' command
  452.     call    set_stack    ;set _stack
  453. L5:    or    AL,AL        ;end of command line?
  454.     jz    L2        ;yes, done
  455.     mov    DX,9*256 + ' '
  456.     .if    AL e ' ', L1
  457.     .if    AL e 9, L1    ;eat spaces and tabs
  458.     .if    AL e '"', L22
  459.     .if    AL ne "'", L21
  460. L22:    mov    DL,AL
  461.     mov    DH,AL
  462.     inc    SI        ;point past the ' or "
  463.  
  464. L21:    .if    BX be ARGMAX*SIZEPTR, L20
  465.     mov    DX,offset badcmd
  466.     jmp    fatmsg
  467.  
  468. L20:    dec    SI        ;address of start of parameter
  469.     mov    argv[BX],SI    ;store in argv
  470.     if LPTR
  471.     mov    argv+2[BX],DS
  472.     endif
  473.     add    BX,SIZEPTR    ;next slot in argv
  474. L4:    lodsb            ;get char of parameter
  475.     or    AL,AL        ;done?
  476.     jz    L2        ;yes
  477.     .if    AL e DL, L3    ;end of parameter
  478.     .if    AL ne DH, L4    ;not end of parameter
  479. L3:    xor    AL,AL
  480.     mov    -1[SI],AL    ;terminate parameter with a 0
  481.     jmp    L1        ;look for next parameter
  482.  
  483. L2:    shr    BX,1        ;get arg count
  484.     if LPTR
  485.     shr    BX,1
  486.     endif
  487.     mov    argc,BX        ;and put in argc
  488.  
  489.     ;Determine if we have an 8087, 80287, or 80387
  490.  
  491.     xor    BX,BX        ;assume no NDP
  492.     test    __8087,0B8BFh
  493.     jnz    L6            ;no 8087
  494.     inc    BX            ;could be 8087, 80287 or 80387
  495.     and    byte ptr __8087,07Fh    ;turn off interrupt mask bit
  496.     fldcw    __8087
  497.     fdisi                ;disable interrupts (works on 8087 only)
  498.     fstcw    __8087
  499.     fwait
  500.     test    byte ptr __8087,80h    ;see if bit is back on
  501.     jnz    L6            ;yes, then 8087
  502.     inc    BX            ;287 or 387
  503.     or    byte ptr __8087,0BFh    ;disable interrupts, mask exceptions
  504.     and    __8087,0EFFFh        ;turn off infinity bit
  505.     fldcw    __8087
  506.     fld1
  507.     fldz
  508.     fdivp    ST(1),ST    ;divide by 0 to get infinity
  509.     fld    ST
  510.     fchs            ;create +infinity and -infinity
  511.     fcompp            ;and see if they're the same
  512.     fstsw    AX
  513.     or    __8087,08000h    ;turn on infinity bit
  514.     fldcw    __8087
  515.     sahf
  516.     jz    L6        ;equal, so it's a 287
  517.     inc    BX        ;BX = 3 for 80387
  518. L6:    mov    __8087,BX    ;set flag
  519.  
  520.     ;Set up stack boundaries
  521.  
  522.     ;__stack = min(_stack,512)
  523.  
  524.     mov    BX,__stack
  525.     or    BX,BX        ;if __stack was special value of 0
  526.     jnz    L14
  527.     mov    BX,02000h    ;then use this as the stack size
  528. L14:    .if    BX ae 512, L8    ;make sure at least 512 bytes
  529.     mov    BX,512
  530. L8:    mov    __stack,BX
  531.  
  532.     if SPTR
  533.     add    BX,__BASE    ;add base of stack to stack size
  534.     jc    outofmemory
  535.     else
  536.     mov    BX,__BASE
  537.     endif
  538.     add    BX,2 + 15    ;base word + round up to paragraph
  539.     jc    outofmemory
  540.     and    BX,0FFF0h
  541.     mov    __pastdata,BX
  542.     mov    __heapbottom,BX
  543.     mov    CL,4
  544.     shr    BX,CL
  545.     mov    __datapar,BX    ;# of paragraphs in data segment
  546.     add    BX,__progpar    ;total size of program in paragraphs
  547.     if LPTR
  548.     mov    __totalpar,BX
  549.     endif
  550.     mov    ES,__psp        ;segment of start of program
  551.     cli            ;SP could point to unallocated memory
  552.     bdos    4Ah        ;resize memory
  553.     push    DS
  554.     pop    ES        ;restore ES
  555.     jnc    L9
  556.     sti
  557.  
  558. outofmemory:
  559.     mov    DX,offset nomem
  560.     jmp    fatmsg
  561.  
  562. L9:
  563.     if SPTR
  564.     mov    SP,__heapbottom    ;new top of stack
  565.     sti
  566.     .if    __okbigbuf e 0, L12
  567.     ;Attempt to grow our data segment to 64k
  568.     mov    AX,0FFF0h
  569.     sub    AX,__pastdata
  570.     push    AX
  571.     call    _sbrk
  572.     pop    BX        ;dump argument off stack
  573.     .if    AX e -1, L13    ;error
  574.     add    AX,2        ;skip over byte count
  575.     push    AX
  576.     call    _free        ;add to memory pool
  577.     pop    BX        ;clean stack
  578.     jmp    short L12
  579.  
  580. L13:    mov    __okbigbuf,0    ;big buffers are not ok, we're short on memory
  581. L12:
  582.     else
  583.     mov    __okbigbuf,0    ;no big buffers for large data model
  584.     push    __stack
  585.     call    _sbrk        ;grow data segment by size of stack wanted
  586.     pop    CX        ;fix stack
  587.     .if    AX e -1, outofmemory
  588.  
  589.     cli            ;while we fiddle with the stack
  590.     mov    ES,DX
  591.     mov    BX,AX
  592.     mov    SP,ES:[BX]    ;set just past end of allocated block
  593.     add    SP,16        ;one paragraph more
  594.     dec    DX        ;but compensate by decrementing segment
  595.     mov    SS,DX        ;this is so stack overflow checks work better
  596.     sti
  597.  
  598.     mov    __heapbottom,SP    ;set top of stack
  599.     mov    __BASE,16    ;set address of check word
  600.     mov    word ptr SS:16,55AAh    ;stack check word
  601.     endif
  602.  
  603.     call    getargv0    ;determine argv[0] if possible
  604.  
  605.     ;Clear uninitialized data segment (UDATA)
  606.     push    DS
  607.     pop    ES
  608.     ifdef I8086T
  609.     mov    CX,offset DGROUP:bssend
  610.     else
  611.     mov    CX,offset DGROUP:_end
  612.     endif
  613.     mov    DI,offset DGROUP:_edata        ;start of uninitialized data
  614.     sub    CX,DI        ;CX = number of bytes to clear
  615.     jcxz    L23        ;no uninitialized data
  616.     xor    AL,AL
  617.     rep    stosb        ;clear it out
  618. L23:
  619.  
  620.  
  621.     xor    BP,BP        ;so debuggers can find last stack frame
  622.     call    __entry        ;perform static constructors
  623.  
  624.  
  625.     ;Call _main(argc,argv)
  626.  
  627.     if LPTR
  628.     push    DS        ;segment of argv
  629.     endif
  630.     mov    AX,offset DGROUP:argv
  631.     push    AX
  632.     push    argc
  633.     call    __main        ;call C _main(argc,argv)
  634.     push    AX        ;save exit status for _exit
  635.     callm    __chkstack    ;see if stack overflowed
  636.     call    _exit        ;return to MS-DOS
  637.  
  638. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  639. ; Determine argv[0] if possible.
  640.  
  641. getargv0 proc    near
  642.     .if    __osmajor b 3, GA1    ;not possible for old versions of DOS
  643.  
  644.     ;Determine start of argv0
  645.     mov    ES,__psp
  646.     mov    ES,ES:2Ch        ;get segment of environment string
  647.     xor    DI,DI
  648.     xor    AL,AL            ;looking for terminating 0
  649.     mov    CX,0FFFFh
  650.     cld
  651. GA2:    repne    scasb
  652.     scasb                ;2 bytes of 0?
  653.     jnz    GA2            ;no, more environment
  654.     add    DI,2            ;ES:DI -> argv0
  655.     if LPTR
  656.     mov    argv,DI
  657.     mov    argv+2,ES
  658.     else ;SPTR
  659.     ;Need to copy to a location accessible by DS. Use the stack.
  660.     ;Determine length needed in CX.
  661.     mov    SI,DI            ;save offset
  662.     mov    CX,0FFFFh
  663.     repne    scasb            ;look for terminating 0
  664.     neg    CX
  665.     and    CX,0FFFEh        ;CX is count rounded up to next word
  666.     pop    BX            ;BX = return address from this function
  667.     sub    SP,CX            ;allocate room for argv0
  668.     mov    DI,SP
  669.     push    ES
  670.     pop    DS            ;SI:DS -> argv0
  671.     push    SS
  672.     pop    ES            ;ES:DI -> stack buffer
  673.     rep    movsb            ;transfer to stack
  674.     push    SS
  675.     pop    DS            ;restore DS
  676.     mov    argv,SP            ;set pointer to it
  677.     ;Note at this point, ES==DS
  678.     jmp    BX
  679.     endif
  680. GA1:    ret
  681. getargv0 endp
  682.  
  683. ;;;;;;;;;;;;;;
  684. ; Set __stack.
  685. ; Input:
  686. ;    SI -> start of parameter
  687. ; Returns:
  688. ;    AL = char past end of number
  689. ;    SI -> past AL
  690. ;    Do not destroy BX
  691.  
  692. set_stack proc near
  693.     mov    DI,10
  694.     xor    CX,CX        ;accumulate result in CX
  695. S1:    lodsb            ;get next char of paramter
  696.     or    AL,AL        ;end of command line?
  697.     jz    S2        ;yes
  698.     .if    AL e ' ', S2
  699.     .if    AL e 9, S2    ;if end of parameter
  700.     sub    AL,'0'
  701.     js    err
  702.     cbw            ;AH = 0
  703.     .if    AX ae DI, err    ;AL is not a digit
  704.     xchg    AX,CX
  705.     mul    DI
  706.     jc    err        ;integer overflow
  707.     add    CX,AX        ;CX = CX*10 + AX
  708.     jnc    S1        ;no error
  709.  
  710. err:    mov    DX,offset badstk
  711.     jmp    short fatmsg
  712.  
  713. S2:    mov    __stack,CX    ;store result in __stack
  714.     ret
  715. set_stack endp
  716.  
  717. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  718. ; Terminate execution of C program.
  719. ; Input:
  720. ;    2[SP]    error code (ignored if not MS-DOS 2.00)
  721.  
  722. func    __exit
  723.     bdos    30h        ;get DOS version number
  724.     .if    AL b 2, E1    ;if pre-DOS 2.00
  725.  
  726.     mov    BP,SP
  727.     mov    AL,P-2[BP]    ;AL = error code
  728.     bdos    04Ch        ;Terminate a process (Exit)
  729.  
  730. E1:    push    __psp
  731.     xor    AX,AX
  732.     push    AX        ;push &(PSP:0)
  733.     .retf            ;far return to DOS
  734. __exit    endp
  735.  
  736. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  737. ; Check and see if stack overflowed.
  738. ; This can be called at any time by the application code. It is useful
  739. ; to place a call to this at selected points when stack overflow checking
  740. ; is turned off.
  741. ; Returns:
  742. ;    # of bytes left in stack
  743.  
  744. func    __chkstack
  745.     mov    BX,__BASE
  746.     if SPTR
  747.     .if    <word ptr [BX]> ne 55AAh, XCOVF
  748.     else
  749.     .if    <SS:word ptr [BX]> ne 55AAh, XCOVF
  750.     endif
  751.     mov    AX,SP
  752.     sub    AX,BX
  753.     jbe XCOVF
  754.     .if    SP a __heapbottom, XCOVF
  755.     ret
  756. __chkstack endp
  757.  
  758. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  759. ; Stack frame generator.
  760. ; Called at entry to each function when stack overflow checking
  761. ; is turned on.
  762.  
  763. func    __chkstk
  764.     pop    DX        ;get offset of return addr
  765.     if LCODE
  766.     pop    CX        ;get segment
  767.     endif
  768.     sub    SP,AX        ;create space for local variables
  769.     jbe    XCOVF        ;overflowed
  770.     mov    BX,__BASE
  771.     if SPTR
  772.     .if    <word ptr [BX]> ne 55AAh, XCOVF
  773.     else
  774.     .if    <SS:word ptr [BX]> ne 55AAh, XCOVF
  775.     endif
  776.     if SPTR
  777.     .if    SP ae __heapbottom, XCOVF
  778.     endif
  779.     if LCODE
  780.     push    CX
  781.     push    DX
  782.     ret
  783.     else
  784.     jmp    DX        ;return to caller
  785.     endif
  786. __chkstk endp
  787.  
  788. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  789. ; Stack overflow jumps here.
  790.  
  791. XCOVF:    mov    DX,offset ovrflw
  792. ;    jmp    short fatmsg
  793.  
  794. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  795. ; Print out fatal error message and abort.
  796. ; Input:
  797. ;    DS:DX -> message
  798.  
  799. fatmsg:    bdos    9
  800.     mov    AX,1        ;error exit code
  801.     push    AX
  802.     call    __exit        ;abort
  803.     ;never reached
  804.  
  805.     if LCODE
  806. C_TEXT    ends
  807.     else
  808. _TEXT    ends
  809.     endif
  810.  
  811.     end    start
  812.