|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.