Annotation of os2sdk/startup/dos/crt0.asm, revision 1.1

1.1     ! root        1:        page    ,132
        !             2:        TITLE   crt0 - C start up routine
        !             3: ;***
        !             4: ;crt0.asm - C start up routine
        !             5: ;
        !             6: ;      Copyright (c) 1985-1987, 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: ;      If the user reassembles this module, he will need to link using the
        !            22: ;      /DOSSEG switch or run the the DOSSEG.EXE program on crt0.obj, i.e.
        !            23: ;
        !            24: ;              dosseg crt0.obj
        !            25: ;
        !            26: ;      See the C documentation for more information about the /DOSSEG switch.
        !            27: ;
        !            28: ;      All assembler modules must be assembled with the /mx switch, i.e.
        !            29: ;
        !            30: ;              masm crt0/mx;
        !            31: ;
        !            32: ;*******************************************************************************
        !            33: 
        !            34: 
        !            35: ?DF=   1                       ; this is special for c startup
        !            36: include        version.inc
        !            37: .xlist
        !            38: ifdef  _QC                     ;[5] move includes out of version
        !            39: include        \sl\qc\src\include\kernel.inc   ;[5]
        !            40: include        \sl\qc\src\include\kmac.inc     ;[5]
        !            41: CEDEF  macro   name, num, msg          ;;[8]
        !            42: name   equ     num                     ;;[8]
        !            43: endm                                   ;;[8]
        !            44: include \sl\qc\src\include\criterr.inc ;[8]
        !            45: endif  ;_QC                    ;[5] 
        !            46: 
        !            47: include        cmacros.inc
        !            48: include        msdos.inc
        !            49: include        brkctl.inc
        !            50: .list
        !            51: 
        !            52: ifdef  _QC                     ;[2]
        !            53: extrn  $Exec_Shell:FAR         ;[9]
        !            54: extrn  $GlobalAlloc:FAR        ;[2]
        !            55: extrn  $GlobalLock:FAR         ;[2]
        !            56: extrn  $GlobalUnlock:FAR       ;[2]
        !            57: extrn  _AddString:FAR          ;[2]
        !            58: endif  ;_QC                    ;[2]
        !            59: 
        !            60:        page
        !            61: ;===========================================================================
        !            62: ;
        !            63: ;      Segment definitions
        !            64: ;
        !            65: ;      The segment order is essentially the same as in XENIX.
        !            66: ;      This module is edited after assembly to contain a dosseg comment
        !            67: ;      record for the linker.
        !            68: ;
        !            69: ;===========================================================================
        !            70: 
        !            71: createSeg _TEXT, code, word,   public, CODE,   <>
        !            72: createSeg C_ETEXT,etext, word, public, ENDCODE,<>
        !            73: 
        !            74: createSeg _DATA, data, word,   public, DATA,   DGROUP
        !            75: createSeg STACK, stack,        para,   stack,  STACK,  DGROUP
        !            76: 
        !            77: defGrp DGROUP                  ; define DGROUP
        !            78: 
        !            79: codeOFFSET equ offset _TEXT:
        !            80: dataOFFSET equ offset DGROUP:
        !            81: 
        !            82: page
        !            83: 
        !            84: public __acrtused              ; trick to force in startup
        !            85:        __acrtused = 9876h      ; funny value not easily matched in SYMDEB
        !            86: 
        !            87: extrn  __acrtmsg:abs           ; trick to pull in startup messages
        !            88: 
        !            89: 
        !            90: ifndef _QC
        !            91: sBegin stack
        !            92: assumes        ds,data
        !            93:        db      2048 dup (?)    ; default stack size
        !            94: sEnd
        !            95: endif  ;_QC
        !            96: 
        !            97: page
        !            98: 
        !            99: ifndef _QC
        !           100: externP        main                    ; C main program
        !           101: endif  ;_QC
        !           102: 
        !           103: externP        exit                    ; exit ( code )
        !           104: 
        !           105: if     sizeC
        !           106: extrn  __exit:far              ; _exit ( code) (cmacros name conflict)
        !           107: else
        !           108: extrn  __exit:near
        !           109: endif
        !           110: 
        !           111: sBegin data
        !           112: 
        !           113: extrn  _edata:byte             ; end of data (start of bss)
        !           114: extrn  _end:byte               ; end of bss (start of stack)
        !           115: 
        !           116: externW        _psp                    ; psp:0 (paragraph #)
        !           117: externW        __argc
        !           118: externDP __argv
        !           119: externDP environ
        !           120: 
        !           121: ifdef _QC
        !           122: externW        _QChdata                ; High water mark of data space
        !           123: globalW        _QCldata,0              ; begining of DGroup (low water mark)
        !           124: 
        !           125: extrn  STKHQQ:WORD
        !           126: 
        !           127: extrn  __QCrtcsip:DWORD        ;[2]
        !           128: endif  ;_QC
        !           129: 
        !           130: ;      these are used by DOS C memory management (not used in Windows)
        !           131: 
        !           132: globalW        _asizds,0               ; DS size (in bytes)
        !           133: globalW        _atopsp,0               ; top of stack (heap bottom)
        !           134: globalW        _aexit_rtn,<codeoffset __exit> ; NEAR pointer
        !           135: 
        !           136: labelW <PUBLIC,_abrktb>        ; segment table for brkctl
        !           137:        dw      ?
        !           138:        dw      DGROUP
        !           139:        db      (MAXSEG-1) * (size segrec) dup (?)
        !           140: 
        !           141: labelW <PUBLIC,_abrktbe>
        !           142: globalW        _abrkp,<dataoffset _abrktb>
        !           143: 
        !           144: sEnd
        !           145: 
        !           146:        page
        !           147: 
        !           148: 
        !           149: externP        _cinit                  ; run-time initializers
        !           150: 
        !           151: ifdef _QC
        !           152: externP _NMSG_TEXT             ; pascal - find error message text
        !           153: endif
        !           154: externP _NMSG_WRITE            ; pascal - write error message to stdout
        !           155: externP        _FF_MSGBANNER           ; pascal - error message banner
        !           156:                                ; (includes FORTRAN $DEBUG info)
        !           157: 
        !           158: externP        _setargv                ; process command line arguments
        !           159: externP        _setenvp                ; process environment
        !           160: externP        _nullcheck              ; check for null assignment
        !           161: 
        !           162: 
        !           163: sBegin code
        !           164: assumes        cs,code
        !           165: 
        !           166: ifdef  _QC
        !           167: 
        !           168:        public  $F_PSP          ; Segment of the fake PSP for QC
        !           169: $F_PSP dw      0               ; Must be in CODE segment for recovery.
        !           170: FirstTime db   1;              ;[10] Flag to catch when the shell startup
        !           171:                                ;[10]   code is executed.
        !           172: 
        !           173: assumes        ds,DGROUP               ; DGROUP is setup and set by QC kernel
        !           174: assumes        es,nothing
        !           175: else   ;_QC
        !           176: assumes        ds,nothing
        !           177: endif  ;_QC
        !           178: 
        !           179: page
        !           180: ;***
        !           181: ;_astart - start of all C programs
        !           182: ;
        !           183: ;Purpose:
        !           184: ;      Startup routine to initialize C run-time environment
        !           185: ;
        !           186: ;Entry:
        !           187: ;
        !           188: ;Exit:
        !           189: ;      Exits to DOS via exit().
        !           190: ;
        !           191: ;Uses:
        !           192: ;
        !           193: ;Exceptions:
        !           194: ;
        !           195: ;*******************************************************************************
        !           196: 
        !           197: labelNP        <PUBLIC,_astart>        ; start address of all "C" programs
        !           198: 
        !           199: ifndef _QC
        !           200: ;      check MS-DOS version for 2.0 or later
        !           201: 
        !           202:        callos  VERSION         ; AX must be preserved until later
        !           203:        cmp     al,2            ; check for version 2 or later
        !           204:        jae     setup           ;   yes - continue with setup
        !           205:        int     20h             ; DOS 1.0 exit program  
        !           206: 
        !           207: setup:
        !           208: endif  ;_QC
        !           209: 
        !           210: ifdef  _QC
        !           211:        mov     cs:[$F_PSP],es  ; Save segment of fake PSP
        !           212: 
        !           213:        mov     di,ds           ; di = DGROUP
        !           214:        mov     si,es:[PSP_EOM_SEG] ; get max. paragraph
        !           215: else   ;_QC
        !           216:        mov     di,DGROUP
        !           217:        mov     si,ds:[DOS_MAXPARA] ; get max. paragraph
        !           218: endif  ;_QC
        !           219: 
        !           220:        sub     si,di           ; si = # para in data area
        !           221:        cmp     si,1000h        ; if more than 64K
        !           222:        jb      setSP
        !           223: 
        !           224:        mov     si,1000H        ; use full 64K (-16)
        !           225: 
        !           226: setSP:
        !           227: 
        !           228:        cli                     ; turn off interrupts
        !           229:        mov     ss,di           ; SS = DGROUP
        !           230:        add     sp,dataoffset _end-2 ; 2 for _asizds limit
        !           231:        sti                     ; turn interrupts back on
        !           232:        jnc     SPok
        !           233: 
        !           234: ifndef         IBMC20
        !           235:        push    ss              ; establish DS=DGROUP for
        !           236:        pop     ds              ; _FF_MSGBANNER -> _NMSG_WRITE -> _NMSG_TEXT
        !           237: endif  ; IBMC20
        !           238: ifdef  _QC                     ;[6]
        !           239:        mov     es,cs:[$F_PSP]  ;[9] find 'fake' PSP
        !           240:        mov     es:[PSP_CRITERR], CE_EXEC; [9] Indicate an error to kernel
        !           241:        jmp     Far Ptr $Exec_Shell ; [9]
        !           242:        
        !           243: else   ;_QC                    ;[6]
        !           244:        call    _FF_MSGBANNER   ; for "\r\nrun-time error " banner
        !           245:        xor     ax,ax           ; stack overflow error message (0)
        !           246:        push    ax
        !           247:        call    _NMSG_WRITE
        !           248:        mov     ax,DOS_terminate shl 8 + 255
        !           249:        callos                  ; terminate process with 255
        !           250: endif  ;_QC                    ;[6]
        !           251: 
        !           252: SPok:
        !           253:        assumes ss,data
        !           254: 
        !           255:        and     sp,not 1        ; make even (if not)
        !           256:        mov     [_abrktb].sz,sp ; top DS free location
        !           257:        mov     [_atopsp],sp    ; save top of stack
        !           258: 
        !           259: ifdef  _QC
        !           260:        mov     bx,sp           ; Setup up a EOS flag on stack.
        !           261:        sub     bx,es:[PSP_STK_SIZE]
        !           262:        add     bx,2+256        ;[1]add stack "slop" to keep 256 bytes
        !           263:        mov     [STKHQQ],bx
        !           264:        mov     Word Ptr [bx],5252h
        !           265: endif  ;_QC
        !           266: 
        !           267:        mov     ax,si           ; si = # paragraphs
        !           268:        mov     cl,4
        !           269:        shl     ax,cl
        !           270:        dec     ax
        !           271:        mov     [_asizds],ax    ; save DS size - 1 (in bytes)
        !           272: 
        !           273: ifdef  _QC
        !           274:        mov     [__psp],es
        !           275: 
        !           276:        mov     [__QCldata],di          ; Low end of memory for pointer checking
        !           277: 
        !           278:        mov     es,di                   ; es = DGROUP
        !           279:        push    es                      ;[7] save DGROUP
        !           280: 
        !           281:        mov     ax,1                    ;[7] Now look for high end
        !           282:        call    $GlobalLock             ;[7] handle table
        !           283:        mov     es,ax                   ;[7]
        !           284:        mov     bx,0                    ;[7]
        !           285:        mov     cx,128                  ;[7] 128 entries in table
        !           286:        mov     ax,0                    ;[7] current high
        !           287:        
        !           288: ast1a:                                 ;[7]
        !           289:        cmp     ax,es:[bx]              ;[7] is this high
        !           290:        jae     ast1b                   ;[7] no
        !           291:        mov     ax,es:[bx]              ;[7] yes - new high
        !           292: ast1b:
        !           293:        add     bx,2                    ;[7] move to next entry
        !           294:        loop    ast1a                   ;[7] loop until done
        !           295: 
        !           296:        mov     [_QChdata],ax           ;[7] save as top of memory.
        !           297:        pop     es                      ;[7] restore es=DGROUP
        !           298: assumes        es,DGROUP
        !           299: 
        !           300: else   ;_QC
        !           301: 
        !           302: ;      release extra space to DOS
        !           303: 
        !           304:        add     si,di           ; si = DGROUP + # para in DGROUP
        !           305:        mov     ds:[DOS_MAXPARA],si ; fix psp:2
        !           306:        mov     bx,es           ; bx = PSP base
        !           307:        sub     bx,si           ; bx = - # para used
        !           308:        neg     bx
        !           309:        callos  setmem          ; set memory block size
        !           310:        mov     [_psp],ds       ; save psp:0
        !           311: 
        !           312: ;      zero data areas (_BSS and c_common)
        !           313: 
        !           314:        push    ss
        !           315:        pop     es
        !           316:        assumes es,data
        !           317: 
        !           318:        cld                     ; set direction flag (up)
        !           319:        mov     di,dataOFFSET _edata ; beginning of bss area
        !           320:        mov     cx,dataOFFSET _end ; end of bss area
        !           321:        sub     cx,di
        !           322:        xor     ax,ax
        !           323:        rep     stosb           ; zero bss
        !           324: 
        !           325: ;      C segmentation conventions set up here  (DS=SS and CLD)
        !           326: 
        !           327:        push    ss              ; set up initial DS=ES=SS, CLD
        !           328:        pop     ds
        !           329:        assumes ds,data
        !           330: endif  ;_QC
        !           331: 
        !           332: ;      do necessary initialization BEFORE command line processing!
        !           333: 
        !           334:        call    _cinit          ; shared by DOS and Windows
        !           335: 
        !           336:        push    ss
        !           337:        pop     ds              ; ds = DGROUP
        !           338:        assumes ds,data
        !           339: 
        !           340: ;      process command line and environment
        !           341: 
        !           342: ifdef  _QC                     ;[10]
        !           343:        test    [FirstTime],1   ;[10] Is this the first time?
        !           344:        jz      setenv2         ;[10] No  -  do the environment
        !           345:        mov     es,[_psp]       ;[11] look at fake psp to see if 
        !           346:        test    es:[PSP_KERNEL_FLGS],PSP_KF_BATCH;[11] in batch mode?
        !           347:        jz      setenv1         ;[11] yes - skip parsing env
        !           348: setenv2:
        !           349:        call    _setenvp        ;[10] crack enviornment
        !           350: setenv1:                       ;[10]
        !           351:        mov     [FirstTime],0   ;[10] Never the first time again
        !           352: else   ;_QC                    ;[10]
        !           353:        call    _setenvp        ; crack environment
        !           354: endif  ;_QC                    ;[10]
        !           355:        call    _setargv        ; crack command line
        !           356: 
        !           357: ;      call main and exit
        !           358: 
        !           359:        xor     bp,bp           ; mark top stack frame for SYMDEB
        !           360: 
        !           361: if     sizeD
        !           362:        push    word ptr [environ+2] ; the environment is not always in DS
        !           363: endif
        !           364:        push    word ptr [environ]
        !           365: 
        !           366: if     sizeD
        !           367:        push    word ptr [__argv+2] ; the arguments are not always in DS
        !           368: endif
        !           369:        push    word ptr [__argv]
        !           370: 
        !           371:        push    [__argc]        ; argument count
        !           372: 
        !           373: ifdef  _QC
        !           374:        mov     es,[__psp]
        !           375:        call    Dword Ptr es:[PSP_MAIN_ENTRY]
        !           376: else   ;_QC
        !           377:        call    main            ; main ( argc , argv , envp )
        !           378: endif  ;_QC
        !           379: 
        !           380: ; use whatever is in ax after returning here from the main program
        !           381: 
        !           382:        push    ax
        !           383:        call    exit            ; exit (AX)
        !           384:                                ;   _exit will call terminators
        !           385: 
        !           386: page
        !           387: ifdef  _QC
        !           388: labelFP <PUBLIC,_QCnptr_error>
        !           389: 
        !           390: ; [2]
        !           391: ; We know we were called far, so to get the 'best guess' cs:ip, we
        !           392: ; just set __QCrtcsip by looking at our return address.
        !           393: ; [2]
        !           394: 
        !           395:        mov     ds,cs:[$F_PSP]          ;[4] get PSP
        !           396:        mov     ax,ds:[PSP_DGROUP_SEG]  ;[4] get DGROUP
        !           397:        mov     ds, ax                  ;[4] ds = DGROUP
        !           398: 
        !           399:        pop     word ptr [__QCrtcsip]   ;[2] Get offset
        !           400:        pop     word ptr [__QCrtcsip+2] ;[2] Get segment
        !           401: 
        !           402:        mov     ax,12           ;Illegal Near pointer encountered.
        !           403:        jmp     short _amsg_exit
        !           404: 
        !           405: labelFP <PUBLIC,_QCfptr_error>
        !           406: 
        !           407: ; [2]
        !           408: ; We know we were called far, so to get the 'best guess' cs:ip, we
        !           409: ; just set __QCrtcsip by looking at our return address.
        !           410: ; [2]
        !           411: 
        !           412:        mov     ds,cs:[$F_PSP]          ;[4] get PSP
        !           413:        mov     ax,ds:[PSP_DGROUP_SEG]  ;[4] get DGROUP
        !           414:        mov     ds, ax                  ;[4] ds = DGROUP
        !           415: 
        !           416:        pop     word ptr [__QCrtcsip]   ;[2] Get offset
        !           417:        pop     word ptr [__QCrtcsip+2] ;[2] Get segment
        !           418: 
        !           419:        mov     ax,13           ;Illegal Far pointer encountered.
        !           420:        jmp     short _amsg_exit
        !           421: 
        !           422: labelFP        <PUBLIC,_Break_error>
        !           423: 
        !           424: ; [2]
        !           425: ; We know we were called far, so to get the 'best guess' cs:ip, we
        !           426: ; just set __QCrtcsip by looking at our return address.
        !           427: ; [2]
        !           428: 
        !           429:        mov     ds,cs:[$F_PSP]          ;[4] get PSP
        !           430:        mov     ax,ds:[PSP_DGROUP_SEG]  ;[4] get DGROUP
        !           431:        mov     ds, ax                  ;[4] ds = DGROUP
        !           432: 
        !           433:        pop     word ptr [__QCrtcsip]   ;[2] Get offset
        !           434:        pop     word ptr [__QCrtcsip+2] ;[2] Get segment
        !           435: 
        !           436:        mov     ax,14           ;Control BREAK encountered.
        !           437:        jmp     short _amsg_exit
        !           438: endif  ;_QC
        !           439: 
        !           440: ;***
        !           441: ;_amsg_exit, _cintDIV - Fast exit fatal errors
        !           442: ;
        !           443: ;Purpose:
        !           444: ;      Exit the program with error code of 255 and appropriate error
        !           445: ;      message.  cintDIV is used for integer divide by zero, amsg_exit
        !           446: ;      is for other run time errors.
        !           447: ;
        !           448: ;Entry:
        !           449: ;      AX      = error message number (amsg_exit only).
        !           450: ;
        !           451: ;Exit:
        !           452: ;      calls exit() [cintDIV] or indirect through _aexit_rtn [amg_exit].
        !           453: ;
        !           454: ;Uses:
        !           455: ;
        !           456: ;Exceptions:
        !           457: ;
        !           458: ;*******************************************************************************
        !           459: 
        !           460: labelNP        <PUBLIC,_cintDIV>
        !           461: 
        !           462: ifndef IBMC20
        !           463:        assumes ds,nothing
        !           464:        assumes ss,data
        !           465: 
        !           466: endif ; IBMC20
        !           467: 
        !           468: ifdef  IBMC20
        !           469: ;      _NMSG_WRITE will reestablish ds = DGROUP
        !           470: else
        !           471: ;      _cintDIV establishes ds = DGROUP
        !           472: endif ; IBMC20
        !           473: 
        !           474: ifdef  _QC                             ;[3]
        !           475: ; [3]
        !           476: ; We got here from an interrupt so the stack looks like:
        !           477: ;   flags
        !           478: ;   seg
        !           479: ;   off
        !           480: ; So to get the CS:IP where it occurred, we just pop the seg and off from
        !           481: ; the stack (we don't need to get back...)
        !           482: ; [3]
        !           483: 
        !           484:        mov     ds,cs:[$F_PSP]          ;[4] get PSP
        !           485:        mov     ax,ds:[PSP_DGROUP_SEG]  ;[4] get DGROUP
        !           486:        mov     ds, ax                  ;[4] ds = DGROUP
        !           487: 
        !           488:        pop     word ptr [__QCrtcsip]   ;[3] Offset
        !           489:        pop     word ptr [__QCrtcsip+2] ;[3] Segment
        !           490: else
        !           491: ifndef IBMC20
        !           492:        mov     ax, DGROUP              ; reestablish DS=DGROUP
        !           493:        mov     ds, ax  
        !           494: endif ; IBMC20
        !           495: endif  ;_QC                            ;[3]
        !           496: 
        !           497:        mov     ax,3            ; Integer divide by zero interrupt
        !           498:        mov     [_aexit_rtn],codeoffset _exit ; call high-level exit()
        !           499:                                ; to cause file buffer flushing
        !           500: 
        !           501: labelNP        <PUBLIC,_amsg_exit>
        !           502: 
        !           503: ifdef  _QC                     ;[2]
        !           504:        push    si              ;[2] Is this necessary?
        !           505:        push    di              ;[2] Is this necessary?
        !           506:        mov     si, ax          ;[2] Save message number
        !           507: endif  ;_QC                    ;[2]
        !           508: 
        !           509:        push    ax              ; message number for _NMSG_WRITE
        !           510:        call    _FF_MSGBANNER   ; run-time error message banner
        !           511:        call    _NMSG_WRITE     ; write error message to stdout
        !           512: 
        !           513: ifdef  _QC                                     ;[2]
        !           514:        mov     es, cs:[$F_PSP]                 ;[2] Find 'fake' PSP
        !           515:        mov     es:[PSP_CRITERR], 255           ;[2] Indicate error to kernel
        !           516: 
        !           517:        mov     ax, es:[PSP_ERRTAB_HDL]         ;[2] Find error table handle
        !           518:        or      ax, ax                          ;[2] Does it exist?
        !           519:        jnz     _QC_0                           ;[2] Yes, don't allocate
        !           520: 
        !           521:        mov     ax, 26 * size error_struct      ;[2]
        !           522:        xor     dx, dx                          ;[2]
        !           523:        xor     cx, cx                          ;[2]
        !           524:        call    $GlobalAlloc                    ;[2]
        !           525:        or      ax, ax                          ;[8] Check to see if we got it
        !           526:        jz      _QC_Fail                        ;[8] Allocation failed
        !           527: 
        !           528: _QC_0:
        !           529:        mov     di, ax                          ;[2] Save handle
        !           530:        call    $GlobalLock                     ;[2] Handle should be in AX
        !           531:        mov     es, ax                          ;[2] Get seg of memory block
        !           532: 
        !           533:        mov     ax, si                          ;[2] Get error number
        !           534:        or      ax, 8000h                       ;[2] Set high bit in case 0
        !           535:        mov     es:[es_ecode], ax               ;[2]
        !           536:        mov     ax, word ptr __QCrtcsip         ;[2]
        !           537:        mov     es:[es_oln], ax                 ;[2] Save IP (kludge)
        !           538:        mov     ax, word ptr __QCrtcsip + 2     ;[2]
        !           539:        mov     es:[es_ob], ax                  ;[2] Save CS (kludge)
        !           540: 
        !           541:        push    es                              ;[2]
        !           542: 
        !           543:        mov     ax,255                          ;[2] 'run-time error' msg
        !           544:        push    ax                              ;[2]
        !           545:        call    _NMSG_TEXT                      ;[2] Fetch msg
        !           546:        push    ax                              ;[2]
        !           547:        call    _AddString                      ;[2] Add to strings heap
        !           548:        add     sp, 2                           ;[2] C-calling convention
        !           549:        cmp     ax, 0FFFFh                      ;[8] Error?
        !           550:        jnz     _QC_2                           ;[8] No, continue
        !           551: 
        !           552:        pop     es                              ;[8]
        !           553:        jmp     short _QC_Fail                  ;[8]
        !           554: 
        !           555: _QC_2:                                         ;[8]
        !           556:        xchg    si, ax                          ;[2] Save offset in heap
        !           557:        push    ax                              ;[2] Retrieve message number
        !           558:        call    _NMSG_TEXT                      ;[2] Return AX -> msg
        !           559:        push    ax                              ;[2]
        !           560:        call    _AddString                      ;[2] Add string to heap
        !           561:        add     sp, 2                           ;[2] AddString is C-calling
        !           562: 
        !           563:        pop     es                              ;[2]
        !           564:        cmp     ax, 0FFFFh                      ;[8] Error in AddString?
        !           565:        jz      _QC_Fail                        ;[8] Yes, fail
        !           566:        mov     es:[es_obString], si            ;[2] Save offset of msg
        !           567: 
        !           568:        mov     es, cs:[$F_PSP]                 ;[2]
        !           569:        mov     es:[PSP_ERRTAB_HDL], di         ;[2]
        !           570: 
        !           571:        mov     ax, di                          ;[2] Retrieve handle
        !           572:        call    $GlobalUnlock                   ;[2]
        !           573:        jmp     short _QC_1                     ;[8] Exit cleanly
        !           574: 
        !           575: _QC_Fail:                                      ;[8] Failure code
        !           576:        mov     es, cs:[$F_PSP]                 ;[8]
        !           577:        mov     es:[PSP_CRITERR], CE_NOMEM      ;[8] Note true error
        !           578: 
        !           579: _QC_1:                                         ;[8] Exit code
        !           580:        pop     di                              ;[2] Necessary?
        !           581:        pop     si                              ;[2] Necessary?
        !           582: endif  ;_QC                                    ;[2]
        !           583: 
        !           584:        assumes ds,data
        !           585: 
        !           586:        mov     ax,255
        !           587:        push    ax
        !           588: if     sizeC
        !           589:        push    cs                              ; _exit is compiled far
        !           590:                                                ;       but called near
        !           591: endif
        !           592:        call    word ptr [_aexit_rtn] ; _exit(255) ordinarily
        !           593:                                ; (or exit(255) for div by 0)
        !           594:                                ; NEAR routine pointer
        !           595: 
        !           596: sEnd
        !           597:        end     _astart         ; start address

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.