Source code of Windows XP (NT5)
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.

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