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.

2150 lines
72 KiB

  1. /*** comdat.c - handle COMDAT records
  2. *
  3. * Copyright <C> 1990, Microsoft Corporation
  4. *
  5. * Purpose:
  6. * Process COMDAT records in various stages of linker work.
  7. *
  8. * Revision History:
  9. *
  10. * [] 06-Jun-1990 WJK Created
  11. *
  12. *************************************************************************/
  13. #include <minlit.h> /* Basic types and constants */
  14. #include <bndtrn.h> /* More types and constants */
  15. #include <bndrel.h> /* More types and constants */
  16. #include <lnkio.h> /* Linker I/O definitions */
  17. #include <newexe.h> /* DOS & 286 .EXE data structures */
  18. #if EXE386
  19. #include <exe386.h> /* 386 .EXE data structures */
  20. #endif
  21. #include <lnkmsg.h> /* Error messages */
  22. #if OXOUT OR OIAPX286
  23. #include <xenfmt.h> /* Xenix format definitions */
  24. #endif
  25. #include <extern.h> /* External declarations */
  26. #include <string.h>
  27. #if OSEGEXE
  28. extern RLCPTR rlcLidata; /* Pointer to LIDATA fixup array */
  29. extern RLCPTR rlcCurLidata; /* Pointer to current LIDATA fixup */
  30. #endif
  31. #define COMDAT_SEG_NAME "\012COMDAT_SEG"
  32. #define COMDAT_NAME_LEN 11
  33. #define COMDATDEBUG FALSE
  34. #define ALLOC_TYPE(x) ((x)&ALLOCATION_MASK)
  35. #define SELECT_TYPE(x) ((x)&SELECTION_MASK)
  36. #define IsVTABLE(x) ((x)&VTABLE_BIT)
  37. #define IsLOCAL(x) ((x)&LOCAL_BIT)
  38. #define IsORDERED(x) ((x)&ORDER_BIT)
  39. #define IsCONCAT(x) ((x)&CONCAT_BIT)
  40. #define IsDEFINED(x) ((x)&DEFINED_BIT)
  41. #define IsALLOCATED(x) ((x)&ALLOCATED_BIT)
  42. #define IsITERATED(x) ((x)&ITER_BIT)
  43. #define IsREFERENCED(x) ((x)&REFERENCED_BIT)
  44. #define IsSELECTED(x) ((x)&SELECTED_BIT)
  45. #define SkipCONCAT(x) ((x)&SKIP_BIT)
  46. /*
  47. * Global data exported from this module
  48. */
  49. FTYPE fSkipFixups; // TRUE if skiping COMDAT and its fixups
  50. FTYPE fFarCallTransSave;
  51. // Previous state of /FarCallTarnaslation
  52. /*
  53. * Local types
  54. */
  55. typedef struct comdatRec
  56. {
  57. GRTYPE ggr;
  58. SNTYPE gsn;
  59. RATYPE ra;
  60. WORD flags;
  61. WORD attr;
  62. WORD align;
  63. WORD type;
  64. RBTYPE name;
  65. }
  66. COMDATREC;
  67. /*
  68. * Local data
  69. */
  70. LOCAL SNTYPE curGsnCode16; // Current 16-bit code segment
  71. LOCAL DWORD curCodeSize16; // Current 16-bit code segment size
  72. LOCAL SNTYPE curGsnData16; // Current 16-bit data segment
  73. LOCAL DWORD curDataSize16; // Current 16-bit data segment size
  74. #if EXE386
  75. LOCAL SNTYPE curGsnCode32; // Current 32-bit code segment
  76. LOCAL DWORD curCodeSize32; // Current 32-bit code segment size
  77. LOCAL SNTYPE curGsnData32; // Current 32-bit data segment
  78. LOCAL DWORD curDataSize32; // Current 32-bit data segment size
  79. #endif
  80. #if OVERLAYS
  81. LOCAL WORD iOvlCur; // Current overlay index
  82. #endif
  83. #if TCE
  84. SYMBOLUSELIST aEntryPoints; // List of program entry points
  85. #endif
  86. extern BYTE * ObExpandIteratedData(unsigned char *pb,
  87. unsigned short cBlocks,
  88. WORD *pSize);
  89. /*
  90. * Local function prototypes
  91. */
  92. LOCAL DWORD NEAR DoCheckSum(void);
  93. LOCAL void NEAR PickComDat(RBTYPE vrComdat, COMDATREC *omfRec, WORD fNew);
  94. LOCAL void NEAR ReadComDat(COMDATREC *omfRec);
  95. LOCAL void NEAR ConcatComDat(RBTYPE vrComdat, COMDATREC *omfRec);
  96. LOCAL void NEAR AttachPublic(RBTYPE vrComdat, COMDATREC *omfRec);
  97. LOCAL void NEAR AdjustOffsets(RBTYPE vrComdat, DWORD startOff, SNTYPE gsnAlloc);
  98. LOCAL WORD NEAR SizeOfComDat(RBTYPE vrComdat, DWORD *pActual);
  99. LOCAL RATYPE NEAR DoAligment(RATYPE value, WORD align);
  100. LOCAL DWORD NEAR DoAllocation(SNTYPE gsnAlloc, DWORD size,
  101. RBTYPE vrComdat, DWORD comdatSize);
  102. LOCAL WORD NEAR NewSegment(SNTYPE *gsnPrev, DWORD *sizePrev, WORD allocKind);
  103. LOCAL void NEAR AllocAnonymus(RBTYPE vrComdat);
  104. LOCAL WORD NEAR SegSizeOverflow(DWORD segSize, DWORD comdatSize,
  105. WORD f16bit, WORD fCode);
  106. #if TCE
  107. LOCAL void NEAR MarkAlive( APROPCOMDAT *pC );
  108. LOCAL void PerformTce( void );
  109. void AddTceEntryPoint( APROPCOMDAT *pC );
  110. #endif
  111. #if COMDATDEBUG
  112. void DisplayComdats(char *title, WORD fPhysical);
  113. #endif
  114. #pragma check_stack(on)
  115. /*** DoCheckSum - calculate a check sum of a COMDAT data block
  116. *
  117. * Purpose:
  118. * The check sum is used for match exact criteria.
  119. *
  120. * Input:
  121. * No explicit value is passed. The following global data is used as
  122. * input to this function:
  123. *
  124. * cbRec - current record lenght; decremented by every read from
  125. * the OMF record, so effectivelly cbRec tells you how
  126. * many bytes are left in the record.
  127. *
  128. * Output:
  129. * Returns the 32-bit check sum of COMDAT data block.
  130. *
  131. * Exceptions:
  132. * None.
  133. *
  134. * Notes:
  135. * None.
  136. *
  137. *************************************************************************/
  138. LOCAL DWORD NEAR DoCheckSum(void)
  139. {
  140. DWORD result;
  141. DWORD shift;
  142. result = 0L;
  143. shift = 0;
  144. while (cbRec > 1)
  145. {
  146. result += ((DWORD ) Gets()) << (BYTELN * shift);
  147. shift = (shift + 1) & 3;
  148. }
  149. return(result);
  150. }
  151. /*** PickComDat - fill in the COMDAT descriptor
  152. *
  153. * Purpose:
  154. * Fill in the linkers symbol table COMDAT descriptor. This function
  155. * is called for new descriptors and for already entered one which
  156. * need to be updated - remember we have plenty of COMDAT selection criteria.
  157. *
  158. * Input:
  159. * vrComDat - virtual pointer to symbol table entry
  160. * omfRec - pointer to COMDAT OMF data
  161. * fNew - TRUE if new entry in symbol table
  162. * mpgsnprop - table mapping global segment index to symbol table entry
  163. * This one of those friendly global variables linker is full of.
  164. * vrprop - virtual pointer to symbol table entry - another global
  165. * variable; it is set by call to PropSymLookup which must
  166. * proceed call to PickComDat
  167. * cbRec - size of current OMF record - global variable - decremented
  168. * by every read from record
  169. * vrpropFile - current .OBJ file - global variable
  170. * lfaLast - current offset in the .OBJ - global variable
  171. *
  172. * Output:
  173. * No explicit value is returned. As a side effect symbol table entry
  174. * is updated and VM page is marked dirty.
  175. *
  176. * Exceptions:
  177. * Explicit allocation, but target segment not defined - issue error and
  178. * return.
  179. *
  180. * Notes:
  181. * None.
  182. *
  183. *************************************************************************/
  184. LOCAL void NEAR PickComDat(RBTYPE vrComdat, COMDATREC *omfRec, WORD fNew)
  185. {
  186. RBTYPE vrTmp; // Virtual pointer to COMDAT symbol table entry
  187. APROPCOMDATPTR apropComdat; // Pointer to symbol table descriptor
  188. APROPFILEPTR apropFile; // Current object module prop. cell
  189. WORD cbDataExp = 0; // Length of expanded DATA field
  190. #if RGMI_IN_PLACE
  191. rgmi = bufg; /* use temporary buffer for holding info */
  192. #endif
  193. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  194. if ((ALLOC_TYPE(omfRec->attr) == EXPLICIT) &&
  195. omfRec->gsn && (mpgsnrprop[omfRec->gsn] == VNIL))
  196. {
  197. // ERROR - explicit allocation segment not defined
  198. OutError(ER_comdatalloc, 1 + GetPropName(apropComdat));
  199. return;
  200. }
  201. // Fill in the COMDAT descriptor
  202. apropComdat->ac_ggr = omfRec->ggr;
  203. apropComdat->ac_gsn = omfRec->gsn;
  204. apropComdat->ac_ra = omfRec->ra;
  205. if (IsITERATED (omfRec->flags)) // We'll need to find size of expanded block
  206. {
  207. BYTE *pb = rgmi;
  208. vcbData = (WORD)(cbRec - 1);// Length of the DATA field
  209. GetBytesNoLim (rgmi, vcbData);
  210. while((pb = ObExpandIteratedData(pb,1, &cbDataExp)) < rgmi + vcbData);
  211. apropComdat->ac_size = cbDataExp;
  212. }
  213. else
  214. {
  215. apropComdat->ac_size = cbRec - 1;
  216. }
  217. if (fNew)
  218. {
  219. apropComdat->ac_flags = omfRec->flags;
  220. #if OVERLAYS
  221. if (IsVTABLE(apropComdat->ac_flags))
  222. apropComdat->ac_iOvl = IOVROOT;
  223. else
  224. apropComdat->ac_iOvl = NOTIOVL;
  225. #endif
  226. }
  227. else
  228. apropComdat->ac_flags |= omfRec->flags;
  229. apropComdat->ac_selAlloc = (BYTE) omfRec->attr;
  230. apropComdat->ac_align = (BYTE) omfRec->align;
  231. if (ALLOC_TYPE(omfRec->attr) == EXACT)
  232. apropComdat->ac_data = DoCheckSum();
  233. else
  234. apropComdat->ac_data = 0L;
  235. apropComdat->ac_obj = vrpropFile;
  236. apropComdat->ac_objLfa = lfaLast;
  237. if (IsORDERED(apropComdat->ac_flags))
  238. apropComdat->ac_flags |= DEFINED_BIT;
  239. if (!IsCONCAT(omfRec->flags))
  240. {
  241. if (ALLOC_TYPE(omfRec->attr) == EXPLICIT)
  242. {
  243. // Attach this COMDAT to its segment list
  244. AttachComdat(vrComdat, omfRec->gsn);
  245. }
  246. #if OVERLAYS
  247. else if (fOverlays && (apropComdat->ac_iOvl == NOTIOVL))
  248. apropComdat->ac_iOvl = iovFile;
  249. #endif
  250. // Attach this COMDAT to its file list
  251. apropFile = (APROPFILEPTR ) FetchSym(vrpropFile, TRUE);
  252. if (apropFile->af_ComDat == VNIL)
  253. {
  254. apropFile->af_ComDat = vrComdat;
  255. apropFile->af_ComDatLast = vrComdat;
  256. }
  257. else
  258. {
  259. vrTmp = apropFile->af_ComDatLast;
  260. apropFile->af_ComDatLast = vrComdat;
  261. apropComdat = (APROPCOMDATPTR ) FetchSym(vrTmp, TRUE);
  262. apropComdat->ac_sameFile = vrComdat;
  263. }
  264. }
  265. }
  266. /*** ReadComDat - self-explanatory
  267. *
  268. * Purpose:
  269. * Decode the COMDAT record.
  270. *
  271. * Input:
  272. * omfRec - pointer to COMDAT OMF record
  273. * bsInput - current .OBJ file - global variable
  274. * grMac - current maximum number of group defined in this .OBJ module
  275. * global variable
  276. * snMac - current maximum number of segments defined in this .OBJ
  277. * module - global variable
  278. * mpgrggr - table mapping local group index to global group index - global
  279. * variable
  280. * mpsngsn - table mapping local segment index to global segment index
  281. * - global variable
  282. *
  283. * Output:
  284. * Returns COMDAT symbol name, group and segment indexes, data offset
  285. * attributes and aligment.
  286. *
  287. * Exceptions:
  288. * Invalid .OBJ format.
  289. *
  290. * Notes:
  291. * None.
  292. *
  293. *************************************************************************/
  294. LOCAL void NEAR ReadComDat(COMDATREC *omfRec)
  295. {
  296. SNTYPE sn; // Local SEGDEF no. - module scope only
  297. omfRec->ggr = 0;
  298. omfRec->gsn = 0;
  299. // The record header (type and length) has been already read
  300. // and stored in rect and cbRec - read the COMDAT attribute byte
  301. omfRec->flags = (WORD) Gets();
  302. omfRec->attr = (WORD) Gets();
  303. omfRec->align = (WORD) Gets();
  304. #if OMF386
  305. if(rect & 1)
  306. omfRec->ra = LGets();
  307. else
  308. #endif
  309. omfRec->ra = WGets(); // Get COMDAT data offset
  310. omfRec->type = GetIndex(0, 0x7FFF); // Get type index
  311. if (ALLOC_TYPE(omfRec->attr) == EXPLICIT)
  312. {
  313. // If explicit allocation read the public base of COMDAT symbol
  314. omfRec->ggr = (GRTYPE) GetIndex(0, (WORD) (grMac - 1));
  315. // Get group index
  316. if(!(sn = GetIndex(0, (WORD) (snMac - 1))))
  317. {
  318. // If frame number present
  319. omfRec->gsn = 0; // No global SEGDEF no.
  320. SkipBytes(2); // Skip the frame number
  321. }
  322. else // Else if local SEGDEF no. given
  323. {
  324. if (omfRec->ggr != GRNIL)
  325. omfRec->ggr = mpgrggr[omfRec->ggr]; // If group specified, get global no
  326. omfRec->gsn = mpsngsn[sn]; // Get global SEGDEF no.
  327. }
  328. }
  329. omfRec->name = mplnamerhte[GetIndex(1, (WORD) (lnameMac - 1))];
  330. // Get symbol length
  331. }
  332. /*** ConcatComDat - append COMDAT to the list of concatenated records
  333. *
  334. * Purpose:
  335. * Concatenate COMDAT records. This function build the list of COMDAT
  336. * descriptors for contatenated records. Only the first descriptor
  337. * on the list has attribute COMDAT, which means that the head of the
  338. * list can be found when looking up the symbol table. The rest of the
  339. * elements on the list remain anonymus.
  340. *
  341. * Input:
  342. * vrComdat - virtual pointer to the first descriptor on the list
  343. * omfRec - pointer to COMDAT OMF record
  344. *
  345. * Output:
  346. * No explicit value is returned. As a side effect this function
  347. * adds the descriptor to the list of concatenated COMDAT records.
  348. *
  349. * Exceptions:
  350. * Different attributes in the first and concatenated records - display
  351. * error message and skip the concatenated record.
  352. *
  353. * Notes:
  354. * None.
  355. *
  356. *************************************************************************/
  357. LOCAL void NEAR ConcatComDat(RBTYPE vrComdat, COMDATREC *omfRec)
  358. {
  359. APROPCOMDATPTR apropComdatNew; // Real pointer to added COMDAT
  360. RBTYPE vrComdatNew; // Virtual pointer to added COMDAT
  361. APROPCOMDATPTR apropComdat; // Real pointer to the head of the list
  362. RBTYPE vrTmp;
  363. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  364. if (apropComdat->ac_gsn != omfRec->gsn ||
  365. apropComdat->ac_ggr != omfRec->ggr ||
  366. apropComdat->ac_selAlloc != (BYTE) omfRec->attr)
  367. {
  368. if(IsORDERED(apropComdat->ac_flags) &&
  369. (ALLOC_TYPE(apropComdat->ac_selAlloc) == EXPLICIT))
  370. {
  371. // Must preserve the allocation info from the .def file
  372. omfRec->gsn = apropComdat->ac_gsn;
  373. omfRec->ggr = apropComdat->ac_ggr;
  374. omfRec->attr = apropComdat->ac_selAlloc;
  375. }
  376. else
  377. OutError(ER_badconcat, 1 + GetPropName(apropComdat));
  378. }
  379. vrComdatNew = RbAllocSymNode(sizeof(APROPCOMDAT));
  380. // Allocate symbol space
  381. apropComdatNew = (APROPCOMDATPTR ) FetchSym(vrComdatNew, TRUE);
  382. apropComdatNew->ac_next = NULL;
  383. apropComdatNew->ac_attr = ATTRNIL;
  384. PickComDat(vrComdatNew, omfRec, TRUE);
  385. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  386. // Refetch head of the list
  387. if (apropComdat->ac_concat == VNIL)
  388. apropComdat->ac_concat = vrComdatNew;
  389. else
  390. {
  391. // Append at the end of the list
  392. vrTmp = apropComdat->ac_concat;
  393. while (vrTmp != VNIL)
  394. {
  395. apropComdat = (APROPCOMDATPTR ) FetchSym(vrTmp, TRUE);
  396. vrTmp = apropComdat->ac_concat;
  397. }
  398. apropComdat->ac_concat = vrComdatNew;
  399. }
  400. }
  401. /*** AttachPublic - add matching public symbol to the COMDAT
  402. *
  403. * Purpose:
  404. * Attaches public symbol definition to the COMDAT definition. It is
  405. * necessary because the fixups work only on matched EXTDEF with PUBDEF
  406. * not with COMDAT, so in order to correctly resolve references to COMDAT
  407. * symbol linker needs the PUBDEF for the same symbol, which eventually
  408. * will be matched with references made to the EXTDEF.
  409. * The public symbols for COMDAT's are created when we see new COMDAT
  410. * symbol or we have COMDAT introduced by ORDER statement in the .DEF
  411. * file.
  412. *
  413. * Input:
  414. * vrComdat - virtual pointer to COMDAT descriptor
  415. * omfRec - COMDAT record
  416. *
  417. * Output:
  418. * No explicit value is returned. As a side effect the link is created
  419. * between COMDAT descriptor and new PUBDEF descriptor.
  420. *
  421. * Exceptions:
  422. * COMDAT symbol matches COMDEF symbol - display error and contine
  423. * with COMDEF symbol converted to PUBDEF. The .EXE will not load
  424. * under OS/2 or Windows, because the error bit will be set.
  425. *
  426. * Notes:
  427. * None.
  428. *
  429. *************************************************************************/
  430. LOCAL void NEAR AttachPublic(RBTYPE vrComdat, COMDATREC *omfRec)
  431. {
  432. APROPNAMEPTR apropName; // Symbol table entry for public name
  433. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  434. WORD fReferenced; // TRUE if we've seen CEXTDEF
  435. fReferenced = FALSE;
  436. apropName = (APROPNAMEPTR ) PropRhteLookup(omfRec->name, ATTRUND, FALSE);
  437. // Look for symbol among undefined
  438. if (apropName != PROPNIL) // Symbol known to be undefined
  439. {
  440. fReferenced = TRUE;
  441. #if TCE
  442. if(((APROPUNDEFPTR)apropName)->au_fAlive) // was called from a non-COMDAT
  443. {
  444. #if TCE_DEBUG
  445. fprintf(stdout, "\r\nAlive UNDEF -> COMDAT %s ", 1+GetPropName(apropName));
  446. #endif
  447. AddTceEntryPoint((APROPCOMDAT*)vrComdat);
  448. }
  449. #endif
  450. }
  451. else
  452. apropName = (APROPNAMEPTR ) PropAdd(omfRec->name, ATTRPNM);
  453. // Else try to create new entry
  454. apropName->an_attr = ATTRPNM; // Symbol is a public name
  455. apropName->an_thunk = THUNKNIL;
  456. if (IsLOCAL(omfRec->flags))
  457. {
  458. apropName->an_flags = 0;
  459. #if ILINK
  460. ++locMac;
  461. #endif
  462. }
  463. else
  464. {
  465. apropName->an_flags = FPRINT;
  466. ++pubMac;
  467. }
  468. #if ILINK
  469. apropName->an_module = imodFile;
  470. #endif
  471. MARKVP(); // Mark virtual page as changed
  472. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  473. apropComdat->ac_pubSym = vrprop;
  474. if (fReferenced)
  475. apropComdat->ac_flags |= REFERENCED_BIT;
  476. #if SYMDEB
  477. if (fSymdeb && !IsLOCAL(omfRec->flags) && !fSkipPublics)
  478. {
  479. DebPublic(vrprop, PUBDEF);
  480. }
  481. #endif
  482. }
  483. /*** ComDatRc1 - process COMDAT record in pass 1
  484. *
  485. * Purpose:
  486. * Process COMDAT record in pass 1. Select appropriate copy of COMDAT.
  487. *
  488. * Input:
  489. * No explicit value is passed to this function. The OMF record is
  490. * read from input file bsInput - global variable.
  491. *
  492. * Output:
  493. * No explicit value is returned. Valid COMDAT descriptor is entered into
  494. * the linker symbol table. If necessary list of COMDATs allocated in the
  495. * explicit segment is updated.
  496. *
  497. * Exceptions:
  498. * Explicit allocation segment not found - error message and skip the record.
  499. * We have public with the same name as COMDAT - error message and skip
  500. * the record.
  501. *
  502. * Notes:
  503. * None.
  504. *
  505. *************************************************************************/
  506. void NEAR ComDatRc1(void)
  507. {
  508. COMDATREC omfRec; // COMDAT OMF record
  509. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  510. RBTYPE vrComdat; // Virtual pointer to COMDAT record
  511. char *sbName; // COMDAT symbol
  512. ReadComDat(&omfRec);
  513. apropComdat = (APROPCOMDATPTR ) PropRhteLookup(omfRec.name, ATTRCOMDAT, FALSE);
  514. // Look for symbol among COMDATs
  515. vrComdat = vrprop;
  516. #if TCE
  517. pActiveComdat = apropComdat;
  518. #endif
  519. if (apropComdat != PROPNIL)
  520. {
  521. // We already know a COMDAT with this name
  522. if (IsORDERED(apropComdat->ac_flags) && !IsDEFINED(apropComdat->ac_flags))
  523. {
  524. if (ALLOC_TYPE(apropComdat->ac_selAlloc) == EXPLICIT)
  525. {
  526. // Preserve explicit allocation from the .def file
  527. omfRec.gsn = apropComdat->ac_gsn;
  528. omfRec.attr = apropComdat->ac_selAlloc;
  529. }
  530. PickComDat(vrComdat, &omfRec, FALSE);
  531. AttachPublic(vrComdat, &omfRec);
  532. }
  533. else if (!SkipCONCAT(apropComdat->ac_flags) &&
  534. IsCONCAT(omfRec.flags) &&
  535. (apropComdat->ac_obj == vrpropFile))
  536. {
  537. // Append concatenation record
  538. ConcatComDat(vrComdat, &omfRec);
  539. }
  540. else
  541. {
  542. #if TCE
  543. pActiveComdat = NULL; // not needed for TCE
  544. #endif
  545. apropComdat->ac_flags |= SKIP_BIT;
  546. sbName = 1 + GetPropName(apropComdat);
  547. switch (SELECT_TYPE(omfRec.attr))
  548. {
  549. case ONLY_ONCE:
  550. DupErr(sbName);
  551. break;
  552. case PICK_FIRST:
  553. break;
  554. case SAME_SIZE:
  555. if (apropComdat->ac_size != (DWORD) (cbRec - 1))
  556. OutError(ER_badsize, sbName);
  557. break;
  558. case EXACT:
  559. if (apropComdat->ac_data != DoCheckSum())
  560. OutError(ER_badexact, sbName);
  561. break;
  562. default:
  563. OutError(ER_badselect, sbName);
  564. break;
  565. }
  566. }
  567. }
  568. else
  569. {
  570. // Check if we know a public symbol with this name
  571. apropComdat = (APROPCOMDATPTR ) PropRhteLookup(omfRec.name, ATTRPNM, FALSE);
  572. if (apropComdat != PROPNIL)
  573. {
  574. if (!IsCONCAT(omfRec.flags))
  575. {
  576. sbName = 1 + GetPropName(apropComdat);
  577. DupErr(sbName); // COMDAT matches code PUBDEF
  578. } // Display error only for the first COMDAT
  579. // ignore concatenation records
  580. }
  581. else
  582. {
  583. // Enter COMDAT into symbol table
  584. apropComdat = (APROPCOMDATPTR ) PropAdd(omfRec.name, ATTRCOMDAT);
  585. vrComdat = vrprop;
  586. PickComDat(vrprop, &omfRec, TRUE);
  587. AttachPublic(vrComdat, &omfRec);
  588. #if TCE
  589. #define ENTRIES 32
  590. #if 0
  591. fprintf(stdout, "\r\nNew COMDAT '%s' at %X; ac_uses %X, ac_usedby %X ",
  592. 1+GetPropName(apropComdat), apropComdat,&(apropComdat->ac_uses), &(apropComdat->ac_usedby));
  593. fprintf(stdout, "\r\nNew COMDAT '%s' ",1+GetPropName(apropComdat));
  594. #endif
  595. apropComdat->ac_fAlive = FALSE; // Assume it is unreferenced
  596. apropComdat->ac_uses.cEntries = 0;
  597. apropComdat->ac_uses.cMaxEntries = ENTRIES;
  598. apropComdat->ac_uses.pEntries = GetMem(ENTRIES * sizeof(APROPCOMDAT*));
  599. pActiveComdat = apropComdat;
  600. #endif
  601. }
  602. }
  603. SkipBytes((WORD) (cbRec - 1)); // Skip to check sum byte
  604. }
  605. /*** AdjustOffsets - adjust COMDATs offsets
  606. *
  607. * Purpose:
  608. * Adjust COMDATs offsets to reflect their position inside
  609. * logical segments.
  610. *
  611. * Input:
  612. * vrComdat - virtual pointer to COMDAT symbol table entry
  613. * startOff - starting offset in the logical segment
  614. * gsnAlloc - global segment index of allocation segment
  615. *
  616. * Output:
  617. * No explicit value is returned. As a side effect offsets
  618. * of COMDAT data block are adjusted to their final position
  619. * inside the logical segment. All concatenated COMDAT block
  620. * get proper global logical segment index.
  621. *
  622. * Exceptions:
  623. * None.
  624. *
  625. * Notes:
  626. * None.
  627. *
  628. *************************************************************************/
  629. LOCAL void NEAR AdjustOffsets(RBTYPE vrComdat, DWORD startOff, SNTYPE gsnAlloc)
  630. {
  631. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  632. while (vrComdat != VNIL)
  633. {
  634. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  635. // Fetch COMDAT descriptor from VM
  636. apropComdat->ac_ra += startOff;
  637. apropComdat->ac_gsn = gsnAlloc;
  638. vrComdat = apropComdat->ac_concat;
  639. }
  640. }
  641. /*** SizeOfComDat - return the size of COMDAT data
  642. *
  643. * Purpose:
  644. * Calculate the size of COMDAT data block. Takes into account the initial
  645. * offset from the COMDAT symbol and concatenation records.
  646. *
  647. * Input:
  648. * vrComdat - virtual pointer to COMDAT symbol table entry
  649. *
  650. * Output:
  651. * Returns TRUE and the size of COMDAT data block in pActual, otherwise
  652. * function returns FALSE and pActual is invalid.
  653. *
  654. * Exceptions:
  655. * COMDAT data block greater then 64k and allocation in 16-bit segment
  656. * - issue error and return FALSE
  657. * COMDAT data block grater then 4Gb - issue error and return FALSE
  658. *
  659. * Notes:
  660. * None.
  661. *
  662. *************************************************************************/
  663. LOCAL WORD NEAR SizeOfComDat(RBTYPE vrComdat, DWORD *pActual)
  664. {
  665. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  666. APROPSNPTR apropSn; // Pointer to COMDAT explicit segment
  667. long raInit; // Initial offset from COMDAT symbol
  668. DWORD sizeTotal; // Total size of data blocks
  669. WORD f16bitAlloc; // TRUE if allocation in 16-bit segment
  670. RBTYPE vrTmp;
  671. *pActual = 0L;
  672. raInit = -1L;
  673. sizeTotal= 0L;
  674. f16bitAlloc = FALSE;
  675. vrTmp = vrComdat;
  676. while (vrTmp != VNIL)
  677. {
  678. apropComdat = (APROPCOMDATPTR ) FetchSym(vrTmp, FALSE);
  679. // Fetch COMDAT descriptor from VM
  680. if (raInit == -1L)
  681. raInit = apropComdat->ac_ra;// Remember initial offset
  682. else if (apropComdat->ac_ra < sizeTotal)
  683. sizeTotal = apropComdat->ac_ra;
  684. // Correct size for overlaping blocks
  685. if (sizeTotal + apropComdat->ac_size < sizeTotal)
  686. {
  687. // Oops !!! more then 4Gb
  688. OutError(ER_size4Gb, 1 + GetPropName(apropComdat));
  689. return(FALSE);
  690. }
  691. sizeTotal += apropComdat->ac_size;
  692. vrTmp = apropComdat->ac_concat;
  693. }
  694. sizeTotal += raInit;
  695. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  696. // Refetch COMDAT descriptor from VM
  697. if (apropComdat->ac_gsn)
  698. {
  699. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[apropComdat->ac_gsn],FALSE);
  700. // Fetch SEGDEF from virtual memory
  701. #if NOT EXE386
  702. if (!Is32BIT(apropSn->as_flags))
  703. f16bitAlloc = TRUE;
  704. #endif
  705. }
  706. else
  707. f16bitAlloc = (WORD) ((ALLOC_TYPE(apropComdat->ac_selAlloc) == CODE16) ||
  708. (ALLOC_TYPE(apropComdat->ac_selAlloc) == DATA16));
  709. if (f16bitAlloc && sizeTotal > LXIVK)
  710. {
  711. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  712. OutError(ER_badsize, 1 + GetPropName(apropComdat));
  713. return(FALSE);
  714. }
  715. *pActual = sizeTotal;
  716. return(TRUE);
  717. }
  718. /*** DoAligment - self-explanatory
  719. *
  720. * Purpose:
  721. * Given the aligment type round the value to the specific boundary.
  722. *
  723. * Input:
  724. * value - value to align
  725. * align - aligment type
  726. *
  727. * Output:
  728. * Returns the aligned value.
  729. *
  730. * Exceptions:
  731. * Unknow aligment type - do nothing.
  732. *
  733. * Notes:
  734. * None.
  735. *
  736. *************************************************************************/
  737. LOCAL RATYPE NEAR DoAligment(RATYPE value, WORD align)
  738. {
  739. if (align == ALGNWRD)
  740. value = (~0L<<1) & (value + (1<<1) - 1);
  741. // Round size up to word boundary
  742. #if OMF386
  743. else if (align == ALGNDBL)
  744. value = (~0L<<2) & (value + (1<<2) - 1);
  745. #endif // Round size up to double boundary
  746. else if (align == ALGNPAR)
  747. value = (~0L<<4) & (value + (1<<4) - 1);
  748. // Round size up to para. boundary
  749. else if (align == ALGNPAG)
  750. value = (~0L<<8) & (value + (1<<8) - 1);
  751. // Round size up to page boundary
  752. return(value);
  753. }
  754. /*** DoAllocation - palce COMDAT inside given segment
  755. *
  756. * Purpose:
  757. * Perform actual COMDAT allocation in given segment. Adjust COMDAT
  758. * position according to the segment or COMDAT (if specified) aligment.
  759. *
  760. * Input:
  761. * gsnAlloc - allocation segment global index
  762. * gsnSize - current segment size
  763. * vrComdat - virtual pointer to COMDAT descriptor
  764. * comdatSize - comdat size
  765. *
  766. * Output:
  767. * Function returns the new segment size. As a side effect the COMDAT
  768. * descriptor is updated to reflect its allocation and the matching
  769. * PUBDEF is entered into symbol table.
  770. *
  771. * Exceptions:
  772. * None.
  773. *
  774. * Notes:
  775. * After allocation the field ac_size is the size of the whole
  776. * COMDAT allocation including all concatenated records, so don't use
  777. * it for determinig the size of this COMDAT record..
  778. *
  779. *************************************************************************/
  780. LOCAL DWORD NEAR DoAllocation(SNTYPE gsnAlloc, DWORD size,
  781. RBTYPE vrComdat, DWORD comdatSize)
  782. {
  783. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  784. APROPSNPTR apropSn; // Pointer to COMDAT segment
  785. APROPNAMEPTR apropName; // Symbol table entry for public name
  786. WORD comdatAlloc; // Allocation criteria
  787. WORD comdatAlign; // COMDAT alignment
  788. WORD align; // Alignment type
  789. WORD f16bitAlloc; // TRUE if allocation in 16-bit segment
  790. WORD fCode; // TRUE if allocation in code segment
  791. GRTYPE comdatGgr; // Global group index
  792. RATYPE comdatRa; // Offset in logical segmet
  793. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  794. if (IsALLOCATED(apropComdat->ac_flags)
  795. #if OVERLAYS
  796. || (fOverlays && (apropComdat->ac_iOvl != iOvlCur))
  797. #endif
  798. )
  799. return(size);
  800. #if TCE
  801. if (fTCE && !apropComdat->ac_fAlive)
  802. {
  803. #if TCE_DEBUG
  804. fprintf(stdout, "\r\nComdat '%s' not included due to TCE ",
  805. 1+GetPropName(apropComdat));
  806. #endif
  807. apropComdat->ac_flags = apropComdat->ac_flags & (!REFERENCED_BIT);
  808. return(size);
  809. }
  810. #endif
  811. comdatAlloc = (WORD) (ALLOC_TYPE(apropComdat->ac_selAlloc));
  812. comdatAlign = apropComdat->ac_align;
  813. comdatGgr = apropComdat->ac_ggr;
  814. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnAlloc],FALSE);
  815. fCode = (WORD) IsCodeFlg(apropSn->as_flags);
  816. if (comdatAlign)
  817. align = comdatAlign;
  818. else
  819. align = (WORD) ((apropSn->as_tysn >> 2) & 7);
  820. size = DoAligment(size, align);
  821. if (comdatAlloc == CODE16 || comdatAlloc == DATA16)
  822. f16bitAlloc = TRUE;
  823. #if NOT EXE386
  824. else if (!Is32BIT(apropSn->as_flags))
  825. f16bitAlloc = TRUE;
  826. #endif
  827. else
  828. f16bitAlloc = FALSE;
  829. if (SegSizeOverflow(size, comdatSize, f16bitAlloc, fCode))
  830. {
  831. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  832. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnAlloc],FALSE);
  833. Fatal(ER_nospace, 1 + GetPropName(apropComdat), 1 + GetPropName(apropSn));
  834. }
  835. else
  836. {
  837. AdjustOffsets(vrComdat, size, gsnAlloc);
  838. size += comdatSize;
  839. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  840. comdatRa = apropComdat->ac_ra;
  841. apropComdat->ac_flags |= ALLOCATED_BIT;
  842. apropComdat->ac_size = comdatSize;
  843. if (apropComdat->ac_pubSym != VNIL)
  844. {
  845. apropName = (APROPNAMEPTR ) FetchSym(apropComdat->ac_pubSym, TRUE);
  846. apropName->an_ggr = comdatGgr;
  847. apropName->an_gsn = gsnAlloc;
  848. apropName->an_ra = comdatRa;
  849. }
  850. else
  851. Fatal(ER_unalloc, 1 + GetPropName(apropComdat));
  852. }
  853. return(size);
  854. }
  855. /*** AllocComDat - allocate COMDATs
  856. *
  857. * Purpose:
  858. * Allocate COMDATs in the final memory image. First start with ordered
  859. * allocation - in .DEF file we saw the list of procedures. Next allocate
  860. * explicitly assinged COMDATs to specific logical segments. And finally
  861. * allocate the rest of COMDATs creating as many as necessary segments
  862. * to hold all allocations.
  863. *
  864. * Input:
  865. * No ecplicit value is passed - I love this - side effects forever.
  866. * In the good linker tradition of using global variables, here is the
  867. * list of globals used by this function:
  868. *
  869. * mpgsnaprop - table mapping global segment index to symbol table entry
  870. * gsnMac - maximum global segment index
  871. *
  872. * Output:
  873. * No explicit value is returned - didn't I tell you - side effects forever.
  874. * So, the side effect of this function is the allocation of COMDATs in the
  875. * appropriate logical segments. The offset fields in the COMDAT descriptor
  876. * (ac_ra) now reflect the final posiotion of data block associated with the
  877. * COMDAT symbol inside given logical segment. The sizes of appropriate
  878. * segments are updated to reflect allocation of COMDATs. For every COMDAT
  879. * symbol there is a matching PUBDEF created by this function, so in pass2
  880. * linker can resolve correctly all references (via fixups to EXTDEF with
  881. * the COMDAT name) to COMDAT symbols.
  882. *
  883. * Exceptions:
  884. * No space in explicitly designated segment for COMDAT - print error
  885. * message and skip COMDAT; probably in pass2 user will see many
  886. * unresolved externals.
  887. *
  888. * Notes:
  889. * This function MUST be called before AssignAddresses. Otherwise there
  890. * will be no spcase for COMDAT allocation, because logical segments will
  891. * packed into physical ones.
  892. *
  893. *************************************************************************/
  894. void NEAR AllocComDat(void)
  895. {
  896. SNTYPE gsn;
  897. RBTYPE vrComdat; // Virtual pointer to COMDAT descriptor
  898. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  899. APROPSNPTR apropSn; // Pointer to COMDAT explicit segment
  900. RATYPE gsnSize; // Size of explicit segment
  901. DWORD comdatSize; // COMDAT data block size
  902. APROPCOMDAT comdatDsc; // COMDAT symbol table descriptor
  903. APROPFILEPTR apropFile; // Pointer to file entry
  904. APROPNAMEPTR apropName; // Pointer to matching PUBDEF
  905. RBTYPE vrFileNext; // Virtual pointer to prop list of next file
  906. #if COMDATDEBUG
  907. DisplayComdats("BEFORE allocation", FALSE);
  908. #endif
  909. #if TCE
  910. APROPCOMDATPTR apropMain;
  911. // Do Transitive Comdat Elimination (TCE)
  912. if(fTCE)
  913. {
  914. apropMain = PropSymLookup("\5_main", ATTRCOMDAT, FALSE);
  915. if(apropMain)
  916. AddTceEntryPoint(apropMain);
  917. #if TCE_DEBUG
  918. else
  919. fprintf(stdout, "\r\nUnable to find block '_main' ");
  920. #endif
  921. apropMain = PropSymLookup("\7WINMAIN", ATTRCOMDAT, FALSE);
  922. if(apropMain)
  923. AddTceEntryPoint(apropMain);
  924. #if TCE_DEBUG
  925. else
  926. fprintf(stdout, "\r\nUnable to find block 'WINMAIN' ");
  927. #endif
  928. apropMain = PropSymLookup("\7LIBMAIN", ATTRCOMDAT, FALSE);
  929. if(apropMain)
  930. AddTceEntryPoint(apropMain);
  931. #if TCE_DEBUG
  932. else
  933. fprintf(stdout, "\r\nUnable to find block 'LIBMAIN' ");
  934. #endif
  935. PerformTce();
  936. }
  937. #endif
  938. // Loop thru overlays - for non overlayed executables
  939. // the following loop is executed only once - iovMac = 1
  940. #if OVERLAYS
  941. for (iOvlCur = 0; iOvlCur < iovMac; iOvlCur++)
  942. {
  943. #endif
  944. // Do ordered allocation
  945. for (vrComdat = procOrder; vrComdat != VNIL; vrComdat = comdatDsc.ac_order)
  946. {
  947. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  948. comdatDsc = *apropComdat;
  949. if (!(comdatDsc.ac_flags & DEFINED_BIT))
  950. {
  951. OutWarn(ER_notdefcomdat, 1 + GetPropName(apropComdat));
  952. continue;
  953. }
  954. #if OVERLAYS
  955. if (fOverlays && (apropComdat->ac_iOvl != NOTIOVL) &&
  956. (apropComdat->ac_iOvl != iOvlCur))
  957. continue;
  958. #endif
  959. if (fPackFunctions && !IsREFERENCED(apropComdat->ac_flags))
  960. continue;
  961. if (SizeOfComDat(vrComdat, &comdatSize))
  962. {
  963. if (ALLOC_TYPE(comdatDsc.ac_selAlloc) == EXPLICIT)
  964. {
  965. gsn = comdatDsc.ac_gsn;
  966. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn], FALSE);
  967. gsnSize = apropSn->as_cbMx;
  968. gsnSize = DoAllocation(gsn, gsnSize, vrComdat, comdatSize);
  969. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn], TRUE);
  970. apropSn->as_cbMx = gsnSize;
  971. }
  972. else if (ALLOC_TYPE(comdatDsc.ac_selAlloc) != ALLOC_UNKNOWN)
  973. AllocAnonymus(vrComdat);
  974. }
  975. }
  976. // Do explicit allocation
  977. for (gsn = 1; gsn < gsnMac; gsn++)
  978. {
  979. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn],FALSE);
  980. // Fetch SEGDEF from virtual memory
  981. #if OVERLAYS
  982. if (fOverlays && apropSn->as_iov != iOvlCur)
  983. continue;
  984. #endif
  985. if (apropSn->as_ComDat != VNIL)
  986. {
  987. gsnSize = apropSn->as_cbMx;
  988. for (vrComdat = apropSn->as_ComDat;
  989. vrComdat != VNIL && SizeOfComDat(vrComdat, &comdatSize);
  990. vrComdat = apropComdat->ac_sameSeg)
  991. {
  992. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  993. if ((!fPackFunctions || IsREFERENCED(apropComdat->ac_flags)) &&
  994. !IsALLOCATED(apropComdat->ac_flags))
  995. {
  996. gsnSize = DoAllocation(gsn, gsnSize, vrComdat, comdatSize);
  997. }
  998. }
  999. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn], TRUE);
  1000. apropSn->as_cbMx = gsnSize;
  1001. }
  1002. }
  1003. // Now allocate the rest of COMDATs
  1004. vrFileNext = rprop1stFile; // Next file to look at is first
  1005. while (vrFileNext != VNIL) // Loop to process objects
  1006. {
  1007. apropFile = (APROPFILEPTR ) FetchSym(vrFileNext, FALSE);
  1008. // Fetch table entry from VM
  1009. vrFileNext = apropFile->af_FNxt;
  1010. // Get pointer to next file
  1011. for (vrComdat = apropFile->af_ComDat;
  1012. vrComdat != VNIL;
  1013. vrComdat = apropComdat->ac_sameFile)
  1014. {
  1015. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  1016. // Fetch table entry from VM
  1017. #if OVERLAYS
  1018. if (fOverlays && (apropComdat->ac_iOvl != NOTIOVL) &&
  1019. (apropComdat->ac_iOvl != iOvlCur))
  1020. continue;
  1021. #endif
  1022. if (!IsREFERENCED(apropComdat->ac_flags))
  1023. {
  1024. // Mark matching PUBDEF as unreferenced, so it shows
  1025. // in the map file
  1026. apropName = (APROPNAMEPTR) FetchSym(apropComdat->ac_pubSym, TRUE);
  1027. apropName->an_flags |= FUNREF;
  1028. }
  1029. if ((!fPackFunctions || IsREFERENCED(apropComdat->ac_flags)) &&
  1030. !IsALLOCATED(apropComdat->ac_flags))
  1031. {
  1032. if (ALLOC_TYPE(apropComdat->ac_selAlloc) != ALLOC_UNKNOWN)
  1033. {
  1034. AllocAnonymus(vrComdat);
  1035. }
  1036. }
  1037. }
  1038. }
  1039. // Close all open segments for anonymus allocation
  1040. if (curGsnCode16)
  1041. {
  1042. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[curGsnCode16], TRUE);
  1043. apropSn->as_cbMx = curCodeSize16;
  1044. curGsnCode16 = 0;
  1045. curCodeSize16 = 0;
  1046. }
  1047. if (curGsnData16)
  1048. {
  1049. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[curGsnData16], TRUE);
  1050. apropSn->as_cbMx = curDataSize16;
  1051. curGsnData16 = 0;
  1052. curDataSize16 = 0;
  1053. }
  1054. #if EXE386
  1055. if (curGsnCode32)
  1056. {
  1057. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[curGsnCode32], TRUE);
  1058. apropSn->as_cbMx = curCodeSize32;
  1059. curGsnCode32 = 0;
  1060. curCodeSize32 = 0;
  1061. }
  1062. if (curGsnData32)
  1063. {
  1064. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[curGsnData32], TRUE);
  1065. apropSn->as_cbMx = curDataSize32;
  1066. curGsnData32 = 0;
  1067. curDataSize32 = 0;
  1068. }
  1069. #endif
  1070. #if OVERLAYS
  1071. }
  1072. #endif
  1073. #if COMDATDEBUG
  1074. DisplayComdats("AFTER allocation", FALSE);
  1075. #endif
  1076. }
  1077. /*** NewSegment - open new COMDAT segment
  1078. *
  1079. * Purpose:
  1080. * Open new linker defined segment. The name of the segment is created
  1081. * according to the following template:
  1082. *
  1083. * COMDAT_SEG<nnn>
  1084. *
  1085. * where - <nnn> is the segment number.
  1086. * If there was previous segment, then update its size.
  1087. *
  1088. * Input:
  1089. * gsnPrev - previous segment global index
  1090. * sizePrev - previous segment size
  1091. * allocKind - segment type to open
  1092. *
  1093. * Output:
  1094. * Function returns the new global segment index in gsnPrev and
  1095. * new segment aligment;
  1096. *
  1097. * Exceptions:
  1098. * To many logical segments - error message displayed by GenSeg
  1099. * and abort.
  1100. *
  1101. * Notes:
  1102. * None.
  1103. *
  1104. *************************************************************************/
  1105. LOCAL WORD NEAR NewSegment(SNTYPE *gsnPrev, DWORD *sizePrev, WORD allocKind)
  1106. {
  1107. static int segNo = 1; // Segment number
  1108. char segName[20]; // Segment name - no names longer then
  1109. // 20 chars since we are generating them
  1110. APROPSNPTR apropSn; // Pointer to COMDAT segment
  1111. if (*gsnPrev)
  1112. {
  1113. // Update previous segment size
  1114. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[*gsnPrev], TRUE);
  1115. apropSn->as_cbMx = *sizePrev;
  1116. *sizePrev = 0L;
  1117. }
  1118. // Create segment name
  1119. strcpy(segName, COMDAT_SEG_NAME);
  1120. _itoa(segNo, &segName[COMDAT_NAME_LEN], 10);
  1121. segName[0] = (char) strlen(&segName[1]);
  1122. ++segNo;
  1123. if (allocKind == CODE16 || allocKind == CODE32)
  1124. {
  1125. apropSn = GenSeg(segName, "\004CODE", GRNIL, (FTYPE) TRUE);
  1126. apropSn->as_flags = dfCode; // Use default code flags
  1127. }
  1128. else
  1129. {
  1130. apropSn = GenSeg(segName,
  1131. allocKind == DATA16 ? "\010FAR_DATA" : "\004DATA",
  1132. GRNIL, (FTYPE) TRUE);
  1133. apropSn->as_flags = dfData; // Use default data flags
  1134. }
  1135. #if OVERLAYS
  1136. apropSn->as_iov = (IOVTYPE) NOTIOVL;
  1137. CheckOvl(apropSn, iOvlCur);
  1138. #endif
  1139. // Set segment aligment
  1140. #if EXE386
  1141. apropSn->as_tysn = DWORDPUBSEG; // DWORD
  1142. #else
  1143. apropSn->as_tysn = PARAPUBSEG; // Paragraph
  1144. #endif
  1145. *gsnPrev = apropSn->as_gsn;
  1146. apropSn->as_fExtra |= COMDAT_SEG;
  1147. return((WORD) ((apropSn->as_tysn >> 2) & 7));
  1148. }
  1149. /*** SegSizeOverflow - check the segment size
  1150. *
  1151. * Purpose:
  1152. * Check if the allocation of the COMDAT in a given segment will
  1153. * overflow its size limits. The segment size limit can be changed
  1154. * by the /PACKCODE:<nnn> or /PACKDATA:<nnn> options. If the /PACKxxxx
  1155. * options are not used the limits are:
  1156. *
  1157. * - 64k - 36 - for 16-bit code segments
  1158. * - 64k - for 16-bit data segments
  1159. * - 4Gb - for 32-bit code/data segments
  1160. *
  1161. * Input:
  1162. * segSize - segment size
  1163. * comdatsize - COMDAT size
  1164. * f16bit - TRUE if 16-bit segment
  1165. * fCode - TRUE if code segment
  1166. *
  1167. * Output:
  1168. * Function returns TRUE if size overflow, otherwise function
  1169. * returns FALSE.
  1170. *
  1171. * Exceptions:
  1172. * None.
  1173. *
  1174. * Notes:
  1175. * None.
  1176. *
  1177. *************************************************************************/
  1178. LOCAL WORD NEAR SegSizeOverflow(DWORD segSize, DWORD comdatSize,
  1179. WORD f16bit, WORD fCode)
  1180. {
  1181. DWORD limit;
  1182. if (fCode)
  1183. {
  1184. if (packLim)
  1185. limit = packLim;
  1186. else if (f16bit)
  1187. limit = LXIVK - 36;
  1188. else
  1189. limit = CBMAXSEG32;
  1190. }
  1191. else
  1192. {
  1193. if (DataPackLim)
  1194. limit = DataPackLim;
  1195. else if (f16bit)
  1196. limit = LXIVK;
  1197. else
  1198. limit = CBMAXSEG32;
  1199. }
  1200. return(limit - comdatSize < segSize);
  1201. }
  1202. /*** AttachComdat - add comdat to the segment list
  1203. *
  1204. * Purpose:
  1205. * Add comdat descriptor to the list of comdats allocated in the
  1206. * given logical segment. Check for overlay assigment missmatch
  1207. * and report problems.
  1208. *
  1209. * Input:
  1210. * vrComdat - virtual pointer to the comdat descriptor
  1211. * gsn - global logical segment index
  1212. *
  1213. * Output:
  1214. * No explicit value is returned. As a side effect the comdat
  1215. * descriptor is placed on the allocation list of given segment.
  1216. *
  1217. * Exceptions:
  1218. * None.
  1219. *
  1220. * Notes:
  1221. * None.
  1222. *
  1223. *************************************************************************/
  1224. void AttachComdat(RBTYPE vrComdat, SNTYPE gsn)
  1225. {
  1226. RBTYPE vrTmp; // Virtual pointer to COMDAT symbol table entry
  1227. APROPSNPTR apropSn; // Pointer to COMDAT segment if explicit allocation
  1228. APROPCOMDATPTR apropComdat; // Pointer to symbol table descriptor
  1229. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  1230. // Attach this COMDAT to its segment list
  1231. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn], TRUE);
  1232. #if OVERLAYS
  1233. if (fOverlays && (apropComdat->ac_iOvl != apropSn->as_iov))
  1234. {
  1235. if (apropComdat->ac_iOvl != NOTIOVL)
  1236. OutWarn(ER_badcomdatovl, 1 + GetPropName(apropComdat),
  1237. apropComdat->ac_iOvl, apropSn->as_iov);
  1238. apropComdat->ac_iOvl = apropSn->as_iov;
  1239. }
  1240. #endif
  1241. if (apropSn->as_ComDat == VNIL)
  1242. {
  1243. apropSn->as_ComDat = vrComdat;
  1244. apropSn->as_ComDatLast = vrComdat;
  1245. apropComdat->ac_sameSeg = VNIL;
  1246. }
  1247. else
  1248. {
  1249. // Because COMDATs can be attached to a given segment in the
  1250. // .DEF file and later in the .OBJ file, we have to check
  1251. // if a given comdat is already on the segment list
  1252. for (vrTmp = apropSn->as_ComDat; vrTmp != VNIL;)
  1253. {
  1254. if (vrTmp == vrComdat)
  1255. return;
  1256. apropComdat = (APROPCOMDATPTR ) FetchSym(vrTmp, FALSE);
  1257. vrTmp = apropComdat->ac_sameSeg;
  1258. }
  1259. // Add new COMDAT to the segment list
  1260. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn], TRUE);
  1261. vrTmp = apropSn->as_ComDatLast;
  1262. apropSn->as_ComDatLast = vrComdat;
  1263. apropComdat = (APROPCOMDATPTR ) FetchSym(vrTmp, TRUE);
  1264. apropComdat->ac_sameSeg = vrComdat;
  1265. }
  1266. }
  1267. /*** AllocAnonymus - allocate COMDATs without explicit segment
  1268. *
  1269. * Purpose:
  1270. * Allocate COMDATs without explicit segment. Create as many as necessary
  1271. * code/data segments to hold all COMDATs.
  1272. *
  1273. * Input:
  1274. * vrComdat - virtual pointer to symbol table entry for COMDAT name
  1275. *
  1276. * Output:
  1277. * No explicit value is returned. As a side effect the COMDAT symbol is
  1278. * allocated and matching public symbol is created. If necessary
  1279. * appropriate segment is defined.
  1280. *
  1281. * Exceptions:
  1282. * None.
  1283. *
  1284. * Notes:
  1285. * None.
  1286. *
  1287. *************************************************************************/
  1288. LOCAL void NEAR AllocAnonymus(RBTYPE vrComdat)
  1289. {
  1290. WORD comdatAlloc; // Allocation type
  1291. WORD comdatAlign; // COMDAT aligment
  1292. WORD align;
  1293. DWORD comdatSize; // COMDAT data block size
  1294. APROPCOMDATPTR apropComdat; // Real pointer to COMDAT descriptor
  1295. static WORD segAlign16; // Aligment for 16-bit segments
  1296. #if EXE386
  1297. static WORD segAlign32; // Aligment for 32-bit segments
  1298. #endif
  1299. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  1300. comdatAlloc = (WORD) (ALLOC_TYPE(apropComdat->ac_selAlloc));
  1301. comdatAlign = apropComdat->ac_align;
  1302. if (SizeOfComDat(vrComdat, &comdatSize))
  1303. {
  1304. if (comdatAlign)
  1305. align = comdatAlign;
  1306. else
  1307. {
  1308. #if EXE386
  1309. if (comdatAlloc == CODE32 || comdatAlloc == DATA32)
  1310. align = segAlign32;
  1311. else
  1312. #endif
  1313. align = segAlign16;
  1314. }
  1315. switch (comdatAlloc)
  1316. {
  1317. case CODE16:
  1318. if (!curGsnCode16 ||
  1319. SegSizeOverflow(DoAligment(curCodeSize16, align), comdatSize, TRUE, TRUE))
  1320. {
  1321. // Open new 16-bit code segment
  1322. segAlign16 = NewSegment(&curGsnCode16, &curCodeSize16, comdatAlloc);
  1323. }
  1324. curCodeSize16 = DoAllocation(curGsnCode16, curCodeSize16, vrComdat, comdatSize);
  1325. AttachComdat(vrComdat, curGsnCode16);
  1326. break;
  1327. case DATA16:
  1328. if (!curGsnData16 ||
  1329. SegSizeOverflow(DoAligment(curDataSize16, align), comdatSize, TRUE, FALSE))
  1330. {
  1331. // Open new 16-bit data segment
  1332. segAlign16 = NewSegment(&curGsnData16, &curDataSize16, comdatAlloc);
  1333. }
  1334. curDataSize16 = DoAllocation(curGsnData16, curDataSize16, vrComdat, comdatSize);
  1335. AttachComdat(vrComdat, curGsnData16);
  1336. break;
  1337. #if EXE386
  1338. case CODE32:
  1339. if (!curGsnCode32 ||
  1340. SegSizeOverflow(DoAligment(curCodeSize32, align), comdatSize, FALSE, TRUE))
  1341. {
  1342. // Open new 32-bit code segment
  1343. segAlign32 = NewSegment(&curGsnCode32, &curCodeSize32, comdatAlloc);
  1344. }
  1345. curCodeSize32 = DoAllocation(curGsnCode32, curCodeSize32, vrComdat, comdatSize);
  1346. AttachComdat(vrComdat, curGsnCode32);
  1347. break;
  1348. case DATA32:
  1349. if (!curGsnData32 ||
  1350. SegSizeOverflow(DoAligment(curDataSize32, align), comdatSize, FALSE, FALSE))
  1351. {
  1352. // Open new 32-bit data segment
  1353. segAlign32 = NewSegment(&curGsnData32, &curDataSize32, comdatAlloc);
  1354. }
  1355. curDataSize32 = DoAllocation(curGsnData32, curDataSize32, vrComdat, comdatSize);
  1356. AttachComdat(vrComdat, curGsnData32);
  1357. break;
  1358. #endif
  1359. default:
  1360. OutError(ER_badalloc, 1 + GetPropName(apropComdat));
  1361. return;
  1362. }
  1363. }
  1364. }
  1365. /*** FixComdatRa - shift by 16 bytes COMDATs allocated in _TEXT
  1366. *
  1367. * Purpose:
  1368. * Follow the /DOSSEG convention for logical segment _TEXT,
  1369. * and shift up by 16 bytes all COMDATS allocated in this segment.
  1370. *
  1371. * Input:
  1372. * gsnText - _TEXT global segment index - global variable
  1373. *
  1374. * Output:
  1375. * No explicit value is returned. As a side effect the offset of
  1376. * the COMDAT allocated in _TEXT is increased by 16.
  1377. *
  1378. * Exceptions:
  1379. * None.
  1380. *
  1381. * Notes:
  1382. * None.
  1383. *
  1384. *************************************************************************/
  1385. void FixComdatRa(void)
  1386. {
  1387. APROPSNPTR apropSn; // Pointer to COMDAT explicit segment
  1388. RBTYPE vrComdat; // Virtual pointer to COMDAT descriptor
  1389. RBTYPE vrConcat; // Virtual pointer to concatenated records
  1390. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  1391. RATYPE raShift;
  1392. apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsnText], FALSE);
  1393. // Fetch SEGDEF from virtual memory
  1394. raShift = mpgsndra[gsnText] - mpsegraFirst[mpgsnseg[gsnText]];
  1395. for (vrComdat = apropSn->as_ComDat; vrComdat != VNIL;)
  1396. {
  1397. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, TRUE);
  1398. vrComdat = apropComdat->ac_sameSeg;
  1399. if (fPackFunctions && !IsREFERENCED(apropComdat->ac_flags))
  1400. continue;
  1401. apropComdat->ac_ra += raShift;
  1402. // Search concatenation list
  1403. for (vrConcat = apropComdat->ac_concat; vrConcat != VNIL; vrConcat = apropComdat->ac_concat)
  1404. {
  1405. apropComdat = (APROPCOMDATPTR ) FetchSym(vrConcat, TRUE);
  1406. apropComdat->ac_ra += raShift;
  1407. }
  1408. }
  1409. }
  1410. /*** UpdateComdatContrib - update COMDATs contributions
  1411. *
  1412. * Purpose:
  1413. * For every file with COMDATs add contribution information to the
  1414. * .ILK file. Some COMDATs are allocated in named segments, some
  1415. * in anonynus segments created by linker. The ILINK needs to know
  1416. * how much given .OBJ file contributed to given logical segment.
  1417. * Since the COMDAT contributions are not visible while processing
  1418. * object files in pass one, this function is required to update
  1419. * contribution information. Also if /MAP:FULL i used then add
  1420. * COMDATs contributions to the map file information
  1421. *
  1422. * Input:
  1423. * - fIlk - TRUE if updating ILINK information
  1424. * - fMap - TRUE if updating MAP file information
  1425. * - rprop1stFile - head of .OBJ file list
  1426. * - vrpropFile - pointer to the current .OBJ
  1427. *
  1428. * Output:
  1429. * No explicit value is returned.
  1430. *
  1431. * Exceptions:
  1432. * None.
  1433. *
  1434. * Notes:
  1435. * This function has to be called after pass 2, so all non-COMDAT
  1436. * contributions are already recorded. This allows us to detect the
  1437. * fact that named COMDAT allocation (explicit segment) has increased
  1438. * contribution to given logical segment by the size of COMDATs.
  1439. *
  1440. *************************************************************************/
  1441. void UpdateComdatContrib(
  1442. #if ILINK
  1443. WORD fIlk,
  1444. #endif
  1445. WORD fMap)
  1446. {
  1447. APROPFILEPTR apropFile; // Pointer to file entry
  1448. RBTYPE vrFileNext; // Virtual pointer to prop list of next file
  1449. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  1450. RBTYPE vrComdat; // Virtual pointer to COMDAT descriptor
  1451. SNTYPE gsnCur; // Global segment index of current segment
  1452. DWORD sizeCur; // Current segment size
  1453. RATYPE raInit; // Initial offset of the first COMDAT
  1454. // allocated in the given segment
  1455. #if ILINK
  1456. RATYPE raEnd; // End offset
  1457. #endif
  1458. vrFileNext = rprop1stFile; // Next file to look at is first
  1459. while (vrFileNext != VNIL) // Loop to process objects
  1460. {
  1461. vrpropFile = vrFileNext; // Make next file the current file
  1462. apropFile = (APROPFILEPTR ) FetchSym(vrFileNext, FALSE);
  1463. // Fetch table entry from VM
  1464. vrFileNext = apropFile->af_FNxt;// Get pointer to next file
  1465. vrComdat = apropFile->af_ComDat;
  1466. #if ILINK
  1467. imodFile = apropFile->af_imod;
  1468. #endif
  1469. sizeCur = 0L;
  1470. while (vrComdat != VNIL)
  1471. {
  1472. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  1473. // Fetch table entry from VM
  1474. vrComdat = apropComdat->ac_sameFile;
  1475. if (fPackFunctions && !IsREFERENCED(apropComdat->ac_flags))
  1476. continue;
  1477. raInit = apropComdat->ac_ra;
  1478. gsnCur = apropComdat->ac_gsn;
  1479. #if ILINK
  1480. raEnd = raInit + apropComdat->ac_size;
  1481. #endif
  1482. sizeCur = apropComdat->ac_size;
  1483. // Save information about contributions
  1484. #if ILINK
  1485. if (fIlk)
  1486. AddContribution(gsnCur, (WORD) raInit, (WORD) raEnd, cbPadCode);
  1487. #endif
  1488. if (fMap)
  1489. AddContributor(gsnCur, raInit, sizeCur);
  1490. }
  1491. }
  1492. }
  1493. #if SYMDEB
  1494. /*** DoComdatDebugging - notify CodeView about segments with COMDATs
  1495. *
  1496. * Purpose:
  1497. * CodeView expects in sstModules subsection an information about code
  1498. * segments defined in the given object module (.OBJ file). When COMDATs
  1499. * are present linker has no way of figuring this out in pass 1, because
  1500. * there is no code segment definitions (all COMDATs have anonymus
  1501. * allocation) or the code segments have size zero (explicit allocation).
  1502. * This function is called after the COMDAT allocation is performed and
  1503. * segments have assigned their addresses. The list of .OBJ files is
  1504. * traversed and for each .OBJ file the list of COMDATs defined in this
  1505. * file is examined and the appropriate code segment information is
  1506. * stored for CodeView.
  1507. *
  1508. * Input:
  1509. * No explicit value is passed. The following global variables are used:
  1510. *
  1511. * rprop1stFile - head of .OBJ file list
  1512. * vrpropFile - pointer to the current .OBJ
  1513. *
  1514. * Output:
  1515. * No explicit value is returned.
  1516. *
  1517. * Exceptions:
  1518. * None.
  1519. *
  1520. * Notes:
  1521. * None.
  1522. *
  1523. *************************************************************************/
  1524. void NEAR DoComdatDebugging(void)
  1525. {
  1526. APROPFILEPTR apropFile; // Pointer to file entry
  1527. RBTYPE vrFileNext; // Virtual pointer to prop list of next file
  1528. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  1529. RBTYPE vrComdat; // Virtual pointer to COMDAT descriptor
  1530. SNTYPE gsnCur; // Global segment index of current segment
  1531. RATYPE raInit; // Initial offset of the first COMDAT
  1532. // allocated in the given segment
  1533. RATYPE raEnd; // End of contributor
  1534. vrFileNext = rprop1stFile; // Next file to look at is first
  1535. while (vrFileNext != VNIL) // Loop to process objects
  1536. {
  1537. vrpropFile = vrFileNext; // Make next file the current file
  1538. apropFile = (APROPFILEPTR ) FetchSym(vrFileNext, FALSE);
  1539. // Fetch table entry from VM
  1540. vrFileNext = apropFile->af_FNxt;// Get pointer to next file
  1541. vrComdat = apropFile->af_ComDat;
  1542. while (vrComdat != VNIL)
  1543. {
  1544. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  1545. // Fetch table entry from VM
  1546. raInit = (RATYPE)-1;
  1547. raEnd = 0;
  1548. gsnCur = apropComdat->ac_gsn;
  1549. while (vrComdat != VNIL && gsnCur == apropComdat->ac_gsn)
  1550. {
  1551. if(apropComdat->ac_ra < raInit && IsALLOCATED(apropComdat->ac_flags))
  1552. raInit = apropComdat->ac_ra;
  1553. if(apropComdat->ac_ra + apropComdat->ac_size > raEnd)
  1554. raEnd = apropComdat->ac_ra + apropComdat->ac_size;
  1555. vrComdat = apropComdat->ac_sameFile;
  1556. if (vrComdat != VNIL)
  1557. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  1558. }
  1559. // Contribution to the new logical segment from this .OBJ file
  1560. SaveCode(gsnCur, raEnd - raInit, raInit);
  1561. }
  1562. }
  1563. }
  1564. #endif
  1565. /*** ComDatRc2 - process COMDAT record in pass 2
  1566. *
  1567. * Purpose:
  1568. * Process COMDAT record in pass 1. Select appropriate copy of COMDAT.
  1569. *
  1570. * Input:
  1571. * No explicit value is passed to this function. The OMF record is
  1572. * read from input file bsInput - global variable.
  1573. *
  1574. * Output:
  1575. * No explicit value is returned. Apropriate copy of COMDAT data block
  1576. * is loaded into final memory image.
  1577. *
  1578. * Exceptions:
  1579. * Unknown COMDAT name - phase error - display internal LINK error and quit
  1580. * Unallocated COMDAT - phase error - display internal LINK error and quit
  1581. *
  1582. * Notes:
  1583. * None.
  1584. *
  1585. *************************************************************************/
  1586. void NEAR ComDatRc2(void)
  1587. {
  1588. COMDATREC omfRec; // COMDAT OMF record
  1589. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  1590. WORD fRightCopy; // TRUE if we have rigth instance of COMDAT
  1591. RBTYPE vrTmp; // Temporary
  1592. char *sbName; // COMDAT symbol
  1593. AHTEPTR ahte; // Hash table entry
  1594. ReadComDat(&omfRec);
  1595. apropComdat = (APROPCOMDATPTR ) PropRhteLookup(omfRec.name, ATTRCOMDAT, FALSE);
  1596. // Look for symbol among COMDATs
  1597. ahte = (AHTEPTR) FetchSym(omfRec.name, FALSE);
  1598. sbName = 1 + GetFarSb(ahte->cch);
  1599. if (apropComdat == PROPNIL)
  1600. Fatal(ER_undefcomdat, sbName);
  1601. if (fPackFunctions && !IsREFERENCED(apropComdat->ac_flags))
  1602. {
  1603. SkipBytes((WORD) (cbRec - 1)); // Skip to checksum byte
  1604. fSkipFixups = TRUE; // Skip fixups if any
  1605. return;
  1606. }
  1607. if (!IsCONCAT(omfRec.flags))
  1608. fRightCopy = (WORD) (apropComdat->ac_obj == vrpropFile &&
  1609. apropComdat->ac_objLfa == lfaLast);
  1610. else
  1611. {
  1612. // Search concatenation list
  1613. vrTmp = apropComdat->ac_concat;
  1614. fRightCopy = FALSE;
  1615. while (vrTmp != VNIL && !fRightCopy)
  1616. {
  1617. apropComdat = (APROPCOMDATPTR ) FetchSym(vrTmp, TRUE);
  1618. vrTmp = apropComdat->ac_concat;
  1619. fRightCopy = (WORD) (apropComdat->ac_obj == vrpropFile &&
  1620. apropComdat->ac_objLfa == lfaLast);
  1621. }
  1622. }
  1623. if (fRightCopy)
  1624. {
  1625. // This is the right copy of COMDAT
  1626. if (!apropComdat->ac_gsn)
  1627. Fatal(ER_unalloc, sbName);
  1628. apropComdat->ac_flags |= SELECTED_BIT;
  1629. fSkipFixups = FALSE; // Process fixups if any
  1630. omfRec.gsn = apropComdat->ac_gsn;
  1631. omfRec.ra = apropComdat->ac_ra; // Set relative address
  1632. omfRec.flags = apropComdat->ac_flags;
  1633. vcbData = (WORD) (cbRec - 1); // set no. of data bytes in rec
  1634. if (vcbData > DATAMAX)
  1635. Fatal(ER_datarec); // Check if record too large
  1636. #if NOT RGMI_IN_PLACE
  1637. GetBytesNoLim(rgmi, vcbData); // Fill the buffer
  1638. #endif
  1639. vgsnCur = omfRec.gsn; // Set global segment index
  1640. fDebSeg = (FTYPE) ((fSymdeb) ? (((0x8000 & omfRec.gsn) != 0)) : FALSE);
  1641. // If debug option on check for debug segs
  1642. if (fDebSeg)
  1643. { // If debug segment
  1644. vraCur = omfRec.ra; // Set current relative address
  1645. vsegCur = vgsnCur = (SEGTYPE) (0x7fff & omfRec.gsn);
  1646. // Set current segment
  1647. }
  1648. else
  1649. {
  1650. // If not a valid segment, don't process datarec
  1651. #if SYMDEB
  1652. if (omfRec.gsn == 0xffff || !omfRec.gsn || mpgsnseg[omfRec.gsn] > segLast)
  1653. #else
  1654. if (!omfRec.gsn || mpgsnseg[omfRec.gsn] > segLast)
  1655. #endif
  1656. {
  1657. vsegCur = SEGNIL;
  1658. vrectData = RECTNIL;
  1659. #if RGMI_IN_PLACE
  1660. SkipBytes(vcbData); // must skip bytes for this record...
  1661. #endif
  1662. return; // Good-bye!
  1663. }
  1664. vsegCur = mpgsnseg[omfRec.gsn];
  1665. // Set current segment
  1666. vraCur = mpsegraFirst[vsegCur] + omfRec.ra;
  1667. // Set current relative address
  1668. if (IsVTABLE(apropComdat->ac_flags))
  1669. {
  1670. fFarCallTransSave = fFarCallTrans;
  1671. fFarCallTrans = (FTYPE) FALSE;
  1672. }
  1673. }
  1674. if (IsITERATED(omfRec.flags))
  1675. {
  1676. #if RGMI_IN_PLACE
  1677. rgmi = bufg;
  1678. GetBytesNoLim(rgmi, vcbData); // Fill the buffer
  1679. #endif
  1680. vrectData = LIDATA; // Simulate LIDATA
  1681. #if OSEGEXE
  1682. if(fNewExe)
  1683. {
  1684. if (vcbData >= DATAMAX)
  1685. Fatal(ER_lidata);
  1686. rlcLidata = (RLCPTR) &rgmi[(vcbData + 1) & ~1];
  1687. // Set base of fixup array
  1688. rlcCurLidata = rlcLidata;// Initialize pointer
  1689. return;
  1690. }
  1691. #endif
  1692. #if ODOS3EXE OR OIAPX286
  1693. if(vcbData > (DATAMAX / 2))
  1694. {
  1695. OutError(ER_lidata);
  1696. memset(&rgmi[vcbData],0,DATAMAX - vcbData);
  1697. }
  1698. else
  1699. memset(&rgmi[vcbData],0,vcbData);
  1700. ompimisegDstIdata = (char *) rgmi + vcbData;
  1701. #endif
  1702. }
  1703. else
  1704. {
  1705. #if RGMI_IN_PLACE
  1706. rgmi = PchSegAddress(vcbData, vsegCur, vraCur);
  1707. GetBytesNoLim(rgmi, vcbData); // Fill the buffer
  1708. #endif
  1709. vrectData = LEDATA; // Simulate LEDATA
  1710. }
  1711. if (rect & 1)
  1712. vrectData++; // Simulate 32-bit version
  1713. }
  1714. else
  1715. {
  1716. SkipBytes((WORD) (cbRec - 1)); // Skip to checksum byte
  1717. fSkipFixups = TRUE; // Skip fixups if any
  1718. }
  1719. }
  1720. #if COMDATDEBUG
  1721. #include <string.h>
  1722. /*** DisplayOne - display one COMDAT symbol table entry
  1723. *
  1724. * Purpose:
  1725. * Debug aid. Display on standard output the contents of given
  1726. * COMDAT symbol table entry.
  1727. *
  1728. * Input:
  1729. * papropName - real pointer to symbol table entry
  1730. * rhte - hash vector entry
  1731. * rprop - pointer to property cell
  1732. * fNewHte - TRUE if new proprerty list (new entry in hash vector)
  1733. *
  1734. * Output:
  1735. * No explicit value is returned.
  1736. *
  1737. * Exceptions:
  1738. * None.
  1739. *
  1740. * Notes:
  1741. * This function is in standard EnSyms format.
  1742. *
  1743. *************************************************************************/
  1744. LOCAL void DisplayOne(APROPCOMDATPTR apropName, WORD fPhysical)
  1745. {
  1746. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  1747. RBTYPE vrComdat; // Virtual pointer to COMDAT descriptor
  1748. APROPCOMDAT comdatDsc; // COMDAT descriptor
  1749. SEGTYPE seg;
  1750. FMEMCPY((char FAR *) &comdatDsc, apropName, sizeof(APROPCOMDAT));
  1751. if (fPhysical)
  1752. seg = mpgsnseg[comdatDsc.ac_gsn];
  1753. fprintf(stdout, "%s:\r\n", 1 + GetPropName(apropName));
  1754. fprintf(stdout, "ggr = %d; gsn = %d; ra = 0x%lx; size = %d\r\n",
  1755. comdatDsc.ac_ggr, comdatDsc.ac_gsn, comdatDsc.ac_ra, comdatDsc.ac_size);
  1756. if (fPhysical)
  1757. fprintf(stdout, "sa = 0x%x; ra = 0x%lx\r\n",
  1758. mpsegsa[seg], mpsegraFirst[seg] + comdatDsc.ac_ra);
  1759. fprintf(stdout, "flags = 0x%x; selAlloc = 0x%x; align = 0x%x\r\n",
  1760. comdatDsc.ac_flags, comdatDsc.ac_selAlloc, comdatDsc.ac_align);
  1761. fprintf(stdout, "data = 0x%lx; obj = 0x%lx; objLfa = 0x%lx\r\n",
  1762. comdatDsc.ac_data, comdatDsc.ac_obj, comdatDsc.ac_objLfa);
  1763. fprintf(stdout, "concat = 0x%lx; sameSeg = 0x%lx pubSym = 0x%lx\r\n",
  1764. comdatDsc.ac_concat, comdatDsc.ac_sameSeg, comdatDsc.ac_pubSym);
  1765. fprintf(stdout, "order = 0x%lx; iOvl = 0x%x\r\n",
  1766. comdatDsc.ac_order, comdatDsc.ac_iOvl);
  1767. vrComdat = comdatDsc.ac_concat;
  1768. while (vrComdat != VNIL)
  1769. {
  1770. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  1771. FMEMCPY((char FAR *) &comdatDsc, apropComdat, sizeof(APROPCOMDAT));
  1772. fprintf(stdout, " +++ ggr = %d; gsn = %d; ra = 0x%lx; size = %d\r\n",
  1773. comdatDsc.ac_ggr, comdatDsc.ac_gsn, comdatDsc.ac_ra, comdatDsc.ac_size);
  1774. if (fPhysical)
  1775. fprintf(stdout, " sa = 0x%x; ra = 0x%lx\r\n",
  1776. mpsegsa[seg], mpsegraFirst[seg] + comdatDsc.ac_ra);
  1777. fprintf(stdout, " flags = 0x%x; selAlloc = 0x%x; align = 0x%x\r\n",
  1778. comdatDsc.ac_flags, comdatDsc.ac_selAlloc, comdatDsc.ac_align);
  1779. fprintf(stdout, " data = 0x%lx; obj = 0x%lx; objLfa = 0x%lx\r\n",
  1780. comdatDsc.ac_data, comdatDsc.ac_obj, comdatDsc.ac_objLfa);
  1781. fprintf(stdout, " concat = 0x%lx; sameSeg = 0x%lx pubSym = 0x%lx\r\n",
  1782. comdatDsc.ac_concat, comdatDsc.ac_sameSeg, comdatDsc.ac_pubSym);
  1783. fprintf(stdout, " order = 0x%lx; iOvl = 0x%x\r\n",
  1784. comdatDsc.ac_order, comdatDsc.ac_iOvl);
  1785. vrComdat = comdatDsc.ac_concat;
  1786. }
  1787. fprintf(stdout, "\r\n");
  1788. fflush(stdout);
  1789. }
  1790. /*** DisplayComdats - self-expalnatory
  1791. *
  1792. * Purpose:
  1793. * Debug aid. Enumerates all COMDAT records in the linker symbol table
  1794. * displaying each entry.
  1795. *
  1796. * Input:
  1797. * title - pointer to info string.
  1798. * fPhysical - display physical addresses - allowed only if you call
  1799. * this function after AssignAddresses.
  1800. *
  1801. * Output:
  1802. * No explicit value is returned. COMDAT information is written to sdtout.
  1803. *
  1804. * Exceptions:
  1805. * None.
  1806. *
  1807. * Notes:
  1808. * None.
  1809. *
  1810. *************************************************************************/
  1811. void DisplayComdats(char *title, WORD fPhysical)
  1812. {
  1813. APROPFILEPTR apropFile; // Pointer to file entry
  1814. RBTYPE rbFileNext; // Virtual pointer to prop list of next file
  1815. APROPCOMDATPTR apropComdat; // Symbol table entry for COMDAT symbol
  1816. RBTYPE vrComdat; // Virtual pointer to COMDAT descriptor
  1817. fprintf(stdout, "\r\nDisplayComdats: %s\r\n\r\n", title);
  1818. rbFileNext = rprop1stFile; // Next file to look at is first
  1819. while (rbFileNext != VNIL) // Loop to process objects
  1820. {
  1821. apropFile = (APROPFILEPTR ) FetchSym(rbFileNext, FALSE);
  1822. // Fetch table entry from VM
  1823. rbFileNext = apropFile->af_FNxt;// Get pointer to next file
  1824. vrComdat = apropFile->af_ComDat;
  1825. if (vrComdat != VNIL)
  1826. {
  1827. fprintf(stdout, "COMDATs from file: '%s'\r\n\r\n", 1+GetPropName(apropFile));
  1828. while (vrComdat != VNIL)
  1829. {
  1830. apropComdat = (APROPCOMDATPTR ) FetchSym(vrComdat, FALSE);
  1831. // Fetch table entry from VM
  1832. vrComdat = apropComdat->ac_sameFile;
  1833. DisplayOne(apropComdat, fPhysical);
  1834. }
  1835. }
  1836. }
  1837. }
  1838. #endif
  1839. #if TCE
  1840. void AddComdatUses(APROPCOMDAT *pAC, APROPCOMDAT *pUses)
  1841. {
  1842. int i;
  1843. SYMBOLUSELIST *pA; // ac_uses of this comdat
  1844. ASSERT(pAC);
  1845. ASSERT(pUses);
  1846. ASSERT(pAC->ac_uses.pEntries);
  1847. ASSERT(pUses->ac_usedby.pEntries);
  1848. // update the ac_uses list
  1849. pA = &pAC->ac_uses;
  1850. for(i=0; i<pA->cEntries; i++) // eliminate duplicate entries
  1851. {
  1852. if((APROPCOMDAT*)pA->pEntries[i] == pUses)
  1853. return;
  1854. }
  1855. if(pA->cEntries >= pA->cMaxEntries-1)
  1856. {
  1857. #if TCE_DEBUG
  1858. fprintf(stdout,"\r\nReallocating ac_uses list of '%s'old size %d -> %d ",
  1859. 1 + GetPropName(pAC), pA->cMaxEntries, pA->cMaxEntries <<1);
  1860. #endif
  1861. pA->cMaxEntries <<= 1;
  1862. if(!(pA->pEntries= REALLOC(pA->pEntries, pA->cMaxEntries*sizeof(RBTYPE*))))
  1863. Fatal(ER_memovf);
  1864. }
  1865. pA->pEntries[pA->cEntries++] = pUses;
  1866. #if TCE_DEBUG
  1867. fprintf(stdout, "\r\nComdat '%s'uses '%s' ",
  1868. 1 + GetPropName(pAC), 1 + GetPropName(pUses));
  1869. #endif
  1870. }
  1871. void MarkAlive( APROPCOMDAT *pC )
  1872. {
  1873. int i;
  1874. SYMBOLUSELIST * pU;
  1875. APROPCOMDAT * pCtmp;
  1876. RBTYPE rhte;
  1877. pU = &pC->ac_uses;
  1878. #if TCE_DEBUG
  1879. fprintf(stdout, "\r\nMarking alive '%s', attr %d ", 1+GetPropName(pC), pC->ac_attr);
  1880. fprintf(stdout, " uses %d symbols ", pU->cEntries);
  1881. for(i=0; i<pU->cEntries; i++)
  1882. fprintf(stdout, " '%s'",1+GetPropName(pU->pEntries[i]));
  1883. fflush(stdout);
  1884. #endif
  1885. pC->ac_fAlive = TRUE;
  1886. for(i=0; i<pU->cEntries; i++)
  1887. {
  1888. pCtmp = (APROPCOMDATPTR)(pU->pEntries[i]);
  1889. if(pCtmp->ac_attr != ATTRCOMDAT)
  1890. {
  1891. // find the COMDAT descriptor, or abort
  1892. rhte = RhteFromProp((APROPPTR)pCtmp);
  1893. ASSERT(rhte);
  1894. pCtmp = PropRhteLookup(rhte, ATTRCOMDAT, FALSE);
  1895. if(!pCtmp)
  1896. {
  1897. #if TCE_DEBUG
  1898. fprintf(stdout, " comdat cell not found. ");
  1899. #endif
  1900. continue;
  1901. }
  1902. AddTceEntryPoint(pCtmp);
  1903. #if TCE_DEBUG
  1904. fprintf(stdout, "\r\nSwitching to COMDAT %s ", 1+GetPropName(pCtmp));
  1905. #endif
  1906. }
  1907. if(!pCtmp->ac_fAlive)
  1908. {
  1909. #if TCE_DEBUG
  1910. fprintf(stdout, "\r\n Recursing with '%s' ", 1+GetPropName(pCtmp));
  1911. #endif
  1912. MarkAlive(pCtmp);
  1913. }
  1914. #if TCE_DEBUG
  1915. else
  1916. fprintf(stdout,"\r\n already alive: '%s' ",1+GetPropName(pCtmp));
  1917. #endif
  1918. }
  1919. #if TCE_DEBUG
  1920. fprintf(stdout, "\r\n Marking alive finished for '%s' ",1+GetPropName(pC));
  1921. #endif
  1922. }
  1923. void PerformTce( void )
  1924. {
  1925. int i;
  1926. for(i=0; i<aEntryPoints.cEntries; i++)
  1927. MarkAlive(aEntryPoints.pEntries[i]);
  1928. }
  1929. void AddTceEntryPoint( APROPCOMDATPTR pC )
  1930. {
  1931. int i;
  1932. for(i=0; i<aEntryPoints.cEntries; i++)
  1933. {
  1934. if(aEntryPoints.pEntries[i] == pC)
  1935. return;
  1936. }
  1937. if(aEntryPoints.cEntries >= aEntryPoints.cMaxEntries -1)
  1938. {
  1939. aEntryPoints.cMaxEntries <<= 1;
  1940. aEntryPoints.pEntries = REALLOC(aEntryPoints.pEntries, aEntryPoints.cMaxEntries * sizeof(RBTYPE*));
  1941. #if TCE_DEBUG
  1942. fprintf(stdout,"\r\nREALLOCATING aEntryPoints List, new size is %d ", aEntryPoints.cMaxEntries);
  1943. #endif
  1944. }
  1945. aEntryPoints.pEntries[aEntryPoints.cEntries++] = pC;
  1946. #if TCE_DEBUG
  1947. fprintf(stdout, "\r\nNew TCE Entry point %d : %s ",
  1948. aEntryPoints.cEntries, 1+GetPropName(pC));
  1949. #endif
  1950. }
  1951. #endif