Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1679 lines
53 KiB

  1. /* SCCSID = %W% %E% */
  2. /*
  3. * Copyright Microsoft Corporation, 1983-1987
  4. *
  5. * This Module contains Proprietary Information of Microsoft
  6. * Corporation and should be treated as Confidential.
  7. */
  8. /****************************************************************
  9. * *
  10. * NEWUTL.C *
  11. * *
  12. * Linker utilities. *
  13. * *
  14. ****************************************************************/
  15. #include <minlit.h> /* Types, constants */
  16. #include <bndtrn.h> /* More types and constants */
  17. #include <bndrel.h> /* More types and constants */
  18. #include <lnkio.h> /* Linker I/O definitions */
  19. #include <lnkmsg.h> /* Error messages */
  20. #include <newdeb.h> /* CodeView support */
  21. #include <extern.h> /* External declarations */
  22. #include <nmsg.h> /* Near message strings */
  23. #include <string.h>
  24. #include <stdarg.h>
  25. #if EXE386
  26. #include <exe386.h>
  27. #endif
  28. #if NEWIO
  29. #include <errno.h> /* System error codes */
  30. #endif
  31. #if USE_REAL
  32. #if NOT defined( _WIN32 )
  33. #define i386
  34. #include <windows.h>
  35. #endif
  36. // The memory sizes are in paragraphs.
  37. #define TOTAL_CONV_MEM (0xFFFF)
  38. #define CONV_MEM_FOR_TNT (0x800) // 32K of memory
  39. #define MIN_CONV_MEM (0x1900) // 100 K of memory
  40. typedef unsigned short selector_t ; //Define type to hold selectors
  41. static selector_t convMemSelector ; // Selector to conv memory.
  42. static short noOfParagraphs ; // size of the available blocks in paragraphs
  43. static int realModeMemPageable ; // = FALSE
  44. #endif
  45. #if WIN_NT OR DOSX32
  46. unsigned char FCHGDSK(int drive)
  47. {
  48. return(FALSE);
  49. }
  50. #endif
  51. #define DISPLAY_ON FALSE
  52. #if DISPLAY_ON
  53. extern int TurnDisplayOn;
  54. #endif
  55. APROPCOMDATPTR comdatPrev=NULL; /* Pointer to symbol table entry */
  56. int fSameComdat=FALSE; /* Set if LINSYM to the same COMDAT */
  57. /********************************************************************
  58. * INPUT ROUTINES *
  59. ********************************************************************/
  60. /*** GetLineOff - read part of LINNUM record
  61. *
  62. * Purpose:
  63. * This function reads line/offset pair from LINNUM record. It is here
  64. * because we want to keep all the I/O functions near and the LINNUM
  65. * processing is performed in NEWDEB.C which resides in another segment.
  66. *
  67. * Input:
  68. * - pLine - pointer to line number
  69. * - pRa - pointer to offset
  70. *
  71. * Output:
  72. * Returns line/offset pair from OMF record.
  73. *
  74. * Exceptions:
  75. * None.
  76. *
  77. * Notes:
  78. * None.
  79. *
  80. *************************************************************************/
  81. void GetLineOff(WORD *pLine, RATYPE *pRa)
  82. {
  83. *pLine = WGets() + QCLinNumDelta; // Get line number
  84. // Get code segment offset
  85. #if OMF386
  86. if (rect & 1)
  87. *pRa = LGets();
  88. else
  89. #endif
  90. *pRa = (RATYPE) WGets();
  91. }
  92. /*** GetGsnInfo - read the segment index of the LINNUM
  93. *
  94. * Purpose:
  95. * This function reads the segemnt index from LINNUM record. It is here
  96. * because we want to keep all the I/O functions near and the LINNUM
  97. * processing is performed in NEWDEB.C which resides in another segment.
  98. *
  99. * Input:
  100. * - pRa - pointer to offset correction for COMDATs
  101. *
  102. * Output:
  103. * Returns global segment index and for lines in COMDAT record
  104. * offset correction.
  105. *
  106. * Exceptions:
  107. * None.
  108. *
  109. * Notes:
  110. * None.
  111. *
  112. *************************************************************************/
  113. WORD GetGsnInfo(GSNINFO *pInfo)
  114. {
  115. WORD fSuccess; // TRUE if everything is OK
  116. WORD attr; // COMDAT flags
  117. WORD comdatIdx; // COMDAT symbol index
  118. APROPCOMDATPTR comdat; // Pointer to symbol table entry
  119. fSuccess = TRUE;
  120. if (TYPEOF(rect) == LINNUM)
  121. {
  122. // Read regular LINNUM record
  123. GetIndex((WORD)0,(WORD)(grMac - 1)); // Skip group index
  124. pInfo->gsn = mpsngsn[GetIndex((WORD)1,(WORD)(snMac - 1))];
  125. // Get global SEGDEF number
  126. pInfo->comdatRa = 0L;
  127. pInfo->comdatSize = 0L;
  128. pInfo->fComdat = FALSE;
  129. }
  130. else
  131. {
  132. // Read LINSYM record - line numbers for COMDAT
  133. attr = (WORD) Gets();
  134. comdatIdx = GetIndex(1, (WORD)(lnameMac - 1));
  135. comdat = (APROPCOMDATPTR ) PropRhteLookup(mplnamerhte[comdatIdx], ATTRCOMDAT, FALSE);
  136. fSameComdat = FALSE;
  137. if (comdat != NULL)
  138. {
  139. if(comdat == comdatPrev)
  140. fSameComdat = 1;
  141. else
  142. comdatPrev = comdat;
  143. if ((fPackFunctions && !(comdat->ac_flags & REFERENCED_BIT)) ||
  144. !(comdat->ac_flags & SELECTED_BIT) ||
  145. comdat->ac_obj != vrpropFile)
  146. {
  147. SkipBytes((WORD)(cbRec - 1));
  148. fSuccess = FALSE;
  149. }
  150. else
  151. {
  152. pInfo->gsn = comdat->ac_gsn;
  153. pInfo->comdatRa = comdat->ac_ra;
  154. pInfo->comdatSize = comdat->ac_size;
  155. pInfo->comdatAlign= comdat->ac_align;
  156. pInfo->fComdat = TRUE;
  157. }
  158. }
  159. else
  160. {
  161. SkipBytes((WORD)(cbRec - 1));
  162. fSuccess = FALSE;
  163. }
  164. }
  165. return(fSuccess);
  166. }
  167. /****************************************************************
  168. * *
  169. * Gets: *
  170. * *
  171. * Read a byte of input and return it. *
  172. * *
  173. ****************************************************************/
  174. #if NOASM
  175. #if !defined( M_I386 ) && !defined( _WIN32 )
  176. WORD NEAR Gets(void)
  177. {
  178. REGISTER WORD b;
  179. if((b = getc(bsInput)) == EOF) InvalidObject();
  180. /* After reading the byte, decrement the OMF record counter. */
  181. --cbRec;
  182. return(b);
  183. }
  184. #endif
  185. #endif
  186. #if ALIGN_REC
  187. #else
  188. /****************************************************************
  189. * *
  190. * WGetsHard: *
  191. * *
  192. * Read a word of input and return it. *
  193. * *
  194. ****************************************************************/
  195. WORD NEAR WGetsHard()
  196. {
  197. REGISTER WORD w;
  198. // handle hard case... easy case already tested in WGets
  199. w = Gets(); /* Get low-order byte */
  200. return(w | (Gets() << BYTELN)); /* Return word */
  201. }
  202. #if OMF386
  203. /****************************************************************
  204. * *
  205. * LGets: *
  206. * *
  207. * Read a long word of input and return it. *
  208. * *
  209. ****************************************************************/
  210. DWORD NEAR LGets()
  211. {
  212. DWORD lw;
  213. FILE * f = bsInput;
  214. // NOTE: this code will only work on a BigEndian machine
  215. if (f->_cnt >= sizeof(DWORD))
  216. {
  217. lw = *(DWORD *)(f->_ptr);
  218. f->_ptr += sizeof(DWORD);
  219. f->_cnt -= sizeof(DWORD);
  220. cbRec -= sizeof(DWORD);
  221. return lw;
  222. }
  223. lw = WGets(); /* Get low-order word */
  224. return(lw | ((DWORD) WGets() << 16));/* Return long word */
  225. }
  226. #endif
  227. #endif
  228. #if 0
  229. /****************************************************************
  230. * *
  231. * GetBytes: *
  232. * *
  233. * Read n bytes from input. *
  234. * If n is greater than SBLEN - 1, issue a fatal error. *
  235. * *
  236. ****************************************************************/
  237. void NEAR GetBytes(pb,n)
  238. BYTE *pb; /* Pointer to buffer */
  239. WORD n; /* Number of bytes to read in */
  240. {
  241. FILE *f = bsInput;
  242. if(n >= SBLEN)
  243. InvalidObject();
  244. if (n <= f->_cnt)
  245. {
  246. memcpy(pb,f->_ptr, n);
  247. f->_cnt -= n;
  248. f->_ptr += n;
  249. }
  250. else
  251. fread(pb,1,n,f); /* Ask for n bytes */
  252. cbRec -= n; /* Update byte count */
  253. }
  254. #endif
  255. #if 0
  256. /****************************************************************
  257. * *
  258. * SkipBytes: *
  259. * *
  260. * Skip n bytes of input. *
  261. * *
  262. ****************************************************************/
  263. void NEAR SkipBytes(n)
  264. REGISTER WORD n; /* Number of bytes to skip */
  265. {
  266. #if WIN_NT
  267. WORD cbRead;
  268. SBTYPE skipBuf;
  269. cbRec -= n; // Update byte count
  270. while (n) // While there are bytes to skip
  271. {
  272. cbRead = n < sizeof(SBTYPE) ? n : sizeof(SBTYPE);
  273. if (fread(skipBuf, 1, cbRead, bsInput) != cbRead)
  274. InvalidObject();
  275. n -= cbRead;
  276. }
  277. #else
  278. FILE *f = bsInput;
  279. if (f->_cnt >= n)
  280. {
  281. f->_cnt -= n;
  282. f->_ptr += n;
  283. }
  284. else if(fseek(f,(long) n,1))
  285. InvalidObject();
  286. cbRec -= n; /* Update byte count */
  287. #endif
  288. }
  289. #endif
  290. /****************************************************************
  291. * *
  292. * GetIndexHard: (GetIndex -- hard case) *
  293. * *
  294. * This function reads in a variable-length index field from *
  295. * the input file. It takes as its arguments two word values *
  296. * which represent the minimum and maximum allowable values *
  297. * the index. The function returns the value of the index. *
  298. * See p. 12 in "8086 Object Module Formats EPS." *
  299. * *
  300. ****************************************************************/
  301. WORD NEAR GetIndexHard(imin,imax)
  302. WORD imin; /* Minimum permissible value */
  303. WORD imax; /* Maximum permissible value */
  304. {
  305. REGISTER WORD index;
  306. FILE *f = bsInput;
  307. if (f->_cnt >= sizeof(WORD))
  308. {
  309. index = *(BYTE *)(f->_ptr);
  310. if (index & 0x80)
  311. {
  312. index <<= BYTELN;
  313. index |= *(BYTE *)(f->_ptr+1);
  314. index &= 0x7fff;
  315. f->_cnt -= sizeof(WORD);
  316. f->_ptr += sizeof(WORD);
  317. cbRec -= sizeof(WORD);
  318. }
  319. else
  320. {
  321. f->_cnt--;
  322. f->_ptr++;
  323. cbRec--;
  324. }
  325. }
  326. else
  327. {
  328. if((index = Gets()) & 0x80)
  329. index = ((index & 0x7f) << BYTELN) | Gets();
  330. }
  331. if(index < imin || index > imax) InvalidObject();
  332. return(index); /* Return a good value */
  333. }
  334. /********************************************************************
  335. * STRING ROUTINES *
  336. ********************************************************************/
  337. #if OSEGEXE
  338. #if NOASM
  339. /****************************************************************
  340. * *
  341. * zcheck: *
  342. * *
  343. * Determine length of initial nonzero stream in a buffer, and *
  344. * return the length. *
  345. * *
  346. ****************************************************************/
  347. #if defined(M_I386)
  348. #pragma auto_inline(off)
  349. #endif
  350. WORD zcheck(BYTE *pb, WORD cb)
  351. {
  352. // Loop down from end until a nonzero byte found.
  353. // Return length of remainder of buffer.
  354. #if defined(M_I386)
  355. _asm
  356. {
  357. push edi ; Save edi
  358. movzx ecx, cb ; Number of bytes to check
  359. push ds ; Copy ds into es
  360. pop es
  361. xor eax, eax ; Looking for zeros
  362. mov edi, pb ; Start of buffer
  363. add edi, ecx ; Just past the end of buffer
  364. dec edi ; Last byte in the buffer
  365. std ; Decrement pointer
  366. repz scasb ; Scan until non-zero byte found
  367. jz AllZeros ; Buffer truly empty
  368. inc ecx ; Fix count
  369. AllZeros:
  370. cld ; Clear flag just to be safe
  371. pop edi ; Restore edi
  372. mov eax, ecx ; Return count in eax
  373. }
  374. #endif
  375. for(pb = &pb[cb]; cb != 0; --cb)
  376. if(*--pb != '\0') break;
  377. return(cb);
  378. }
  379. #endif
  380. #endif /* OSEGEXE */
  381. #if defined(M_I386)
  382. #pragma auto_inline(on)
  383. #endif
  384. /*** CheckSegmentsMemory - check is all segments have allocated memory
  385. *
  386. * Purpose:
  387. * Check for not initialized segments. If the segment have a non-zero
  388. * size but no initialized data, then we have to allocate for it a
  389. * zero filled memory buffer. Normally 'MoveToVm' allocates memory
  390. * buffer for segments, but in this case there was no 'moves to VM'.
  391. *
  392. * Input:
  393. * No explicit value is passed.
  394. *
  395. * Output:
  396. * No explicit value is returned.
  397. *
  398. * Exceptions:
  399. * None.
  400. *
  401. * Notes:
  402. * None.
  403. *
  404. *************************************************************************/
  405. void CheckSegmentsMemory(void)
  406. {
  407. SEGTYPE seg;
  408. SATYPE sa;
  409. if (fNewExe)
  410. {
  411. for (sa = 1; sa < saMac; sa++)
  412. if (mpsaMem[sa] == NULL && mpsacb[sa] > 0)
  413. mpsaMem[sa] = (BYTE FAR *) GetMem(mpsacb[sa]);
  414. }
  415. else
  416. {
  417. for (seg = 1; seg <= segLast; seg++)
  418. if (mpsegMem[seg] == NULL && mpsegcb[seg] > 0)
  419. mpsegMem[seg] = (BYTE FAR *) GetMem(mpsegcb[seg] + mpsegraFirst[seg]);
  420. }
  421. }
  422. /*** WriteExe - write bytes to the executable file
  423. *
  424. * Purpose:
  425. * Write to the executable file and check for errors.
  426. *
  427. * Input:
  428. * pb - byte buffer to write
  429. * cb - buffer size in bytes
  430. *
  431. * Output:
  432. * No explicit value is returned.
  433. *
  434. * Exceptions:
  435. * I/O problems - fatal error and abort
  436. *
  437. * Notes:
  438. * None.
  439. *
  440. *************************************************************************/
  441. #if !defined( M_I386 ) && !defined( _WIN32 )
  442. #pragma check_stack(on)
  443. void WriteExe(void FAR *pb, unsigned cb)
  444. {
  445. BYTE localBuf[1024];
  446. WORD count;
  447. while (cb > 0)
  448. {
  449. count = (WORD) (cb <= sizeof(localBuf) ? cb : sizeof(localBuf));
  450. FMEMCPY((BYTE FAR *) localBuf, pb, count);
  451. if (fwrite((char *) localBuf, sizeof(BYTE), count, bsRunfile) != count)
  452. {
  453. ExitCode = 4;
  454. Fatal(ER_spcrun, strerror(errno));
  455. }
  456. cb -= count;
  457. ((BYTE FAR *) pb) += count;
  458. }
  459. }
  460. #pragma check_stack(off)
  461. #else
  462. /*** NoRoomForExe - the exe didn't fit
  463. *
  464. * Purpose:
  465. * emit error message
  466. * give fatal error and abort
  467. *
  468. * Input:
  469. * errno must be set
  470. *
  471. * Output:
  472. * No explicit value is returned.
  473. *
  474. * Notes:
  475. * None.
  476. *
  477. *************************************************************************/
  478. void NoRoomForExe()
  479. {
  480. ExitCode = 4;
  481. Fatal(ER_spcrun, strerror(errno));
  482. }
  483. #endif
  484. /*** WriteZeros - write zero bytes to the executable file
  485. *
  486. * Purpose:
  487. * Pad executable file with zero bytes.
  488. *
  489. * Input:
  490. * cb - number of bytes to write
  491. *
  492. * Output:
  493. * No explicit value is returned.
  494. *
  495. * Exceptions:
  496. * I/O problems - fatal error and abort
  497. *
  498. * Notes:
  499. * None.
  500. *
  501. *************************************************************************/
  502. void WriteZeros(unsigned cb)
  503. {
  504. BYTE buf[512];
  505. unsigned count;
  506. memset(buf, 0, sizeof(buf));
  507. while (cb > 0)
  508. {
  509. count = cb <= sizeof(buf) ? cb : sizeof(buf);
  510. WriteExe(buf, count);
  511. cb -= count;
  512. }
  513. }
  514. /****************************************************************
  515. * *
  516. * MoveToVm: *
  517. * *
  518. * Move a piece of data into a virtual memory area/va. *
  519. * *
  520. * Input: cb Count of bytes to be moved. *
  521. * obData Address of data to be moved. *
  522. * seg Logical segment to which data belongs. *
  523. * ra Offset at which data belongs. *
  524. * *
  525. ****************************************************************/
  526. #pragma intrinsic(memcpy)
  527. #if EXE386
  528. void MoveToVm(WORD cb, BYTE *obData, SEGTYPE seg, RATYPE ra)
  529. #else
  530. void NEAR MoveToVm(WORD cb, BYTE *obData, SEGTYPE seg, RATYPE ra)
  531. #endif
  532. {
  533. long cbtot; /* Count of bytes total */
  534. long cbSeg; /* Segment size */
  535. WORD fError;
  536. BYTE FAR *pMemImage;
  537. CVINFO FAR *pCVInfo;
  538. SATYPE sa;
  539. cbtot = (long) cb + ra;
  540. if (fDebSeg)
  541. {
  542. pCVInfo = ((APROPFILEPTR ) FetchSym(vrpropFile, FALSE))->af_cvInfo;
  543. if (pCVInfo)
  544. {
  545. if (seg < (SEGTYPE) (segDebFirst + ObjDebTotal))
  546. {
  547. cbSeg = pCVInfo->cv_cbTyp;
  548. pMemImage = pCVInfo->cv_typ;
  549. }
  550. else
  551. {
  552. cbSeg = pCVInfo->cv_cbSym;
  553. pMemImage = pCVInfo->cv_sym;
  554. }
  555. // Check against segment bounds
  556. fError = cbtot > cbSeg;
  557. }
  558. else
  559. {
  560. OutError(ER_badcvseg);
  561. return;
  562. }
  563. }
  564. else
  565. {
  566. if (fNewExe)
  567. {
  568. cbSeg = ((APROPSNPTR) FetchSym(mpgsnrprop[vgsnCur],FALSE))->as_cbMx;
  569. sa = mpsegsa[seg];
  570. if (mpsaMem[sa] == NULL)
  571. mpsaMem[sa] = (BYTE FAR *) GetMem(mpsacb[sa]);
  572. pMemImage = mpsaMem[sa];
  573. // Check against segment bounds
  574. fError = (long) ((ra - mpgsndra[vgsnCur]) + cb) > cbSeg;
  575. // If data is going up to or past current end of initialized data,
  576. // omit any trailing null bytes and reset mpsacbinit. Mpsacbinit
  577. // will usually go up but may go down if a common segment over-
  578. // writes previous end data with nulls.
  579. if ((DWORD) cbtot >= mpsacbinit[sa])
  580. {
  581. if ((DWORD) ra < mpsacbinit[sa] ||
  582. (cb = zcheck(obData,cb)) != 0)
  583. mpsacbinit[sa] = (long) ra + cb;
  584. }
  585. }
  586. else
  587. {
  588. cbSeg = mpsegcb[seg] + mpsegraFirst[seg];
  589. if (mpsegMem[seg] == NULL)
  590. mpsegMem[seg] = (BYTE FAR *) GetMem(cbSeg);
  591. pMemImage = mpsegMem[seg];
  592. // Check against segment bounds
  593. fError = cbtot > cbSeg;
  594. }
  595. }
  596. if (fError)
  597. {
  598. if (!fDebSeg)
  599. OutError(ER_segbnd, 1 + GetFarSb(GetHte(mpgsnrprop[vgsnCur])->cch));
  600. else
  601. OutError(ER_badcvseg);
  602. }
  603. else
  604. FMEMCPY(&pMemImage[ra], obData, cb);
  605. }
  606. #pragma function(memcpy)
  607. #if (OSEGEXE AND ODOS3EXE) OR EXE386
  608. /*
  609. * Map segment index to memory image address for new-format exes.
  610. */
  611. BYTE FAR * NEAR msaNew (SEGTYPE seg)
  612. {
  613. return(mpsaMem[mpsegsa[seg]]);
  614. }
  615. #endif
  616. #if (OSEGEXE AND ODOS3EXE) OR EXE386
  617. /*
  618. * Map segment index to memory image address for DOS3 or 286Xenix exes.
  619. */
  620. BYTE FAR * NEAR msaOld (SEGTYPE seg)
  621. {
  622. return(mpsegMem[seg]);
  623. }
  624. #endif
  625. #if EXE386
  626. /*
  627. * Map segment index to VM area address for 386 exes.
  628. */
  629. long NEAR msa386 (seg)
  630. SEGTYPE seg;
  631. {
  632. register long *p; /* Pointer to mpsegcb */
  633. register long *pEnd; /* Pointer to end of mpsegcb */
  634. register long va = AREAFSG; /* Current VM address */
  635. /*
  636. * Segment number-to-VM area mapping is different for 386 segments
  637. * because their size limit is so big that allocating a fixed amount
  638. * for each segment is impractical, especially when sdb support is
  639. * enabled. So segments are allocated contiguously. Each segment
  640. * is padded to a VM page boundary for efficiency.
  641. *
  642. * Implementation: the fastest way would be to allocate a segment
  643. * based table of virtual addresses, but this would take more code
  644. * and memory. Counting segment sizes is slower but this is not
  645. * time-critical routine, and in most cases there will be very few
  646. * segments.
  647. */
  648. if (fNewExe)
  649. {
  650. p = &mpsacb[1];
  651. pEnd = &mpsacb[seg];
  652. }
  653. #if ODOS3EXE
  654. else
  655. {
  656. p = &mpsegcb[1];
  657. pEnd = &mpsegcb[seg];
  658. }
  659. #endif
  660. for( ; p < pEnd; ++p)
  661. va += (*p + (PAGLEN - 1)) & ~(PAGLEN - 1);
  662. return(va);
  663. }
  664. #endif /* EXE386 */
  665. /********************************************************************
  666. * (ERROR) MESSAGE ROUTINES *
  667. ********************************************************************/
  668. #pragma auto_inline(off)
  669. /*
  670. * SysFatal : system-level error
  671. *
  672. * Issue error message and exit with return code 4.
  673. */
  674. void cdecl SysFatal (MSGTYPE msg)
  675. {
  676. ExitCode = 4;
  677. Fatal(msg);
  678. }
  679. void NEAR InvalidObject(void)
  680. {
  681. Fatal((MSGTYPE)(fDrivePass ? ER_badobj: ER_eofobj));
  682. }
  683. #pragma auto_inline(on)
  684. /********************************************************************
  685. * MISCELLANEOUS ROUTINES *
  686. ********************************************************************/
  687. /*
  688. * Output a word integer.
  689. */
  690. void OutWord(x)
  691. WORD x; /* A word integer */
  692. {
  693. WriteExe(&x, CBWORD);
  694. }
  695. /*
  696. * GetLocName : read in a symbol name for L*DEF
  697. *
  698. * Transform the name by prefixing a space followed by the
  699. * module number. Update the length byte.
  700. *
  701. * Parameters: pointer to a string buffer, 1st byte already
  702. * contains length
  703. * Returns: nothing
  704. */
  705. void NEAR GetLocName (psb)
  706. BYTE *psb; /* Name buffer */
  707. {
  708. WORD n;
  709. BYTE *p;
  710. p = &psb[1]; /* Start after length byte */
  711. *p++ = 0x20; /* Prefix begins with space char */
  712. GetBytes(p,B2W(psb[0])); /* Read in text of symbol */
  713. p += B2W(psb[0]); /* Go to end of string */
  714. *p++ = 0x20;
  715. n = modkey; /* Initialize */
  716. /* Convert the module key to ASCII and store backwards */
  717. do
  718. {
  719. *p++ = (BYTE) ((n % 10) + '0');
  720. n /= 10;
  721. } while(n);
  722. psb[0] = (BYTE) ((p - (psb + 1))); /* Update length byte */
  723. }
  724. PROPTYPE EnterName(psym,attr,fCreate)
  725. BYTE *psym; /* Pointer to length-prefixed string */
  726. ATTRTYPE attr; /* Attribute to look up */
  727. WORD fCreate; /* Create prop cell if not found */
  728. {
  729. return(PropSymLookup(psym, attr, fCreate));
  730. /* Hide call to near function */
  731. }
  732. #if CMDMSDOS
  733. #pragma check_stack(on)
  734. /*** ValidateRunFileName - Check if output file has proper extension
  735. *
  736. * Purpose:
  737. * Check user-specified output file name for valid extension.
  738. * Issue warning if extension is invalid and create new file
  739. * name with proper extension.
  740. *
  741. * Input:
  742. * ValidExtension - pointer to length prefixed ascii string
  743. * representing valid exetension for output
  744. * file name.
  745. * ForceExtension - TRUE if output file must have new extension,
  746. * otherwise user responce takes precedence.
  747. * WarnUser - If TRUE than display L4045 if file name changed.
  748. *
  749. * Output:
  750. * rhteRunfile - global virtual pointer to output file
  751. * name, changed only if new output name
  752. * is created because of invalid original
  753. * extension.
  754. * warning L4045 - if output file name have to be changed.
  755. *
  756. *************************************************************************/
  757. void NEAR ValidateRunFileName(BYTE *ValidExtension,
  758. WORD ForceExtension,
  759. WORD WarnUser)
  760. {
  761. SBTYPE sb; /* String buffer */
  762. BYTE *psbRunfile; /* Name of runfile */
  763. char oldDrive[_MAX_DRIVE];
  764. char oldDir[_MAX_DIR];
  765. char oldName[_MAX_FNAME];
  766. char oldExt[_MAX_EXT];
  767. /* Get the name of the runfile and check if it has user supplied extension */
  768. psbRunfile = GetFarSb(((AHTEPTR) FetchSym(rhteRunfile,FALSE))->cch);
  769. _splitpath(psbRunfile, oldDrive, oldDir, oldName, oldExt);
  770. /* Force extension only when no user defined extension */
  771. if (ForceExtension && oldExt[0] == NULL)
  772. {
  773. memcpy(sb, ValidExtension, strlen(ValidExtension));
  774. memcpy(bufg, psbRunfile, 1 + B2W(*psbRunfile));
  775. }
  776. else
  777. {
  778. memcpy(bufg, ValidExtension, strlen(ValidExtension));
  779. memcpy(sb, psbRunfile, 1 + B2W(*psbRunfile));
  780. }
  781. UpdateFileParts(bufg, sb);
  782. /* If the name has changed, issue a warning and update rhteRunfile. */
  783. if (!SbCompare(bufg, psbRunfile, (FTYPE) TRUE))
  784. {
  785. if (WarnUser && !SbCompare(ValidExtension, sbDotExe, (FTYPE) TRUE))
  786. OutWarn(ER_outputname,bufg + 1);
  787. PropSymLookup(bufg, ATTRNIL, TRUE);
  788. rhteRunfile = vrhte;
  789. }
  790. }
  791. #pragma check_stack(off)
  792. #endif
  793. /********************************************************************
  794. * PORTABILITY ROUTINES *
  795. ********************************************************************/
  796. #if M_BYTESWAP
  797. WORD getword(cp) /* Get a word given a pointer */
  798. REGISTER char *cp; /* Pointer */
  799. {
  800. return(B2W(cp[0]) + (B2W(cp[1]) << BYTELN));
  801. /* Return 8086-style word */
  802. }
  803. DWORD getdword(cp)/* Get a double word given a pointer */
  804. REGISTER char *cp; /* Pointer */
  805. {
  806. return(getword(cp) + (getword(cp+2) << WORDLN));
  807. /* Return 8086-style double word */
  808. }
  809. #endif
  810. #if NOT M_WORDSWAP OR M_BYTESWAP
  811. /*
  812. * Portable structure I/O routines
  813. */
  814. #define cget(f) fgetc(f)
  815. static int bswap; /* Byte-swapped mode (1 on; 0 off) */
  816. static int wswap; /* Word-swapped mode (1 on; 0 off) */
  817. static cput(c,f)
  818. char c;
  819. FILE *f;
  820. {
  821. #if FALSE AND OEXE
  822. CheckSum(1, &c);
  823. #endif
  824. fputc(c, f);
  825. }
  826. static pshort(s,f)
  827. REGISTER short s;
  828. REGISTER FILE *f;
  829. {
  830. cput(s & 0xFF,f); /* Low byte */
  831. cput(s >> 8,f); /* High byte */
  832. }
  833. static unsigned short gshort(f)
  834. REGISTER FILE *f;
  835. {
  836. REGISTER short s;
  837. s = cget(f); /* Get low byte */
  838. return(s + (cget(f) << 8)); /* Get high byte */
  839. }
  840. static pbshort(s,f)
  841. REGISTER short s;
  842. REGISTER FILE *f;
  843. {
  844. cput(s >> 8,f); /* High byte */
  845. cput(s & 0xFF,f); /* Low byte */
  846. }
  847. static unsigned short gbshort(f)
  848. REGISTER FILE *f;
  849. {
  850. REGISTER short s;
  851. s = cget(f) << 8; /* Get high byte */
  852. return(s + cget(f)); /* Get low byte */
  853. }
  854. static int (*fpstab[2])() =
  855. {
  856. pshort,
  857. pbshort
  858. };
  859. static unsigned short (*fgstab[2])() =
  860. {
  861. gshort,
  862. gbshort
  863. };
  864. static plong(l,f)
  865. long l;
  866. REGISTER FILE *f;
  867. {
  868. (*fpstab[bswap])((short)(l >> 16),f);
  869. /* High word */
  870. (*fpstab[bswap])((short) l,f); /* Low word */
  871. }
  872. static long glong(f)
  873. REGISTER FILE *f;
  874. {
  875. long l;
  876. l = (long) (*fgstab[bswap])(f) << 16;
  877. /* Get high word */
  878. return(l + (unsigned) (*fgstab[bswap])(f));
  879. /* Get low word */
  880. }
  881. static pwlong(l,f)
  882. long l;
  883. REGISTER FILE *f;
  884. {
  885. (*fpstab[bswap])((short) l,f); /* Low word */
  886. (*fpstab[bswap])((short)(l >> 16),f);
  887. /* High word */
  888. }
  889. static long gwlong(f)
  890. REGISTER FILE *f;
  891. {
  892. long l;
  893. l = (unsigned) (*fgstab[bswap])(f); /* Get low word */
  894. return(l + ((long) (*fgstab[bswap])(f) << 16));
  895. /* Get high word */
  896. }
  897. static int (*fpltab[2])() =
  898. {
  899. plong,
  900. pwlong
  901. };
  902. static long (*fgltab[2])() =
  903. {
  904. glong,
  905. gwlong
  906. };
  907. /*
  908. * int swrite(cp,dopevec,count,file)
  909. * char *cp;
  910. * char *dopevec;
  911. * int count;
  912. * FILE *file;
  913. *
  914. * Returns number of bytes written.
  915. *
  916. * Dopevec is a character string with the
  917. * following format:
  918. *
  919. * "[b][w][p]{[<cnt>]<type>}"
  920. *
  921. * where [...] denotes an optional part, {...} denotes a part
  922. * that may be repeated zero or more times, and <...> denotes
  923. * a description of a part.
  924. *
  925. * b bytes are "swapped" (not in PDP-11 order)
  926. * w words are swapped
  927. * p struct is "packed" (no padding for alignment)
  928. * <cnt> count of times to repeat following type
  929. * <type> one of the following:
  930. * c char
  931. * s short
  932. * l long
  933. *
  934. * Example: given the struct
  935. *
  936. * struct
  937. * {
  938. * short x;
  939. * short y;
  940. * char z[16];
  941. * long w;
  942. * };
  943. *
  944. * and assuming it is to be written so as to use VAX byte- and
  945. * word-ordering, its dope vector would be:
  946. *
  947. * "wss16cl"
  948. */
  949. int swrite(cp,dopevec,count,file)
  950. char *cp; /* Pointer to struct array */
  951. char *dopevec; /* Dope vector for struct */
  952. int count; /* Number of structs in array */
  953. FILE *file; /* File to write to */
  954. {
  955. int pack; /* Packed flag */
  956. int rpt; /* Repeat count */
  957. REGISTER int cc = 0; /* Count of characters written */
  958. REGISTER char *dv; /* Dope vector less flags */
  959. short *sp; /* Pointer to short */
  960. long *lp; /* Pointer to long */
  961. bswap = wswap = pack = 0; /* Initialize flags */
  962. while(*dopevec != '\0') /* Loop to set flags */
  963. {
  964. if(*dopevec == 'b') bswap = 1; /* Check for byte-swapped flag */
  965. else if(*dopevec == 'p') pack = 1;
  966. /* Check for packed flag */
  967. else if(*dopevec == 'w') wswap = 1;
  968. /* Check for word-swapped flag */
  969. else break;
  970. ++dopevec;
  971. }
  972. while(count-- > 0) /* Main loop */
  973. {
  974. dv = dopevec; /* Initialize */
  975. for(;;) /* Loop to write struct */
  976. {
  977. if(*dv >= '0' && *dv <= '9')
  978. { /* If there is a repeat count */
  979. rpt = 0; /* Initialize */
  980. do /* Loop to get repeat count */
  981. {
  982. rpt = rpt*10 + *dv++ - '0';
  983. /* Take digit */
  984. }
  985. while(*dv >= '0' && *dv <= '9');
  986. /* Loop until non-digit found */
  987. }
  988. else rpt = 1; /* Else repeat count defaults to one */
  989. if(*dv == '\0') break; /* break if end of dope vector */
  990. switch(*dv++) /* Switch on type character */
  991. {
  992. case 'c': /* Character */
  993. #if FALSE AND OEXE
  994. CheckSum(rpt, cp);
  995. #endif
  996. if(fwrite(cp,sizeof(char),rpt,file) != rpt) return(cc);
  997. /* Write the characters */
  998. cp += rpt; /* Increment pointer */
  999. cc += rpt; /* Increment count of bytes written */
  1000. break;
  1001. case 's': /* Short */
  1002. if(!pack && (cc & 1)) /* If not packed and misaligned */
  1003. {
  1004. cput(*cp++,file); /* Write padding byte */
  1005. ++cc; /* Increment byte count */
  1006. }
  1007. sp = (short *) cp; /* Initialize pointer */
  1008. while(rpt-- > 0) /* Loop to write shorts */
  1009. {
  1010. (*fpstab[bswap])(*sp++,file);
  1011. /* Write the short */
  1012. if(feof(file) || ferror(file)) return(cc);
  1013. /* Check for errors */
  1014. cc += sizeof(short);
  1015. /* Increment byte count */
  1016. }
  1017. cp = (char *) sp; /* Update pointer */
  1018. break;
  1019. case 'l': /* Long */
  1020. if(!pack && (cc & 3)) /* If not packed and misaligned */
  1021. {
  1022. while(cc & 3) /* While not aligned */
  1023. {
  1024. cput(*cp++,file);
  1025. /* Write padding byte */
  1026. ++cc; /* Increment byte count */
  1027. }
  1028. }
  1029. lp = (long *) cp; /* Initialize pointer */
  1030. while(rpt-- > 0) /* Loop to write longs */
  1031. {
  1032. (*fpltab[wswap])(*lp++,file);
  1033. /* Write the long */
  1034. if(feof(file) || ferror(file)) return(cc);
  1035. /* Check for errors */
  1036. cc += sizeof(long);
  1037. /* Increment byte count */
  1038. }
  1039. cp = (char *) lp; /* Update pointer */
  1040. break;
  1041. }
  1042. }
  1043. }
  1044. return(cc); /* Return count of bytes written */
  1045. }
  1046. /*
  1047. * int sread(cp,dopevec,count,file)
  1048. * char *cp;
  1049. * char *dopevec;
  1050. * int count;
  1051. * FILE *file;
  1052. *
  1053. * Returns number of bytes read.
  1054. *
  1055. * Dopevec is a character string whose format is described
  1056. * with swrite() above.
  1057. */
  1058. int sread(cp,dopevec,count,file)
  1059. char *cp; /* Pointer to struct array */
  1060. char *dopevec; /* Dope vector for struct */
  1061. int count; /* Number of structs in array */
  1062. FILE *file; /* File to read from */
  1063. {
  1064. int pack; /* Packed flag */
  1065. int rpt; /* Repeat count */
  1066. REGISTER int cc = 0; /* Count of characters written */
  1067. REGISTER char *dv; /* Dope vector less flags */
  1068. short *sp; /* Pointer to short */
  1069. long *lp; /* Pointer to long */
  1070. bswap = wswap = pack = 0; /* Initialize flags */
  1071. while(*dopevec != '\0') /* Loop to set flags */
  1072. {
  1073. if(*dopevec == 'b') bswap = 1; /* Check for byte-swapped flag */
  1074. else if(*dopevec == 'p') pack = 1;
  1075. /* Check for packed flag */
  1076. else if(*dopevec == 'w') wswap = 1;
  1077. /* Check for word-swapped flag */
  1078. else break;
  1079. ++dopevec;
  1080. }
  1081. while(count-- > 0) /* Main loop */
  1082. {
  1083. dv = dopevec; /* Initialize */
  1084. for(;;) /* Loop to write struct */
  1085. {
  1086. if(*dv >= '0' && *dv <= '9')
  1087. { /* If there is a repeat count */
  1088. rpt = 0; /* Initialize */
  1089. do /* Loop to get repeat count */
  1090. {
  1091. rpt = rpt*10 + *dv++ - '0';
  1092. /* Take digit */
  1093. }
  1094. while(*dv >= '0' && *dv <= '9');
  1095. /* Loop until non-digit found */
  1096. }
  1097. else rpt = 1; /* Else repeat count defaults to one */
  1098. if(*dv == '\0') break; /* break if end of dope vector */
  1099. switch(*dv++) /* Switch on type character */
  1100. {
  1101. case 'c': /* Character */
  1102. if(fread(cp,sizeof(char),rpt,file) != rpt) return(cc);
  1103. /* Read the characters */
  1104. cp += rpt; /* Increment pointer */
  1105. cc += rpt; /* Increment count of bytes written */
  1106. break;
  1107. case 's': /* Short */
  1108. if(!pack && (cc & 1)) /* If not packed and misaligned */
  1109. {
  1110. *cp ++ = cget(file);
  1111. /* Read padding byte */
  1112. ++cc; /* Increment byte count */
  1113. }
  1114. sp = (short *) cp; /* Initialize pointer */
  1115. while(rpt-- > 0) /* Loop to read shorts */
  1116. {
  1117. *sp++ = (*fgstab[bswap])(file);
  1118. /* Read the short */
  1119. if(feof(file) || ferror(file)) return(cc);
  1120. /* Check for errors */
  1121. cc += sizeof(short);
  1122. /* Increment byte count */
  1123. }
  1124. cp = (char *) sp; /* Update pointer */
  1125. break;
  1126. case 'l': /* Long */
  1127. if(!pack && (cc & 3)) /* If not packed and misaligned */
  1128. {
  1129. while(cc & 3) /* While not aligned */
  1130. {
  1131. *cp++ = cget(file);
  1132. /* Read padding byte */
  1133. ++cc; /* Increment byte count */
  1134. }
  1135. }
  1136. lp = (long *) cp; /* Initialize pointer */
  1137. while(rpt-- > 0) /* Loop to read longs */
  1138. {
  1139. *lp++ = (*fgltab[wswap])(file);
  1140. /* Read the long */
  1141. if(feof(file) || ferror(file)) return(cc);
  1142. /* Check for errors */
  1143. cc += sizeof(long);
  1144. /* Increment byte count */
  1145. }
  1146. cp = (char *) lp; /* Update pointer */
  1147. break;
  1148. }
  1149. }
  1150. }
  1151. return(cc); /* Return count of bytes written */
  1152. }
  1153. #endif
  1154. #define CB_POOL 4096
  1155. typedef struct _POOLBLK
  1156. {
  1157. struct _POOLBLK * pblkNext; // next pool in list
  1158. int cb; // number of bytes in this pool (free+alloc)
  1159. char rgb[1]; // data for this pool (variable sized)
  1160. } POOLBLK;
  1161. typedef struct _POOL
  1162. {
  1163. struct _POOLBLK * pblkHead; // start of poolblk list
  1164. struct _POOLBLK * pblkCur; // current poolblk we are searching
  1165. int cb; // # bytes free in current pool
  1166. char * pch; // pointer to free data in current pool
  1167. } POOL;
  1168. void *
  1169. PInit()
  1170. {
  1171. POOL *ppool;
  1172. // create new pool, set size and allocate CB_POOL bytes
  1173. ppool = (POOL *)GetMem(sizeof(POOL));
  1174. ppool->pblkHead = (POOLBLK *)GetMem(sizeof(POOLBLK) + CB_POOL-1);
  1175. ppool->pblkHead->cb = CB_POOL;
  1176. ppool->pblkHead->pblkNext = NULL;
  1177. ppool->cb = CB_POOL;
  1178. ppool->pch = &ppool->pblkHead->rgb[0];
  1179. ppool->pblkCur = ppool->pblkHead;
  1180. return (void *)ppool;
  1181. }
  1182. void *
  1183. PAlloc(void *pp, int cb)
  1184. {
  1185. POOL *ppool = (POOL *)pp;
  1186. void *pchRet;
  1187. POOLBLK *pblkCur, *pblkNext;
  1188. // if the allocation doesn't fit in the current block
  1189. if (cb > ppool->cb)
  1190. {
  1191. pblkCur = ppool->pblkCur;
  1192. pblkNext = pblkCur->pblkNext;
  1193. // then check the next block
  1194. if (pblkNext && pblkNext->cb >= cb)
  1195. {
  1196. // set the master info to reflect the next page...
  1197. ppool->pblkCur = pblkNext;
  1198. ppool->cb = pblkNext->cb;
  1199. ppool->pch = &pblkNext->rgb[0];
  1200. memset(ppool->pch, 0, ppool->cb);
  1201. }
  1202. else
  1203. {
  1204. POOLBLK *pblkNew; // new pool
  1205. // allocate new memory -- at least enough for this allocation
  1206. pblkNew = (POOLBLK *)GetMem(sizeof(POOLBLK)+cb+CB_POOL-1);
  1207. pblkNew->cb = CB_POOL + cb;
  1208. // link the current page to the new page
  1209. pblkNew->pblkNext = pblkNext;
  1210. pblkCur->pblkNext = pblkNew;
  1211. // set the master info to reflect the new page...
  1212. ppool->pblkCur = pblkNew;
  1213. ppool->cb = CB_POOL + cb;
  1214. ppool->pch = &pblkNew->rgb[0];
  1215. }
  1216. }
  1217. pchRet = (void *)ppool->pch;
  1218. ppool->pch += cb;
  1219. ppool->cb -= cb;
  1220. return pchRet;
  1221. }
  1222. void
  1223. PFree(void *pp)
  1224. {
  1225. POOL *ppool = (POOL *)pp;
  1226. POOLBLK *pblk = ppool->pblkHead;
  1227. POOLBLK *pblkNext;
  1228. while (pblk)
  1229. {
  1230. pblkNext = pblk->pblkNext;
  1231. FFREE(pblk);
  1232. pblk = pblkNext;
  1233. }
  1234. FFREE(ppool);
  1235. }
  1236. void
  1237. PReinit(void *pp)
  1238. {
  1239. POOL *ppool = (POOL *)pp;
  1240. ppool->pblkCur = ppool->pblkHead;
  1241. ppool->cb = ppool->pblkHead->cb;
  1242. ppool->pch = &ppool->pblkHead->rgb[0];
  1243. memset(ppool->pch, 0, ppool->cb);
  1244. }
  1245. #if RGMI_IN_PLACE
  1246. /****************************************************************
  1247. * *
  1248. * PchSegAddress: *
  1249. * *
  1250. * compute the address that will hold this data so we can read *
  1251. * it in place... we make sure that we can read in place at *
  1252. * and give errors as in MoveToVm if we cannot *
  1253. * *
  1254. * Input: cb Count of bytes to be moved. *
  1255. * seg Logical segment to which data belongs. *
  1256. * ra Offset at which data belongs. *
  1257. * *
  1258. ****************************************************************/
  1259. BYTE FAR * PchSegAddress(WORD cb, SEGTYPE seg, RATYPE ra)
  1260. {
  1261. long cbtot; /* Count of bytes total */
  1262. long cbSeg; /* Segment size */
  1263. WORD fError;
  1264. BYTE FAR *pMemImage;
  1265. CVINFO FAR *pCVInfo;
  1266. SATYPE sa;
  1267. cbtot = (long) cb + ra;
  1268. if (fDebSeg)
  1269. {
  1270. pCVInfo = ((APROPFILEPTR ) FetchSym(vrpropFile, FALSE))->af_cvInfo;
  1271. if (pCVInfo)
  1272. {
  1273. if (seg < (SEGTYPE) (segDebFirst + ObjDebTotal))
  1274. {
  1275. cbSeg = pCVInfo->cv_cbTyp;
  1276. pMemImage = pCVInfo->cv_typ;
  1277. if (!pMemImage)
  1278. pCVInfo->cv_typ = pMemImage = GetMem(cbSeg);
  1279. }
  1280. else
  1281. {
  1282. cbSeg = pCVInfo->cv_cbSym;
  1283. pMemImage = pCVInfo->cv_sym;
  1284. if (!pMemImage)
  1285. pCVInfo->cv_sym = pMemImage = GetMem(cbSeg);
  1286. }
  1287. // Check against segment bounds
  1288. fError = cbtot > cbSeg;
  1289. }
  1290. else
  1291. {
  1292. OutError(ER_badcvseg);
  1293. return NULL;
  1294. }
  1295. }
  1296. else
  1297. {
  1298. if (fNewExe)
  1299. {
  1300. cbSeg = ((APROPSNPTR) FetchSym(mpgsnrprop[vgsnCur],FALSE))->as_cbMx;
  1301. sa = mpsegsa[seg];
  1302. if (mpsaMem[sa] == NULL)
  1303. mpsaMem[sa] = (BYTE FAR *) GetMem(mpsacb[sa]);
  1304. pMemImage = mpsaMem[sa];
  1305. // Check against segment bounds
  1306. fError = (long) ((ra - mpgsndra[vgsnCur]) + cb) > cbSeg;
  1307. }
  1308. else
  1309. {
  1310. cbSeg = mpsegcb[seg] + mpsegraFirst[seg];
  1311. if (mpsegMem[seg] == NULL)
  1312. mpsegMem[seg] = (BYTE FAR *) GetMem(cbSeg);
  1313. pMemImage = mpsegMem[seg];
  1314. // Check against segment bounds
  1315. fError = cbtot > cbSeg;
  1316. }
  1317. }
  1318. if (fError)
  1319. {
  1320. if (!fDebSeg)
  1321. OutError(ER_segbnd, 1 + GetFarSb(GetHte(mpgsnrprop[vgsnCur])->cch));
  1322. else
  1323. OutError(ER_badcvseg);
  1324. }
  1325. return (pMemImage + ra);
  1326. }
  1327. #endif
  1328. #if USE_REAL
  1329. // Indicates if you are running under TNT.
  1330. // If it returns FALSE today, you are running on NT.
  1331. int IsDosxnt ( ) {
  1332. #if defined( _WIN32 )
  1333. return FALSE;
  1334. #else
  1335. HINSTANCE hLib = GetModuleHandle("kernel32.dll");
  1336. if ( hLib != 0 && (GetProcAddress(hLib, "IsTNT") != 0)) {
  1337. return(TRUE);
  1338. }
  1339. else {
  1340. return(FALSE);
  1341. }
  1342. #endif
  1343. }
  1344. // Are we running on Win31 or greater.
  1345. // Note that we know if we are running under Windows we are running in enhanced mode.
  1346. int IsWin31() {
  1347. #if defined( _WIN32 )
  1348. return FALSE;
  1349. #else
  1350. __asm {
  1351. mov ax,1600h ; Is Win31 or greater running
  1352. int 2fh
  1353. cmp al,03h ; Is major version number 3.0
  1354. jb NotWin31 ; Major version less than 3.0
  1355. ja ItIsWin31
  1356. cmp ah,0ah ; Is minor version atleast .10
  1357. jb NotWin31 ; Must be Win3.0
  1358. }
  1359. ItIsWin31:
  1360. return (TRUE);
  1361. NotWin31:
  1362. return (FALSE);
  1363. #endif // NOT _WIN32
  1364. }
  1365. int MakeConvMemPageable ( )
  1366. {
  1367. #if defined( _WIN32 )
  1368. return TRUE;
  1369. #else
  1370. if ( realModeMemPageable ) {
  1371. return ( TRUE ); // Somebody already freed the real mode mem.
  1372. }
  1373. __asm {
  1374. mov ax,0100h ; function to get DOS memory.
  1375. mov bx,TOTAL_CONV_MEM ; Ask for 1 M to get max memory count
  1376. int 31h
  1377. jnc errOut ; allocated 1 M - something must be wrong.
  1378. cmp ax,08h ; Did we fail because of not enough memory
  1379. jne errOut ; No we failed because of some other reason.
  1380. cmp bx,MIN_CONV_MEM ; See if we can allocate atleast the min
  1381. // We could fail for two reasons here .
  1382. // 1) we really didn't have sufficient memory.
  1383. // 2) Some TNT app that spawned us already unlocked this memory. For ex:
  1384. // cl might have already freed up the memory when it calls link.exe.
  1385. jb errOut ; Too little mem available don't bother.
  1386. sub bx,CONV_MEM_FOR_TNT ; Leave real mode mem for TNT.
  1387. mov ax,0100h ; Try again with new amount of memory
  1388. int 31h ; Ask for the real mode memory from DPMI.
  1389. jc errOut ; didn't succeed again, give up.
  1390. mov convMemSelector,dx ; Save the value of the selector for allocated block
  1391. mov noOfParagraphs,bx ; amount of memory we were able to allocate.
  1392. mov ax,0006h ; function to get base addr of a selector
  1393. mov bx,dx ; move the selector to bx
  1394. int 31h ; Get Segment Base Address
  1395. jc errOut ;
  1396. mov bx,cx ; mov lin addr from cx:dx to bx:cx
  1397. mov cx,dx ;
  1398. movzx eax,noOfParagraphs
  1399. shl eax,4 ; Multiply by 16 to get count in bytes.
  1400. mov di,ax ; transfer size to si:di from eax
  1401. shr eax,16 ;
  1402. mov si,ax ;
  1403. mov ax,602h ; Make real mode memory pageable
  1404. int 31h
  1405. jc errOut ; Didn't work.
  1406. mov ax,703h ; Indicate data in these pages is discardable.
  1407. int 31h
  1408. // Even if we fail this call, we will still assume we are succesful,
  1409. // because it is just a performance enhancement
  1410. // Also for correctness we should relock the memory once it is free.
  1411. }
  1412. realModeMemPageable = TRUE ;
  1413. errOut:
  1414. return(realModeMemPageable);
  1415. #endif // NOT _WIN32
  1416. }
  1417. /* Relock the real mode memory now */
  1418. int RelockConvMem ( void )
  1419. {
  1420. #if defined( _WIN32 )
  1421. return TRUE;
  1422. #else
  1423. if ( !realModeMemPageable ) {
  1424. return ( TRUE ); // We were never able to free the mem anyway.
  1425. }
  1426. __asm {
  1427. mov bx, convMemSelector
  1428. mov ax, 0006h
  1429. int 31h ; Get Segment Base Address.
  1430. jc errOut ;
  1431. mov bx,cx ; Mov lin addr from cx:dx to bx:cx
  1432. mov cx,dx
  1433. movzx eax,noOfParagraphs
  1434. shl eax,4 ; Mul paragraphs by 16 to get count in bytes.
  1435. mov di,ax ;Transfer size to si:di from eax.
  1436. shr eax,16
  1437. mov si,ax
  1438. mov ax,603h ; Relock real mode region
  1439. int 31h
  1440. jc errOut
  1441. mov dx,convMemSelector
  1442. mov ax,101h ; Free the real mode memory
  1443. int 31h
  1444. jc errOut
  1445. }
  1446. realModeMemPageable = FALSE ;
  1447. return ( TRUE );
  1448. errOut:
  1449. return ( FALSE );
  1450. #endif // NOT _WIN32
  1451. }
  1452. void RealMemExit(void)
  1453. {
  1454. if(fUseReal)
  1455. {
  1456. if(!RelockConvMem())
  1457. OutError(ER_membad);
  1458. fUseReal = FALSE;
  1459. }
  1460. }
  1461. #endif