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.

769 lines
30 KiB

  1. /*
  2. * Copyright Microsoft Corporation, 1983-1989
  3. *
  4. * This Module contains Proprietary Information of Microsoft
  5. * Corporation and should be treated as Confidential.
  6. */
  7. /*
  8. * Segmented-Executable Format Output Module
  9. *
  10. * Modifications:
  11. *
  12. * 23-Feb-1989 RB Fix stack allocation when DGROUP is only stack.
  13. */
  14. #include <minlit.h> /* Types and constants */
  15. #include <bndtrn.h> /* Types and constants */
  16. #include <bndrel.h> /* Relocation definitions */
  17. #include <lnkio.h> /* Linker I/O definitions */
  18. #include <newexe.h> /* New .EXE header definitions */
  19. #include <lnkmsg.h> /* Error messages */
  20. #include <extern.h> /* External declarations */
  21. #include <impexp.h>
  22. #if NOT (WIN_NT OR DOSEXTENDER OR DOSX32) AND NOT WIN_3
  23. #define INCL_BASE
  24. #include <os2.h>
  25. #include <basemid.h>
  26. #if defined(M_I86LM)
  27. #undef NEAR
  28. #define NEAR
  29. #endif
  30. #endif
  31. #define CBSTUBSTK 0x80 /* # bytes in stack of default stub */
  32. extern unsigned char LINKREV; /* Release number */
  33. extern unsigned char LINKVER; /* Version number */
  34. LOCAL long cbOldExe; /* Size of image of old .EXE file */
  35. /*
  36. * LOCAL FUNCTION PROTOTYPES
  37. */
  38. LOCAL void NEAR CopyBytes(long cb);
  39. LOCAL void NEAR OutSegTable(unsigned short *mpsasec);
  40. LOCAL long NEAR PutName(long lfaimage, struct exe_hdr *hdr);
  41. #define NAMESIZE 9 /* size of signature array */
  42. void NEAR PadToPage(align)
  43. WORD align; /* Alignment factor */
  44. {
  45. REGISTER WORD cb; /* Number of bytes to write */
  46. align = 1 << align; /* Calculate page size */
  47. cb = align - ((WORD) ftell(bsRunfile) & (align - 1));
  48. /* Calculate needed padding */
  49. if (cb != align) /* If padding needed */
  50. WriteZeros(cb);
  51. }
  52. long NEAR MakeHole(cb)
  53. long cb;
  54. {
  55. long lfaStart; /* Starting file address */
  56. lfaStart = ftell(bsRunfile); /* Save starting address */
  57. #if OSXENIX
  58. fseek(bsRunfile,cb,1); /* Leave a hole */
  59. #else
  60. WriteZeros(cb);
  61. #endif
  62. return(lfaStart); /* Return starting file address */
  63. }
  64. LOCAL void NEAR CopyBytes(cb) /* Copy from bsInput to bsRunfile */
  65. long cb; /* Number of bytes to copy */
  66. {
  67. BYTE buffer[PAGLEN]; /* Buffer */
  68. #if FALSE
  69. raChksum = (WORD) ftell(bsRunfile); /* Determine checksum relative offset */
  70. #endif
  71. while(cb >= (long) PAGLEN) /* While full buffers remain */
  72. {
  73. if (fread(buffer,sizeof(BYTE),PAGLEN,bsInput) != PAGLEN)
  74. Fatal(ER_badobj);
  75. /* Read */
  76. WriteExe(buffer, PAGLEN); /* Write */
  77. cb -= (long) PAGLEN; /* Decrement count of bytes */
  78. }
  79. if(cb != 0L) /* If bytes remain */
  80. {
  81. if (fread(buffer,sizeof(BYTE),(WORD) cb,bsInput) != cb)
  82. Fatal(ER_badobj);
  83. /* Read */
  84. WriteExe(buffer, (WORD) cb); /* Write */
  85. }
  86. }
  87. #pragma check_stack(on)
  88. BSTYPE LinkOpenExe(sbExe)
  89. BYTE *sbExe; /* .EXE file name */
  90. {
  91. SBTYPE sbPath; /* Path */
  92. SBTYPE sbFile; /* File name */
  93. SBTYPE sbDefault; /* Default file name */
  94. char FAR *lpch; /* Pointer to buffer */
  95. REGISTER BYTE *sb; /* Pointer to string */
  96. BSTYPE bsFile; /* File handle */
  97. #if OSMSDOS
  98. #if WIN_NT
  99. memcpy(sbFile, sbExe, sbExe[0] + 1);
  100. sbFile[sbFile[0]+1] = '\0';
  101. #else
  102. memcpy(sbFile,"\006A:.EXE",7); /* Initialize file name */
  103. sbFile[1] += DskCur; /* Use current drive */
  104. UpdateFileParts(sbFile,sbExe); /* Use parts of name given */
  105. #endif
  106. #endif
  107. memcpy(sbDefault,sbFile,sbFile[0]+2);
  108. /* Set default file name */
  109. if((bsFile = fopen(&sbFile[1],RDBIN)) != NULL) return(bsFile);
  110. /* If file found, return handle */
  111. #if OSMSDOS
  112. if (lpszPath != NULL) /* If variable set */
  113. {
  114. lpch = lpszPath;
  115. sb = sbPath; /* Initialize */
  116. do /* Loop through environment value */
  117. {
  118. if(*lpch == ';' || *lpch == '\0')
  119. { /* If end of path specification */
  120. if(sb > sbPath) /* If specification not empty */
  121. {
  122. if (!fPathChr(*sb) && *sb != ':') *++sb = CHPATH;
  123. /* Add path char if none */
  124. sbPath[0] = (BYTE)(sb - sbPath);
  125. /* Set length of path string */
  126. UpdateFileParts(sbFile,sbPath);
  127. /* Use the new path spec */
  128. if((bsFile = fopen(&sbFile[1],RDBIN)) != NULL)
  129. return(bsFile); /* If file found, return handle */
  130. sb = sbPath; /* Reset pointer */
  131. memcpy(sbFile,sbDefault,sbDefault[0]+2);
  132. /* Initialize file name */
  133. }
  134. }
  135. else *++sb = *lpch; /* Else copy character to path */
  136. }
  137. while(*lpch++ != '\0'); /* Loop until end of string */
  138. }
  139. #endif
  140. return(NULL); /* File not found */
  141. }
  142. /*
  143. * Default realmode DOS program stub.
  144. */
  145. LOCAL BYTE DefStub[] =
  146. {
  147. 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8,
  148. 0x01, 0x4c, 0xcd, 0x21
  149. };
  150. void NEAR EmitStub(void) /* Emit old .EXE header */
  151. {
  152. struct exe_hdr exe; /* Stub .EXE header */
  153. AHTEPTR ahteStub; /* File hash table entry */
  154. long lfaimage; /* File offset of old .EXE image */
  155. #if MSGMOD
  156. unsigned MsgLen;
  157. SBTYPE Msg; /* Message text */
  158. unsigned MsgStatus;
  159. char *pMsg; /* Pointer to message text */
  160. #endif
  161. SBTYPE StubFileName;
  162. #if OSMSDOS
  163. char buf[512]; /* File buffer */
  164. #endif
  165. /*
  166. * Emit stub .EXE header
  167. */
  168. if (rhteStub != RHTENIL
  169. #if ILINK
  170. || fQCIncremental
  171. #endif
  172. )
  173. {
  174. /* If a stub has been supplied or QC incremental link */
  175. #if ILINK
  176. if (fQCIncremental)
  177. {
  178. strcpy(StubFileName, "\014ilinkstb.ovl");
  179. }
  180. else
  181. {
  182. #endif
  183. ahteStub = (AHTEPTR ) FetchSym(rhteStub,FALSE);
  184. /* Get the stub file name */
  185. strcpy(StubFileName, GetFarSb(ahteStub->cch));
  186. #if ILINK
  187. }
  188. #endif
  189. StubFileName[StubFileName[0] + 1] = '\0';
  190. if((bsInput = LinkOpenExe(StubFileName)) == NULL)
  191. /* If file not found, quit */
  192. Fatal(ER_nostub, &StubFileName[1]);
  193. #if OSMSDOS
  194. setvbuf(bsInput,buf,_IOFBF,sizeof(buf));
  195. #endif
  196. if (xread(&exe,CBEXEHDR,1,bsInput) != 1) /* Read the header */
  197. Fatal(ER_badstub);
  198. if(E_MAGIC(exe) != EMAGIC) /* If stub is not an .EXE file */
  199. {
  200. fclose(bsInput); /* Close stub file */
  201. Fatal(ER_badstub);
  202. /* Print error message and die */
  203. }
  204. if (fseek(bsInput,(long) E_LFARLC(exe),0))
  205. Fatal(ER_ioerr, strerror(errno));
  206. /* Seek to relocation table */
  207. E_LFARLC(exe) = sizeof(struct exe_hdr);
  208. /* Change to new .EXE value */
  209. lfaimage = (long) E_CPARHDR(exe) << 4;
  210. /* Save offset of image */
  211. cbOldExe = ((long) E_CP(exe) << LG2PAG) - lfaimage;
  212. /* Calculate in-file image size */
  213. if(E_CBLP(exe) != 0) cbOldExe -= (long) PAGLEN - E_CBLP(exe);
  214. /* Diddle size for last page */
  215. E_CPARHDR(exe) = (WORD)((((long) E_CRLC(exe)*CBRLC +
  216. sizeof(struct exe_hdr) + PAGLEN - 1) >> LG2PAG) << 5);
  217. /* Calculate header size in para.s */
  218. E_RES(exe) = 0; /* Clear reserved word */
  219. E_CBLP(exe) = E_CP(exe) = E_MINALLOC(exe) = 0;
  220. E_LFANEW(exe) = 0L; /* Clear words which will be patched */
  221. raChksum = 0; /* Set checksum offset */
  222. WriteExe(&exe, CBEXEHDR); /* Write now, patch later */
  223. CopyBytes((long) E_CRLC(exe)*CBRLC);
  224. /* Copy relocations */
  225. PadToPage(LG2PAG); /* Pad to page boundary */
  226. if (fseek(bsInput,lfaimage,0)) /* Seek to start of image */
  227. Fatal(ER_ioerr, strerror(errno));
  228. #if ILINK
  229. if (fQCIncremental)
  230. cbOldExe -= PutName(lfaimage, &exe);
  231. /* Imbed .EXE file name into QC stubloader */
  232. #endif
  233. CopyBytes(cbOldExe); /* Copy the image */
  234. fclose(bsInput); /* Close input file */
  235. #if ILINK
  236. if (!fQCIncremental)
  237. #endif
  238. PadToPage(LG2PAG); /* Pad to page boundary */
  239. cbOldExe += ((long) E_MINALLOC(exe) << 4) +
  240. ((long) E_CPARHDR(exe) << 4); /* Add unitialized space and header */
  241. return; /* And return */
  242. }
  243. memset(&exe,0,sizeof(struct exe_hdr));/* Initialize to zeroes */
  244. #if CPU286
  245. if(TargetOs==NE_WINDOWS) /* Provide standard windows stub */
  246. {
  247. pMsg = GetMsg(P_stubmsgwin);
  248. MsgLen = strlen(pMsg);
  249. strcpy(Msg, pMsg);
  250. }
  251. else
  252. {
  253. MsgStatus = DosGetMessage((char far * far *) 0, 0,
  254. (char far *) Msg, SBLEN,
  255. MSG_PROT_MODE_ONLY,
  256. (char far *) "OSO001.MSG",
  257. (unsigned far *) &MsgLen);
  258. if (MsgStatus == 0)
  259. {
  260. /* Message retrieved from system file */
  261. Msg[MsgLen-1] = 0xd; /* Append CR */
  262. Msg[MsgLen] = 0xa; /* Append LF */
  263. Msg[MsgLen+1] = '$';
  264. MsgLen += 2;
  265. }
  266. else
  267. {
  268. /* System message file is not present - use standard message */
  269. #endif
  270. #if MSGMOD
  271. if(TargetOs==NE_WINDOWS) /* Provide standard windows stub */
  272. {
  273. pMsg = GetMsg(P_stubmsgwin);
  274. }
  275. else
  276. {
  277. pMsg = GetMsg(P_stubmsg);
  278. }
  279. MsgLen = strlen(pMsg);
  280. strcpy(Msg, pMsg);
  281. #endif
  282. #if CPU286
  283. }
  284. }
  285. #endif
  286. E_MAGIC(exe) = EMAGIC; /* Set magic number */
  287. E_MAXALLOC(exe) = 0xffff; /* Default is all available mem */
  288. /* SS will be same as CS, SP will be end of image + stack */
  289. #if MSGMOD
  290. cbOldExe = sizeof(DefStub) + MsgLen + CBSTUBSTK + ENEWEXE;
  291. #else
  292. cbOldExe = sizeof(DefStub) + strlen(P_stubmsg) + CBSTUBSTK + ENEWEXE;
  293. #endif
  294. E_SP(exe) = (WORD) ((cbOldExe - ENEWEXE) & ~1);
  295. E_LFARLC(exe) = ENEWEXE;
  296. E_CPARHDR(exe) = ENEWEXE >> 4;
  297. raChksum = 0; /* Set checksum offset */
  298. WriteExe(&exe, CBEXEHDR); /* Write the stub header */
  299. WriteExe(DefStub, sizeof(DefStub));
  300. #if MSGMOD
  301. WriteExe(Msg, MsgLen);
  302. #else
  303. WriteExe(P_stubmsg, strlen(P_stubmsg));
  304. #endif
  305. PadToPage(4); /* Pad to paragraph boundary */
  306. }
  307. #pragma check_stack(off)
  308. void NEAR PatchStub(lfahdr, lfaseg)
  309. long lfahdr; /* File address of new header */
  310. long lfaseg; /* File address of first segment */
  311. {
  312. long cbTotal; /* Total file size */
  313. WORD cpTotal; /* Pages total */
  314. WORD cbLast; /* Bytes on last page */
  315. WORD cparMin; /* Extra paragraphs needed */
  316. if (TargetOs == NE_WINDOWS
  317. #if ILINK
  318. || fQCIncremental
  319. #endif
  320. )
  321. cbTotal = lfaseg; /* QC incremental linking or Windows app */
  322. else
  323. cbTotal = ftell(bsRunfile); /* Get the size of the file */
  324. cpTotal = (WORD)((cbTotal + PAGLEN - 1) >> LG2PAG);
  325. /* Get the total number of pages */
  326. cbLast = (WORD) (cbTotal & (PAGLEN - 1));
  327. /* Get no. of bytes on last page */
  328. cbTotal = (cbTotal + 0x000F) & ~(1L << LG2PAG);
  329. /* Round to paragraph boundary */
  330. cbOldExe = (cbOldExe + 0x000F) & ~(1L << LG2PAG);
  331. /* Round to paragraph boundary */
  332. cbOldExe -= cbTotal; /* Subtract new size from old */
  333. if (fseek(bsRunfile,(long) ECBLP,0)) /* Seek into header */
  334. Fatal(ER_ioerr, strerror(errno));
  335. raChksum = ECBLP; /* Set checksum offset */
  336. WriteExe(&cbLast, CBWORD); /* Write no. of bytes on last page */
  337. WriteExe(&cpTotal, CBWORD); /* Write number of pages */
  338. if (fseek(bsRunfile,(long) EMINALLOC,0))/* Seek into header */
  339. Fatal(ER_ioerr, strerror(errno));
  340. cparMin = (cbOldExe < 0L)? 0: (WORD)(cbOldExe >> 4);
  341. /* Min. no. of extra paragraphs */
  342. raChksum = EMINALLOC; /* Set checksum offset */
  343. WriteExe(&cparMin, CBWORD); /* Write no. of extra para.s needed */
  344. if (fseek(bsRunfile,(long) ENEWHDR,0)) /* Seek into header */
  345. Fatal(ER_ioerr, strerror(errno));
  346. raChksum = ENEWHDR; /* Set checksum offset */
  347. WriteExe(&lfahdr, CBLONG); /* Write offset to new header */
  348. }
  349. #if NOT EXE386
  350. /****************************************************************
  351. * *
  352. * OutSas: *
  353. * *
  354. * This function moves a segment from virtual memory to the *
  355. * run file. *
  356. * *
  357. ****************************************************************/
  358. LOCAL void NEAR OutSas(WORD *mpsasec)
  359. {
  360. SATYPE sa; /* File segment number */
  361. DWORD lfaseg; /* File segment offset */
  362. if (saMac == 1)
  363. {
  364. OutWarn(ER_nosegdef); /* No code or initialized data in .EXE */
  365. return;
  366. }
  367. for(sa = 1; sa < saMac; ++sa) /* Loop through file segments */
  368. {
  369. if (mpsaRlc[sa] && mpsacbinit[sa] == 0L)
  370. mpsacbinit[sa] = 1L; /* If relocs, must be bytes in file */
  371. if (mpsacbinit[sa] != 0L) /* If bytes to write in file */
  372. {
  373. PadToPage(fileAlign); /* Pad to page boundary */
  374. lfaseg = (ftell(bsRunfile) >> fileAlign);
  375. WriteExe(mpsaMem[sa], mpsacbinit[sa]);
  376. /* Output the segment */
  377. FFREE(mpsaMem[sa]); // Free segment's memory
  378. }
  379. else
  380. lfaseg = 0L; /* Else no bytes in file */
  381. if (mpsaRlc[sa])
  382. OutFixTab(sa); /* Output fixups if any */
  383. if (lfaseg > 0xffffL)
  384. Fatal(ER_filesec);
  385. else
  386. mpsasec[sa] = (WORD)lfaseg;
  387. }
  388. ReleaseRlcMemory();
  389. }
  390. #pragma check_stack(on)
  391. /*** PutName - put .EXE file name into QC stubloader
  392. *
  393. * Purpose:
  394. * PutName will imbed the outfile name (.EXE) into the stubloader
  395. * so that programs can load in DOS 2.x
  396. *
  397. * Input:
  398. * hdr - pointer to stub loader .EXE header
  399. * lfaimage - start of the stub loader code in file
  400. * Output:
  401. * Number of bytes copied to .EXE file
  402. *
  403. *************************************************************************/
  404. LOCAL long NEAR PutName(long lfaimage, struct exe_hdr *hdr)
  405. {
  406. long offset_to_filename;
  407. char newname[NAMESIZE];
  408. char oldname[NAMESIZE];
  409. SBTYPE sbRun; /* Executable file name */
  410. AHTEPTR hte; /* Hash table entry address */
  411. long BytesCopied;
  412. WORD i, oldlen;
  413. /* Calculate the offset to the filename data patch */
  414. offset_to_filename = (E_CPARHDR(*hdr) << 4) + /* paragraphs in header */
  415. (E_CS(*hdr) << 4) + /* start of cs adjusted */
  416. E_IP(*hdr) - /* offset into cs of ip */
  417. NAMESIZE; /* back up to filename */
  418. /* Copy begin of stubloader */
  419. BytesCopied = offset_to_filename - lfaimage - 2;
  420. CopyBytes(BytesCopied);
  421. /* Read in the lenght and file name template and validate it */
  422. if (xread(&oldlen, sizeof(unsigned int), 1, bsInput) != 1)
  423. Fatal(ER_badobj);
  424. if (xread(oldname, sizeof(char), NAMESIZE, bsInput) != NAMESIZE)
  425. Fatal(ER_badobj);
  426. /* Does the name read match the signature */
  427. if (!(strcmp(oldname, "filename")))
  428. {
  429. hte = (AHTEPTR ) FetchSym(rhteRunfile,FALSE);
  430. /* Get run file name */
  431. memcpy(sbRun, &GetFarSb(hte->cch)[1], B2W(hte->cch[0]));
  432. /* Get name from hash table */
  433. sbRun[B2W(hte->cch[0])] = '\0'; /* Null-terminate name */
  434. memset(newname, 0, NAMESIZE); /* Initialize to zeroes */
  435. /* Copy only the proper number of characters */
  436. for (i = 0; (i < NAMESIZE-1 && sbRun[i] && sbRun[i] != '.'); i++)
  437. newname[i] = sbRun[i];
  438. /* Write the length of name */
  439. WriteExe(&i, sizeof(WORD));
  440. /* Write the new name over the signature */
  441. WriteExe(newname, NAMESIZE);
  442. return(BytesCopied + NAMESIZE + 2);
  443. }
  444. WriteExe(&oldlen, sizeof(WORD));
  445. return(BytesCopied + 2);
  446. }
  447. #pragma check_stack(off)
  448. /****************************************************************
  449. * *
  450. * OutSegTable: *
  451. * *
  452. * This function outputs the segment table. *
  453. * *
  454. ****************************************************************/
  455. LOCAL void NEAR OutSegTable(mpsasec)
  456. WORD *mpsasec; /* File segment to sector address */
  457. {
  458. struct new_seg ste; /* Segment table entry */
  459. SATYPE sa; /* Counter */
  460. for(sa = 1; sa < saMac; ++sa) /* Loop through file segments */
  461. {
  462. NS_SECTOR(ste) = mpsasec[sa]; /* Set the sector number */
  463. NS_CBSEG(ste) = (WORD) mpsacbinit[sa];
  464. /* Save the "in-file" length */
  465. NS_MINALLOC(ste) = (WORD) mpsacb[sa];
  466. /* Save total size */
  467. NS_FLAGS(ste) = mpsaflags[sa]; /* Set the segment attribute flags */
  468. if (mpsaRlc[sa])
  469. NS_FLAGS(ste) |= NSRELOC; /* Set reloc bit if there are relocs */
  470. WriteExe(&ste, CBNEWSEG); /* Write it to the executable file */
  471. }
  472. }
  473. /*
  474. * OutSegExe:
  475. *
  476. * Outputs a segmented-executable format file. This format is used
  477. * by DOS 4.0 and later, and Windows.
  478. * Called by OutRunfile.
  479. */
  480. void NEAR OutSegExe(void)
  481. {
  482. WORD sasec[SAMAX]; /* File segment to sector table */
  483. struct new_exe hdr; /* Executable header */
  484. SEGTYPE segStack; /* Stack segment */
  485. WORD i; /* Counter */
  486. long lfahdr; /* File address of new header */
  487. long lfaseg; /* File address of first segment */
  488. if (fStub
  489. #if ILINK
  490. || fQCIncremental
  491. #endif
  492. )
  493. EmitStub();
  494. /* Emit stub old .EXE header */
  495. /*
  496. * Emit the new portion of the .EXE
  497. */
  498. memset(&hdr,0,sizeof(struct new_exe));/* Set to zeroes */
  499. NE_MAGIC(hdr) = NEMAGIC; /* Set the magic number */
  500. NE_VER(hdr) = LINKVER; /* Set linker version number */
  501. NE_REV(hdr) = LINKREV; /* Set linker revision number */
  502. NE_CMOVENT(hdr) = cMovableEntries; /* Set count of movable entries */
  503. NE_ALIGN(hdr) = fileAlign; /* Set segment alignment field */
  504. NE_CRC(hdr) = 0; /* Assume CRC = 0 when calculating */
  505. if (((TargetOs == NE_OS2) || (TargetOs == NE_WINDOWS)) &&
  506. #if O68K
  507. iMacType == MAC_NONE &&
  508. #endif
  509. !(vFlags & NENOTP) && !(vFlags & NEAPPTYP))
  510. {
  511. if (TargetOs == NE_OS2)
  512. vFlags |= NEWINCOMPAT;
  513. else
  514. vFlags |= NEWINAPI;
  515. }
  516. if (gsnAppLoader)
  517. vFlags |= NEAPPLOADER;
  518. NE_FLAGS(hdr) = vFlags; /* Set header flags */
  519. NE_EXETYP(hdr) = TargetOs; /* Set target operating system */
  520. if (TargetOs == NE_WINDOWS)
  521. NE_EXPVER(hdr) = (((WORD) ExeMajorVer) << 8) | ExeMinorVer;
  522. NE_FLAGSOTHERS(hdr) = vFlagsOthers; /* Set other module flags */
  523. /*
  524. * If SINGLE or MULTIPLE DATA, then set the automatic data segment
  525. * from DGROUP. If DGROUP has not been declared and we're not a
  526. * dynlink library then issue a warning.
  527. */
  528. if((NE_FLAGS(hdr) & NEINST) || (NE_FLAGS(hdr) & NESOLO))
  529. {
  530. if(mpggrgsn[ggrDGroup] == SNNIL)
  531. {
  532. if(!(vFlags & NENOTP))
  533. OutWarn(ER_noautod);
  534. NE_AUTODATA(hdr) = SANIL;
  535. }
  536. else NE_AUTODATA(hdr) = mpsegsa[mpgsnseg[mpggrgsn[ggrDGroup]]];
  537. }
  538. else NE_AUTODATA(hdr) = SANIL; /* Else no auto data segment */
  539. if (fHeapMax)
  540. {
  541. if (NE_AUTODATA(hdr) != SANIL)
  542. NE_HEAP(hdr) = (WORD) (LXIVK - mpsacb[NE_AUTODATA(hdr)]-16);
  543. else /* Heap size = 64k - size of DGROUP - 16 */
  544. NE_HEAP(hdr) = 0xffff-16;
  545. }
  546. else
  547. NE_HEAP(hdr) = cbHeap; /* Set heap allocation */
  548. NE_STACK(hdr) = 0; /* Assume no stack in DGROUP */
  549. if (vFlags & NENOTP)
  550. NE_SSSP(hdr) = 0L; /* Libraries have no stack at all */
  551. else if (gsnStack != SNNIL)
  552. {
  553. /* If there is a stack segment definition */
  554. segStack = mpgsnseg[gsnStack]; /* Get stack segment number */
  555. /*
  556. * If stack segment is in DGROUP, adjust size of DGROUP down and
  557. * move stack allocation to ne_stack field, so it can be modified
  558. * after linking. Only do this if DGROUP has more than just the
  559. * stack segment.
  560. */
  561. if (fSegOrder &&
  562. NE_AUTODATA(hdr) == mpsegsa[segStack] &&
  563. mpsacb[NE_AUTODATA(hdr)] > cbStack)
  564. {
  565. mpsacb[NE_AUTODATA(hdr)] -= cbStack;
  566. NE_STACK(hdr) = (WORD) cbStack;
  567. NE_SSSP(hdr) = (long) (NE_AUTODATA(hdr)) << WORDLN;
  568. /* SS:SP = DS:0 */
  569. if (fHeapMax)
  570. {
  571. /* If max heap - adjust heap size */
  572. if (NE_HEAP(hdr) >= (WORD) cbStack)
  573. NE_HEAP(hdr) -= cbStack;
  574. }
  575. }
  576. else
  577. NE_SSSP(hdr) = cbStack + mpsegraFirst[segStack] +
  578. ((long) mpsegsa[segStack] << WORDLN);
  579. /* Set initial SS:SP */
  580. }
  581. else /* Else assume stack is in DGROUP */
  582. {
  583. NE_SSSP(hdr) = (long) NE_AUTODATA(hdr) << WORDLN;
  584. /* SS:SP = DS:0 */
  585. NE_STACK(hdr) = (WORD) cbStack; /* Set stack allocation */
  586. if (fHeapMax)
  587. {
  588. /* If max heap - adjust heap size */
  589. if (NE_HEAP(hdr) >= (WORD) cbStack)
  590. NE_HEAP(hdr) -= cbStack;
  591. }
  592. }
  593. /* Check that auto data + heapsize <= 64K */
  594. if(NE_AUTODATA(hdr) != SNNIL)
  595. if(mpsacb[NE_AUTODATA(hdr)] +
  596. (long) NE_HEAP(hdr) +
  597. (long) NE_STACK(hdr) > LXIVK)
  598. OutError(ER_datamax);
  599. if (!(vFlags & NENOTP) && (segStart == 0))
  600. Fatal(ER_nostartaddr);
  601. NE_CSIP(hdr) = raStart + ((long) mpsegsa[segStart] << WORDLN);
  602. /* Set starting point */
  603. NE_CSEG(hdr) = saMac - 1; /* Number of file segments */
  604. NE_CMOD(hdr) = ModuleRefTable.wordMac;
  605. /* Number of modules imported */
  606. lfahdr = MakeHole((long) sizeof(struct new_exe));
  607. /* Leave space for header */
  608. i = NE_CSEG(hdr)*sizeof(struct new_seg);
  609. /* Calc. size of Segment Table */
  610. NE_SEGTAB(hdr) = (WORD)(MakeHole((long) i) - lfahdr);
  611. /* Leave hole for segment table */
  612. NE_RSRCTAB(hdr) = NE_SEGTAB(hdr) + i;
  613. /* Offset of Resource Table */
  614. NE_RESTAB(hdr) = NE_RSRCTAB(hdr); /* Offset of Resident Name Table */
  615. NE_MODTAB(hdr) = NE_RESTAB(hdr);
  616. #if OUT_EXP
  617. /* Convert Res and Non Resident Name Tables to uppercase
  618. and write export file */
  619. ProcesNTables(bufExportsFileName);
  620. #endif
  621. if (ResidentName.byteMac)
  622. {
  623. ByteArrayPut(&ResidentName, sizeof(BYTE), "\0");
  624. WriteByteArray(&ResidentName); /* If we have Resident Name Table */
  625. /* Output table with null at end */
  626. NE_MODTAB(hdr) += ResidentName.byteMac;
  627. FreeByteArray(&ResidentName);
  628. }
  629. /* Calc. offset of Module Ref Table */
  630. WriteWordArray(&ModuleRefTable);
  631. /* Output the Module Reference Table */
  632. NE_IMPTAB(hdr) = NE_MODTAB(hdr) + ModuleRefTable.wordMac * sizeof(WORD);
  633. FreeWordArray(&ModuleRefTable);
  634. /* Calc offset of Imported Names Tab */
  635. NE_ENTTAB(hdr) = NE_IMPTAB(hdr); /* Minimum offset of Entry Table */
  636. if (ImportedName.byteMac > 1) /* If Imported Names Table not empty */
  637. {
  638. WriteByteArray(&ImportedName); /* Output the Imported Names Table */
  639. NE_ENTTAB(hdr) += ImportedName.byteMac;
  640. FreeByteArray(&ImportedName);
  641. /* Add in length of table */
  642. }
  643. #if NOT QCLINK
  644. #if ILINK
  645. if (!fQCIncremental)
  646. #endif
  647. OutEntTab(); /* Output the Entry Table */
  648. #endif
  649. NE_CBENTTAB(hdr) = EntryTable.byteMac;
  650. /* Set size of Entry Table */
  651. FreeByteArray(&EntryTable);
  652. NE_NRESTAB(hdr) = ftell(bsRunfile);
  653. ByteArrayPut(&NonResidentName, sizeof(BYTE), "\0");
  654. WriteByteArray(&NonResidentName); /* Output table with null at end */
  655. NE_CBNRESTAB(hdr) = NonResidentName.byteMac;
  656. FreeByteArray(&NonResidentName);
  657. /* Size of non-resident name table */
  658. lfaseg = ftell(bsRunfile); /* Remember where segment data starts in file */
  659. OutSas(sasec); /* Output the file segments */
  660. PatchStub(lfahdr, lfaseg); /* Patch stub header */
  661. if(cErrors || fUndefinedExterns) NE_FLAGS(hdr) |= NEIERR;
  662. /* If errors, set error bit */
  663. if (fseek(bsRunfile,lfahdr,0)) /* Seek to beginning of header */
  664. Fatal(ER_ioerr, strerror(errno));
  665. raChksum = (WORD) lfahdr; /* Set checksum offset */
  666. WriteExe(&hdr, CBNEWEXE); /* Write the header */
  667. OutSegTable(sasec); /* Write the segment table */
  668. if (fseek(bsRunfile,lfahdr+NECRC,0)) /* Seek into new header */
  669. Fatal(ER_ioerr, strerror(errno));
  670. NE_CRC(hdr) = chksum32; /* Must copy, else chksum32 trashed */
  671. WriteExe((BYTE FAR *) &NE_CRC(hdr), CBLONG);
  672. /* Write the checksum */
  673. if (fseek(bsRunfile, 0L, 2)) /* Go to end of file */
  674. Fatal(ER_ioerr, strerror(errno));
  675. if (fExeStrSeen)
  676. WriteExe(ExeStrBuf, ExeStrLen);
  677. #if SYMDEB
  678. if (fSymdeb)
  679. {
  680. #if ILINK
  681. if (fIncremental)
  682. PadToPage(fileAlign); /* Pad to page boundary for ILINK */
  683. #endif
  684. OutDebSections(); /* Generate ISLAND sections */
  685. }
  686. #endif
  687. }
  688. #endif /* NOT EXE386 */