Windows NT 4.0 source code leak
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.

6139 lines
133 KiB

4 years ago
  1. /***********************************************************************
  2. * Microsoft (R) 32-Bit Incremental Linker
  3. *
  4. * Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
  5. *
  6. * File: incr.cpp
  7. *
  8. * File Comments:
  9. *
  10. * ilink routines that didn't find a place elsewhere.
  11. *
  12. ***********************************************************************/
  13. #include "link.h"
  14. // statics
  15. static PLIB plibModObjs; // linker defined lib for the modified cmdline objs
  16. static LPEXT lpextWeak = {CPEXT_WEAK, 0, 0, 0}; // list that has the weak/lazy externs
  17. static PLPEXT plpextWeak = &lpextWeak; // list that has the weak/lazy externs
  18. static LPEXT lpextMultDef = {CPEXT_MULT, 0, 0, 0}; // list that will hold potential
  19. static PLPEXT plpextMultDef = &lpextMultDef; // multiply defined syms.
  20. static PLEXT plextMovedData; // list of data externs that have moved
  21. static WORD cmods; // count of MODs in project
  22. static DWORD cReloc; // count of relocs
  23. static PGRP pgrpIdata$4;
  24. static PGRP pgrpIdata$5;
  25. static PGRP pgrpIdata$6;
  26. // globals
  27. struct ILINK_INFO
  28. {
  29. const void *pvJumpEntry;
  30. size_t cbJumpEntry;
  31. WORD address_offset;
  32. BYTE bPad;
  33. };
  34. static const ILINK_INFO *ilink_info;
  35. static const BYTE I386JmpTblEntry[] = { // jmp rel32
  36. 0xE9,
  37. 0x00, 0x00, 0x00, 0x00
  38. };
  39. static const ILINK_INFO I386_ilink = {
  40. I386JmpTblEntry,
  41. sizeof(I386JmpTblEntry),
  42. 1,
  43. X86_INT3
  44. };
  45. static const BYTE MPPCJmpTblEntry[] = { // for MacPPC
  46. 0x00, 0x00, 0x00, 0x00
  47. };
  48. static const ILINK_INFO MPPC_ilink = {
  49. MPPCJmpTblEntry,
  50. sizeof(MPPCJmpTblEntry),
  51. 0,
  52. 0 // 0xFF
  53. };
  54. static const DWORD MIPSJmpTblEntry[] = {
  55. 0x03e04025, /* or t0,ra,zero */
  56. 0x04110001, /* bgezal zero,0xc */
  57. 0x00000000, /* nop */
  58. 0x8fe90014, /* lw t1,20(ra) */
  59. 0x013f4821, /* addu t1,t1,ra */
  60. 0x25290018, /* addiu t1,t1,24 */
  61. 0x01200008, /* jr t1 */
  62. 0x0100f825, /* or ra,t0,zero */
  63. 0xdeadbeef, /* ld t5,-16657(s5) */
  64. };
  65. static const ILINK_INFO MIPS_ilink = {
  66. MIPSJmpTblEntry,
  67. sizeof(MIPSJmpTblEntry),
  68. sizeof(MIPSJmpTblEntry)-4,
  69. 0xff
  70. };
  71. static const DWORD ALPHAJmpTblEntry[] = {
  72. 0xc0000000, // br $0, zero Pick up PC value
  73. 0x20600014, // lda 20($3), zero
  74. 0xa0a3fffc, // ldl $5, -4($3)
  75. 0x40a30003, // addl $5, $3, $3
  76. 0x68030000, // jmp zero, $3
  77. 0x00000000 // halt (maintain 16 byte align and puke if execute)
  78. };
  79. static const ILINK_INFO ALPHA_ilink = {
  80. ALPHAJmpTblEntry,
  81. sizeof(ALPHAJmpTblEntry),
  82. sizeof(ALPHAJmpTblEntry)-4,
  83. 0xff
  84. };
  85. size_t cbJumpEntry;
  86. PLMOD plmodNewModsFromLibSrch; // list of mods added as a result of lib search.
  87. // reloc counting function
  88. void CountBaseRelocsPMOD(PMOD, DWORD *);
  89. // weak extern prototypes
  90. void AssignWeakDefinition(PEXTERNAL, PEXTERNAL, PST);
  91. // calc ptrs prototypes
  92. void FindSlotForPCON(PCON);
  93. // export function prototypes
  94. BOOL FExpFileChanged(PEXPINFO);
  95. // library inclusion
  96. BOOL CheckForUnrefLibMods(PIMAGE);
  97. void CheckForMultDefns(PIMAGE, PLPEXT);
  98. #ifdef ILINKLOG
  99. DWORD dwBegin;
  100. void
  101. IlinkLog (
  102. UINT FullLinkErr
  103. )
  104. {
  105. DWORD cb;
  106. char McName[32];
  107. char rgchOut[1024];
  108. char szFname[_MAX_FNAME + _MAX_EXT];
  109. char szExt[_MAX_EXT];
  110. char rgchLogFilename[] = "\\\\fabrice2\\public\\linker\\ilink.log";
  111. HANDLE hFile;
  112. const int cRetry = 1;
  113. int i;
  114. // user requested no logging
  115. if (!fIlinkLog) {
  116. return;
  117. }
  118. if (!fINCR) {
  119. // non-incremental link
  120. if (FullLinkErr == -1) {
  121. strcpy(rgchOut, "RLINK ");
  122. } else {
  123. strcpy(rgchOut, "RFAIL ");
  124. }
  125. } else if (fIncrDbFile) {
  126. // Incremental link
  127. if (errInc == errNone) {
  128. strcpy(rgchOut, "ILINK ");
  129. } else {
  130. strcpy(rgchOut, "IFAIL ");
  131. }
  132. } else {
  133. // Full link
  134. if (FullLinkErr == -1) {
  135. strcpy(rgchOut, "FLINK ");
  136. } else {
  137. strcpy(rgchOut, "FFAIL ");
  138. }
  139. }
  140. // Name of machine
  141. cb = 32;
  142. if (!GetComputerName(McName, &cb)) {
  143. strcpy(McName, "UNKNOWN");
  144. }
  145. sprintf(szFname, "%-10s", McName); // for better formatting
  146. strcat(rgchOut, szFname);
  147. strcat(rgchOut, " ");
  148. // put in linker version
  149. strcat(rgchOut, " ");
  150. strcat(rgchOut, VERSION_STR);
  151. strcat(rgchOut, " ");
  152. // time for the link
  153. sprintf(McName, "%08ld ", (DWORD)(GetTickCount() - dwBegin));
  154. strcat(rgchOut, McName);
  155. // name of target
  156. if (OutFilename) {
  157. _splitpath(OutFilename, NULL, NULL, szFname, szExt);
  158. strcat(rgchOut, "\"");
  159. strcat(rgchOut, szFname);
  160. strcat(rgchOut, szExt);
  161. strcat(rgchOut, "\" ");
  162. } else {
  163. strcat(rgchOut, " NOOUTPUTFILE ");
  164. }
  165. // report target platform
  166. char *szPlatform;
  167. switch (wMachine) {
  168. case IMAGE_FILE_MACHINE_I386 :
  169. szPlatform = " IX86 ";
  170. break;
  171. case IMAGE_FILE_MACHINE_R3000 :
  172. case IMAGE_FILE_MACHINE_R4000 :
  173. case IMAGE_FILE_MACHINE_R10000 :
  174. szPlatform = " MIPS ";
  175. break;
  176. case IMAGE_FILE_MACHINE_ALPHA :
  177. szPlatform = " ALFA ";
  178. break;
  179. case IMAGE_FILE_MACHINE_POWERPC :
  180. szPlatform = " PWPC ";
  181. break;
  182. case IMAGE_FILE_MACHINE_M68K :
  183. szPlatform = " M68K ";
  184. break;
  185. case IMAGE_FILE_MACHINE_MPPC_601 :
  186. szPlatform = " MPPC ";
  187. break;
  188. default :
  189. szPlatform = " UNKN ";
  190. break;
  191. }
  192. strcat(rgchOut, szPlatform);
  193. // put out the host platform
  194. if (IsOSWin95()) {
  195. strcat(rgchOut, " WIN95 ");
  196. } else {
  197. strcat(rgchOut, " WINNT ");
  198. }
  199. // put out the date
  200. time_t ltime;
  201. _tzset();
  202. time((time_t *)&ltime);
  203. char *szTime = ctime(&ltime);
  204. if (szTime != NULL) {
  205. szTime[strlen(szTime) - 1] = '\0';
  206. strcat(rgchOut, szTime);
  207. } else {
  208. strcat(rgchOut, "notime");
  209. }
  210. strcat(rgchOut, " ");
  211. if (fIncrDbFile) {
  212. // Incremental link
  213. switch (errInc) {
  214. case errNone:
  215. break;
  216. case errOutOfDiskSpace:
  217. strcat(rgchOut, "OUT_OF_DISKSPACE");
  218. break;
  219. case errOutOfMemory:
  220. strcat(rgchOut, "OUT_OF_MEMORY");
  221. break;
  222. case errFpo:
  223. strcat(rgchOut, "FPO_PAD_OVERFLOW");
  224. break;
  225. case errTypes:
  226. strcat(rgchOut, "ERROR_TYPES");
  227. break;
  228. case errDataMoved:
  229. strcat(rgchOut, "DATA_MOVED");
  230. break;
  231. case errCalcPtrs:
  232. strcat(rgchOut, "PAD_OVERFLOW");
  233. break;
  234. case errUndefinedSyms:
  235. strcat(rgchOut, "UNDEFINED_SYMS");
  236. break;
  237. case errWeakExtern:
  238. strcat(rgchOut, "WEAK_EXTERN");
  239. break;
  240. case errCommonSym:
  241. strcat(rgchOut, "NEW_BSS_SYM");
  242. break;
  243. case errAbsolute:
  244. strcat(rgchOut, "ABSOLUTE_SYM");
  245. break;
  246. case errJmpTblOverflow:
  247. strcat(rgchOut, "JMP_TBL_OVERFLOW");
  248. break;
  249. case errDirectives:
  250. strcat(rgchOut, "DIRECTIVS_CHNG");
  251. break;
  252. case errBaseReloc:
  253. strcat(rgchOut, "BASERELOC_PAD_OVERFLOW");
  254. break;
  255. case errFileAdded:
  256. strcat(rgchOut, "NEW_FILE_ADDED");
  257. break;
  258. case errFileDeleted:
  259. strcat(rgchOut, "FILE_DELETED_OR_RENAMED");
  260. break;
  261. case errLibChanged:
  262. strcat(rgchOut, "LIB_CHANGED");
  263. break;
  264. case errTooManyChanges:
  265. strcat(rgchOut, "TOO_MANY_CHANGES");
  266. break;
  267. case errExports:
  268. strcat(rgchOut, "EXPORTS_CHANGED");
  269. break;
  270. case errLibRefSetChanged:
  271. strcat(rgchOut, "LIB_REFSET_CHANGED");
  272. break;
  273. case errMultDefFound:
  274. strcat(rgchOut, "MULTIPLE_DEFN_FOUND");
  275. break;
  276. case errComdat:
  277. strcat(rgchOut, "COMDAT_SEL_FAILED");
  278. break;
  279. case errNoChanges:
  280. strcat(rgchOut, "NO_CHANGES");
  281. break;
  282. default:
  283. strcat(rgchOut, "UNKNOWN");
  284. }
  285. } else {
  286. // Full link
  287. if (FullLinkErr != -1) {
  288. sprintf(McName, "error %04u", FullLinkErr);
  289. strcat(rgchOut, McName);
  290. }
  291. }
  292. strcat(rgchOut, "\r\n");
  293. for (i = 0; i < cRetry; i++) {
  294. hFile = CreateFile(rgchLogFilename,
  295. GENERIC_READ | GENERIC_WRITE,
  296. FILE_SHARE_READ,
  297. NULL,
  298. OPEN_ALWAYS,
  299. FILE_ATTRIBUTE_NORMAL,
  300. NULL);
  301. if (hFile != INVALID_HANDLE_VALUE) {
  302. break;
  303. }
  304. // Sleep(100); // sleep for 0.1s and retry
  305. }
  306. // tried our best to log an entry.
  307. if (i == cRetry) {
  308. return;
  309. }
  310. assert(hFile != INVALID_HANDLE_VALUE);
  311. // Seek to end of file
  312. SetFilePointer(hFile, 0, NULL, FILE_END);
  313. // Write
  314. WriteFile(hFile, rgchOut, strlen(rgchOut), &cb, NULL);
  315. // Close the file.
  316. CloseHandle(hFile);
  317. }
  318. #endif // ILINKLOG
  319. BOOL
  320. FArgOnList (
  321. PNAME_LIST pnl,
  322. PARGUMENT_LIST parg
  323. )
  324. /*++
  325. Routine Description:
  326. Searches for the arg on the list. Marks the list entries as processed.
  327. Arguments:
  328. pnl - list to search
  329. parg - arg to look for.
  330. Return Value:
  331. TRUE if found else FALSE
  332. --*/
  333. {
  334. WORD i;
  335. PARGUMENT_LIST pal;
  336. assert(parg);
  337. // walk the list
  338. for (i = 0, pal = pnl->First;
  339. i < pnl->Count;
  340. i++, pal = pal->Next) {
  341. // skip already processed entries
  342. if (pal->Flags & ARG_Processed) {
  343. continue;
  344. }
  345. if (!strcmp(pal->OriginalName, parg->OriginalName)) {
  346. pal->Flags |= ARG_Processed;
  347. return 1;
  348. }
  349. }
  350. // not found
  351. return 0;
  352. }
  353. void
  354. AddArgToListOnHeap (
  355. PNAME_LIST pnl,
  356. PARGUMENT_LIST parg
  357. )
  358. /*++
  359. Routine Description:
  360. Adds the arg to the name list on private heap.
  361. Arguments:
  362. pnl - ptr to name list on private heap
  363. parg - arg to add
  364. Return Value:
  365. None.
  366. --*/
  367. {
  368. PARGUMENT_LIST pal;
  369. assert(parg);
  370. // alloc space
  371. pal = (PARGUMENT_LIST) Malloc(sizeof(ARGUMENT_LIST));
  372. // fill in fields
  373. pal->OriginalName = Strdup(parg->OriginalName);
  374. if (parg->ModifiedName) {
  375. pal->ModifiedName = Strdup(parg->ModifiedName);
  376. } else {
  377. pal->ModifiedName = NULL;
  378. }
  379. pal->Next = NULL;
  380. // attach it to list
  381. if (!pnl->First) {
  382. pnl->First = pal;
  383. } else {
  384. pnl->Last->Next = pal;
  385. }
  386. // update count
  387. pnl->Count++;
  388. // update last member
  389. pnl->Last = pal;
  390. // done
  391. return;
  392. }
  393. void
  394. AddExtToList(
  395. PLPEXT plpext,
  396. BOOL fTempList,
  397. PEXTERNAL pext
  398. )
  399. /*++
  400. Routine Description:
  401. Adds the extern to the specified list.
  402. Arguments:
  403. plpext - pointer to list of externs
  404. fTempList - list is a temporary list
  405. pext - external sym to add.
  406. Return Value:
  407. None.
  408. --*/
  409. {
  410. EXTERNAL **rgpext;
  411. if ((plpext->pextChunkCur == NULL) || (plpext->cpextCur >= plpext->cpextMax)) {
  412. // allocate a chunk
  413. size_t cb = sizeof(EXTCHUNK) + plpext->cpextMax * sizeof(PEXTERNAL);
  414. EXTCHUNK *pextChunk = fTempList ? (EXTCHUNK *) PvAlloc(cb):
  415. (EXTCHUNK *) Malloc(cb);
  416. // update state
  417. pextChunk->pextChunkNext = plpext->pextChunkCur;
  418. plpext->pextChunkCur = pextChunk;
  419. plpext->cpextCur = 0;
  420. }
  421. rgpext = RgPext(plpext->pextChunkCur);
  422. rgpext[plpext->cpextCur++] = pext;
  423. plpext->cpextTotal++;
  424. }
  425. void
  426. DelExtFromList(
  427. PLPEXT plpext,
  428. PEXTERNAL pext
  429. )
  430. /*++
  431. Routine Description:
  432. Removes the extern from the specified list.
  433. Arguments:
  434. plpext - pointer to list of externs
  435. pext - external sym to add.
  436. Return Value:
  437. None.
  438. --*/
  439. {
  440. EXTCHUNK *pextChunk;
  441. WORD cpextMax;
  442. for (pextChunk = plpext->pextChunkCur, cpextMax = plpext->cpextCur;
  443. pextChunk != NULL;
  444. pextChunk = pextChunk->pextChunkNext, cpextMax = plpext->cpextMax) {
  445. EXTERNAL **rgpext;
  446. WORD ipext;
  447. rgpext = RgPext(pextChunk);
  448. for (ipext = 0; ipext < cpextMax; ipext++) {
  449. if (rgpext[ipext] == pext) {
  450. rgpext[ipext] = NULL;
  451. plpext->cpextTotal--;
  452. return;
  453. }
  454. }
  455. }
  456. }
  457. BOOL
  458. IsExtListEmpty (
  459. PLPEXT plpext
  460. )
  461. /*++
  462. Routine Description:
  463. Checks to see if the specified list is empty.
  464. Arguments:
  465. plpext - pointer to list of externs
  466. Return Value:
  467. TRUE if list is empty.
  468. --*/
  469. {
  470. return(!plpext->cpextTotal);
  471. }
  472. //
  473. // Enumerator of all externs in list
  474. //
  475. INIT_ENM(ExtList, EXT_LIST, (ENM_EXT_LIST *penm, PLPEXT plpext)) {
  476. if (plpext) {
  477. penm->lpext = (*plpext);
  478. } else {
  479. penm->lpext.pextChunkCur = NULL;
  480. }
  481. penm->ipext = 0;
  482. }
  483. NEXT_ENM(ExtList, EXT_LIST) {
  484. if (penm->lpext.pextChunkCur == NULL) {
  485. return(FALSE);
  486. }
  487. {
  488. EXTERNAL **rgpext = RgPext(penm->lpext.pextChunkCur);
  489. penm->pext = rgpext[penm->ipext++];
  490. }
  491. if (penm->ipext == penm->lpext.cpextCur) {
  492. penm->lpext.pextChunkCur = penm->lpext.pextChunkCur->pextChunkNext;
  493. penm->lpext.cpextCur = penm->lpext.cpextMax;
  494. penm->ipext = 0;
  495. }
  496. return(TRUE);
  497. }
  498. END_ENM(ExtList, EXT_LIST) {
  499. }
  500. DONE_ENM
  501. void
  502. AddExtToModRefList (
  503. PMOD pmod,
  504. PEXTERNAL pext
  505. )
  506. /*++
  507. Routine Description:
  508. Adds the extern to the specified MODs reference list.
  509. Arguments:
  510. pmod - pointer to MOD
  511. pext - external sym to add.
  512. Return Value:
  513. None.
  514. --*/
  515. {
  516. if (!(pext->Flags & EXTERN_NO_REFS)) {
  517. AddExtToList(pmod->plpextRef, FALSE, pext);
  518. }
  519. }
  520. void
  521. RemoveAllRefsToPext (
  522. PEXTERNAL pext
  523. )
  524. /*++
  525. Routine Description:
  526. Removes all references made to this extern. This is done to
  527. enable checking for correct library module inclusion
  528. Arguments:
  529. pext - external sym whose references need to be removed
  530. Return Value:
  531. None.
  532. --*/
  533. {
  534. ENM_MOD_EXT enmModExt;
  535. if (!pext->pmodOnly) {
  536. return;
  537. }
  538. // walk the list of referencing MODs kept at each sym
  539. InitEnmModExt(&enmModExt, pext);
  540. while (FNextEnmModExt(&enmModExt)) {
  541. if (!enmModExt.pmod) {
  542. continue; // for ilink we remove references
  543. }
  544. DelExtFromList(enmModExt.pmod->plpextRef, pext);
  545. }
  546. }
  547. BOOL
  548. RemoveExtFromDefList (
  549. PMOD pmod,
  550. PEXTERNAL pext
  551. )
  552. /*++
  553. Routine Description:
  554. Removes extern from defined list of MOD if present.
  555. Arguments:
  556. pmod - ptr to MOD.
  557. pext - external sym which needs to be removed from DEF list
  558. Return Value:
  559. TRUE if we did find pext in the list & removed it
  560. --*/
  561. {
  562. PEXTERNAL *ppextPrev, pextCur;
  563. pextCur = pmod->pextFirstDefined;
  564. ppextPrev = &pmod->pextFirstDefined;
  565. while (pextCur) {
  566. if (pextCur == pext) {
  567. (*ppextPrev) = pextCur->pextNextDefined; // remove pext from chain
  568. pextCur->pextNextDefined = NULL; // set next field to NULL for pext just removed
  569. return(TRUE);
  570. }
  571. ppextPrev = &pextCur->pextNextDefined;
  572. pextCur = pextCur->pextNextDefined;
  573. }
  574. return(FALSE);
  575. }
  576. void
  577. RemovePrevDefn (
  578. PEXTERNAL pext
  579. )
  580. /*++
  581. Routine Description:
  582. All externs defined by a MOD are chained together. Need to remove
  583. it from that chain.
  584. For COMMON syms this is difficult since pext->pcon->pmodBack is
  585. a "linker defined module". .
  586. Arguments:
  587. pext - external sym whose references need to be removed
  588. Return Value:
  589. None.
  590. --*/
  591. {
  592. ENM_MOD_EXT enmModExt;
  593. assert(pext->Flags & EXTERN_COMMON);
  594. if (fIncrDbFile) {
  595. assert(PmodPCON(pext->pcon) == pmodLinkerDefined);
  596. }
  597. assert(pext->pmodsFirst);
  598. // walk the list of referencing MODs kept at each sym
  599. // one of these MODs has defined the COMMON (eeewww!!!)
  600. InitEnmModExt(&enmModExt, pext);
  601. while (FNextEnmModExt(&enmModExt)) {
  602. if (!enmModExt.pmod) {
  603. continue; // for ilink we remove references
  604. }
  605. if (RemoveExtFromDefList(enmModExt.pmod, pext)) {
  606. return; // found the definition
  607. }
  608. }
  609. }
  610. void
  611. ProcessUndefinedExternals(
  612. PIMAGE pimage
  613. )
  614. /*++
  615. Routine Description:
  616. Makes a pass over the undefined externals to see if they are really undefined.
  617. REVIEW: Need to make a pass over this again w/ regard to weak externs since
  618. we are doing lib searches now.
  619. Arguments:
  620. pimage - pointer to image
  621. Return Value:
  622. None.
  623. --*/
  624. {
  625. PEXTERNAL pext;
  626. ENM_UNDEF_EXT enmUndefExt;
  627. PST pst = pimage->pst;
  628. // First pass thru symbols checks for cases which may cause a full
  629. // link. This way we avoid giving any warnings & later decide to do
  630. // a full link after all.
  631. InitEnmUndefExt(&enmUndefExt, pst);
  632. while (FNextEnmUndefExt(&enmUndefExt)) {
  633. pext = enmUndefExt.pext;
  634. // symbol to be ignored
  635. if ((pext->Flags & EXTERN_DEFINED) ||
  636. (pext->Flags & EXTERN_IGNORE) )
  637. continue;
  638. // symbol no longer referenced by anybody
  639. if (!FPextRef(pext)) {
  640. SetDefinedExt(pext, TRUE, pst); // take it off undef list
  641. pext->Flags = EXTERN_IGNORE;
  642. pext->pcon = NULL; // clean
  643. pext->ImageSymbol = NullSymbol; // clean
  644. continue;
  645. }
  646. // if symbol undefined & marked relink then relink (for bss with multiple defn)
  647. if (pext->Flags & EXTERN_RELINK) {
  648. errInc = errCommonSym;
  649. return;
  650. }
  651. // a COMDAT with a reference, dirty files didn't have defn but atleast one of the
  652. // non-dirty files has a reference & may (or may not) have a defn
  653. if (pext->Flags & EXTERN_COMDAT) {
  654. errInc = errComdat;
  655. return;
  656. }
  657. // undefined sym
  658. #ifdef INSTRUMENT
  659. {
  660. char *szOutSymName;
  661. szOutSymName = SzOutputSymbolName(SzNamePext(pext, pst), TRUE);
  662. LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "undefined sym: %s", szOutSymName);
  663. if (szOutSymName != SzNamePext(pext, pst)) {
  664. free(szOutSymName);
  665. }
  666. }
  667. #endif // INSTRUMENT
  668. errInc = errUndefinedSyms;
  669. } // end while
  670. }
  671. BOOL
  672. IsExpObj (
  673. const char *szName
  674. )
  675. /*++
  676. Routine Description:
  677. Is the name specified an export object.
  678. Arguments:
  679. szName - name of file.
  680. Return Value:
  681. TRUE if export object else FALSE
  682. --*/
  683. {
  684. char szDrive[_MAX_DRIVE];
  685. char szDir[_MAX_DIR];
  686. char szFname[_MAX_FNAME];
  687. char szExt[_MAX_EXT];
  688. char szExpFilename[_MAX_FNAME];
  689. char szImplibFilename[_MAX_FNAME];
  690. const char *szImplibT;
  691. // generate possible import lib name (could be user specified)
  692. if ((szImplibT = ImplibFilename) == NULL) {
  693. _splitpath(OutFilename, szDrive, szDir, szFname, szExt);
  694. _makepath(szImplibFilename, szDrive, szDir, szFname, ".lib");
  695. szImplibT = szImplibFilename;
  696. }
  697. // Generate possible export filename
  698. _splitpath(szImplibT, szDrive, szDir, szFname, NULL);
  699. _makepath(szExpFilename, szDrive, szDir, szFname, ".exp");
  700. // check to see if the names match
  701. if (!_tcsicmp(szName, szExpFilename)) {
  702. return 1;
  703. }
  704. return 0;
  705. }
  706. PARGUMENT_LIST
  707. PargFindSz (
  708. const char *szName,
  709. PNAME_LIST ptrList
  710. )
  711. /*++
  712. Routine Description:
  713. Find the module in the given list
  714. Arguments:
  715. szName - name of file.
  716. ptrList - list to search
  717. Return Value:
  718. pointer to argument or NULL
  719. --*/
  720. {
  721. DWORD i;
  722. PARGUMENT_LIST parg;
  723. for (i = 0, parg = ptrList->First;
  724. i < ptrList->Count;
  725. i++, parg=parg->Next) {
  726. // original name to handle resource files etc.
  727. if (!_tcsicmp(szName, parg->OriginalName)) {
  728. return parg;
  729. }
  730. }
  731. return NULL;
  732. }
  733. BOOL
  734. IsDirtyPMOD (
  735. PMOD pmod
  736. )
  737. /*++
  738. Routine Description:
  739. Checks to see if this MOD if dirty.
  740. Arguments:
  741. pmod - ptr to a MOD.
  742. Return Value:
  743. TRUE if it is dirty.
  744. --*/
  745. {
  746. // is it referenced by a modified file?
  747. PARGUMENT_LIST parg = PargFindSz(SzOrigFilePMOD(pmod), &ModFileList);
  748. return(parg != NULL);
  749. }
  750. void
  751. AddToModList (
  752. PARGUMENT_LIST parg,
  753. WORD Flags
  754. )
  755. /*++
  756. Routine Description:
  757. Adds entry to modified list.
  758. Arguments:
  759. parg - pointer to entry to be added.
  760. Flags - flags of entry
  761. Return Value:
  762. None.
  763. --*/
  764. {
  765. PARGUMENT_LIST ptrList;
  766. ptrList = (PARGUMENT_LIST) PvAlloc(sizeof(ARGUMENT_LIST));
  767. // fill in fields
  768. ptrList->OriginalName = parg->OriginalName;
  769. ptrList->ModifiedName = parg->ModifiedName;
  770. ptrList->TimeStamp = parg->TimeStamp;
  771. ptrList->Flags = Flags;
  772. ptrList->Next = NULL;
  773. // If first member to be added.
  774. if (!ModFileList.Last) {
  775. ModFileList.Last = ptrList;
  776. } else {
  777. // Not first member, so add to the front.
  778. ptrList->Next = ModFileList.First;
  779. }
  780. // Increment number of members in list.
  781. ++ModFileList.Count;
  782. // Remember first member in list.
  783. ModFileList.First = ptrList;
  784. }
  785. void
  786. ProcessFileArg (
  787. PARGUMENT_LIST parg,
  788. WORD Flags,
  789. DWORD TimeStamp,
  790. DWORD HdrTimeStamp,
  791. DWORD cbFile,
  792. char *szOrigName,
  793. BOOL fExpFileGen,
  794. BOOL *pfLib,
  795. BOOL *pfDel
  796. )
  797. /*++
  798. Routine Description:
  799. Adds entry to modified list.
  800. Arguments:
  801. parg - pointer to entry to be added if not NULL.
  802. Flags - obj or lib
  803. Timestamp - filssystem timestamp of obj or lib
  804. HdrTimeStamp - timestamp in the hdr of obj file (ignored for obj in lib)
  805. cbFile - size of object file (ignored for obj in lib)
  806. szOrigName - original name of file (used for deleted files)
  807. Return Value:
  808. None.
  809. --*/
  810. {
  811. ARGUMENT_LIST arg;
  812. // found a matching name
  813. if (parg) {
  814. parg->Flags |= ARG_Processed;
  815. // modified file
  816. if (parg->TimeStamp != TimeStamp) {
  817. if (Flags & ARG_Library) { // library modified
  818. #ifdef INSTRUMENT
  819. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "lib modified: %s", parg->OriginalName);
  820. #endif // INSTRUMENT
  821. *pfLib = 1;
  822. } else { // object file modified
  823. IMAGE_FILE_HEADER imFileHdr;
  824. FileReadHandle = FileOpen(parg->ModifiedName, O_RDONLY | O_BINARY, 0);
  825. ReadFileHeader(FileReadHandle, &imFileHdr);
  826. assert(HdrTimeStamp);
  827. assert(cbFile);
  828. // file not really changed - touched for MR
  829. if (imFileHdr.TimeDateStamp == HdrTimeStamp &&
  830. FileLength(FileReadHandle) == (LONG) cbFile) {
  831. FileClose(FileReadHandle, TRUE);
  832. return;
  833. }
  834. FileClose(FileReadHandle, FALSE);
  835. }
  836. Flags |= ARG_Modified;
  837. AddToModList(parg, Flags);
  838. DBEXEC(DB_LISTMODFILES, DBPRINT("Modified File= %s\n",
  839. parg->OriginalName));
  840. DBEXEC(DB_LISTMODFILES, DBPRINT("\tOld TimeStamp= %s",
  841. ctime((time_t *)&TimeStamp)));
  842. DBEXEC(DB_LISTMODFILES, DBPRINT("\tNew TimeStamp= %s",
  843. ctime((time_t *)&parg->TimeStamp)));
  844. // unmodified file
  845. } else {
  846. DBEXEC(DB_LISTMODFILES, DBPRINT("Unchanged File= %s\n",parg->OriginalName));
  847. }
  848. // did not find matching name
  849. } else {
  850. // check to see if this is an export object
  851. if (fExpFileGen && IsExpObj(szOrigName)) {
  852. return;
  853. }
  854. *pfDel = 1;
  855. arg.OriginalName = arg.ModifiedName = szOrigName;
  856. Flags |= ARG_Deleted;
  857. AddToModList(&arg, Flags);
  858. #ifdef INSTRUMENT
  859. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "file deleted: %s", szOrigName);
  860. #endif // INSTRUMENT
  861. DBEXEC(DB_LISTMODFILES, DBPRINT("Deleted File= %s\n",szOrigName));
  862. }
  863. }
  864. void
  865. InitModFileList (
  866. PIMAGE pimage,
  867. BOOL *pfLib,
  868. BOOL *pfNew,
  869. BOOL *pfDel
  870. )
  871. /*++
  872. Routine Description:
  873. Builds a list of files whose timestamp is newer than the
  874. previous link.
  875. Arguments:
  876. pimage - image structure
  877. pfLib - set to TRUE if LIB was modified
  878. pfNew - set to TRUE if a NEW file was added
  879. pfDel - Set to TRUE if an existing MOD was deleted
  880. Return Value:
  881. None.
  882. --*/
  883. {
  884. PARGUMENT_LIST parg;
  885. ARGUMENT_LIST arg;
  886. DWORD i;
  887. PLIB plib;
  888. PMOD pmod;
  889. ENM_MOD enm_mod;
  890. ENM_LIB enm_lib;
  891. *pfLib = 0;
  892. *pfNew = 0;
  893. *pfDel = 0;
  894. // check out mods
  895. InitEnmMod(&enm_mod, pimage->plibCmdLineObjs);
  896. while (FNextEnmMod(&enm_mod)) {
  897. pmod = enm_mod.pmod;
  898. cmods++;
  899. assert(pmod);
  900. parg = PargFindSz(SzOrigFilePMOD(pmod), &FilenameArguments);
  901. ProcessFileArg(parg,
  902. ARG_Object,
  903. pmod->TimeStamp,
  904. pmod->HdrTimeStamp,
  905. pmod->cbFile,
  906. SzOrigFilePMOD(pmod),
  907. pimage->ExpInfo.pmodGen != NULL,
  908. pfLib,
  909. pfDel);
  910. }
  911. EndEnmMod(&enm_mod);
  912. // check out libs
  913. InitEnmLib(&enm_lib, pimage->libs.plibHead);
  914. while (FNextEnmLib(&enm_lib)) {
  915. plib = enm_lib.plib;
  916. assert(plib);
  917. if (plib->flags & LIB_DontSearch) {
  918. continue;
  919. }
  920. if (plib->flags & LIB_Default) {
  921. struct _stat statfile;
  922. char szFname[_MAX_FNAME];
  923. char szExt[_MAX_EXT];
  924. char szFilename[_MAX_FNAME + _MAX_EXT];
  925. _splitpath(plib->szName, NULL, NULL, szFname, szExt);
  926. strcpy(szFilename, szFname);
  927. strcat(szFilename, szExt);
  928. char *sz = SzSearchEnv("LIB", szFilename, LIB_EXT);
  929. // lib names don't match
  930. if (_tcsicmp(plib->szName, sz)) {
  931. parg = NULL;
  932. } else {
  933. arg.OriginalName = arg.ModifiedName = sz;
  934. if (_stat(arg.OriginalName, &statfile) == -1) {
  935. Fatal(NULL, CANTOPENFILE, arg.OriginalName);
  936. }
  937. arg.TimeStamp = statfile.st_mtime;
  938. parg = &arg;
  939. }
  940. } else {
  941. parg = PargFindSz(plib->szName, &FilenameArguments);
  942. }
  943. ProcessFileArg(parg, ARG_Library, plib->TimeStamp,
  944. 0, 0, plib->szName, FALSE, pfLib, pfDel);
  945. }
  946. EndEnmLib(&enm_lib);
  947. // check for new files
  948. for (i = 0, parg = FilenameArguments.First;
  949. i < FilenameArguments.Count;
  950. i++, parg = parg->Next) {
  951. RESN *pTempResn;
  952. // already processed
  953. if (parg->Flags & ARG_Processed) {
  954. continue;
  955. }
  956. // check for repeated args
  957. if (PmodFind(pimage->plibCmdLineObjs, parg->OriginalName, 0) ||
  958. PlibFind(parg->OriginalName, pimage->libs.plibHead, FALSE)) {
  959. continue;
  960. }
  961. parg->Flags |= ARG_Processed;
  962. // check to see if it happens to be a PowerMac resource
  963. if ((pTempResn = GetMacResourcePointer(parg->OriginalName, pimage)) != NULL) {
  964. if (pTempResn->TimeStamp == parg->TimeStamp) {
  965. continue;
  966. } else {
  967. PostNote(NULL, RESFILECHANGE, parg->OriginalName);
  968. }
  969. }
  970. AddToModList(parg, ARG_NewFile);
  971. *pfNew = 1;
  972. DBEXEC(DB_LISTMODFILES, DBPRINT("New File= %s\n",parg->OriginalName));
  973. #ifdef INSTRUMENT
  974. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "new file: %s", parg->OriginalName);
  975. #endif // INSTRUMENT
  976. }
  977. }
  978. void
  979. DoPass2PMOD (
  980. IN PMOD pmod,
  981. IN BOOL fDoDebug
  982. )
  983. /*++
  984. Routine Description:
  985. Mark the MOD for doing pass2 and for doing debug info if required.
  986. CAVEAT: A MOD cannot change state from MOD_DoDebug to !MOD_DoDebug
  987. or vice-versa during the same link.
  988. Arguments:
  989. pmod - ptr to MOD
  990. fDoDebug - TRUE if debug info needs to be done during Pass2
  991. Return Value:
  992. None.
  993. --*/
  994. {
  995. PLIB plib;
  996. ENM_MOD enm_mod;
  997. // already marked for doing pass2
  998. if (FDoPass2PMOD(pmod)) {
  999. return;
  1000. }
  1001. // mark for doing pass2
  1002. pmod->LnkFlags |= MOD_DoPass2;
  1003. if (fDoDebug) {
  1004. pmod->LnkFlags |= MOD_DoDebug;
  1005. }
  1006. // done if command line obj
  1007. if (!FIsLibPMOD(pmod)) {
  1008. return;
  1009. }
  1010. // mark MODs with the same name for Pass2 (DBI hack for import libs)
  1011. plib = pmod->plibBack;
  1012. // REVIEW: base reloc count is not accurate
  1013. InitEnmMod(&enm_mod, plib);
  1014. while (FNextEnmMod(&enm_mod)) {
  1015. if (!_tcsicmp(SzOrigFilePMOD(enm_mod.pmod),SzOrigFilePMOD(pmod))) {
  1016. enm_mod.pmod->LnkFlags |= MOD_DoPass2;
  1017. CountBaseRelocsPMOD(enm_mod.pmod, &cReloc);
  1018. if (fDoDebug) {
  1019. enm_mod.pmod->LnkFlags |= MOD_DoDebug;
  1020. }
  1021. }
  1022. }
  1023. EndEnmMod(&enm_mod);
  1024. }
  1025. void
  1026. DetermineTimeStamps (
  1027. VOID
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Determine timestamps of all files.
  1032. Arguments:
  1033. None.
  1034. Return Value:
  1035. None.
  1036. --*/
  1037. {
  1038. PARGUMENT_LIST argument;
  1039. DWORD i;
  1040. struct _stat statfile;
  1041. for (i = 0, argument = FilenameArguments.First;
  1042. i < FilenameArguments.Count;
  1043. argument = argument->Next, i++) {
  1044. // determine current timestamp of file
  1045. if (_stat(argument->OriginalName, &statfile) == -1) {
  1046. Fatal(NULL, CANTOPENFILE, argument->OriginalName);
  1047. }
  1048. argument->TimeStamp = statfile.st_mtime;
  1049. }
  1050. }
  1051. // assign the weak definition
  1052. void
  1053. AssignWeakDefinition (
  1054. PEXTERNAL pext,
  1055. PEXTERNAL pextWeakDefault,
  1056. PST pst
  1057. )
  1058. {
  1059. // define the weak/lazy external to its "default"
  1060. assert(pext);
  1061. assert(pextWeakDefault);
  1062. if ((pextWeakDefault->Flags & EXTERN_DEFINED)) {
  1063. PMOD pmod;
  1064. pext->ImageSymbol.Value =
  1065. pextWeakDefault->ImageSymbol.Value;
  1066. // + PsecPCON(pext->pextWeakDefault->pcon)->rva;
  1067. pext->ImageSymbol.SectionNumber =
  1068. pextWeakDefault->ImageSymbol.SectionNumber;
  1069. pext->ImageSymbol.Type =
  1070. pextWeakDefault->ImageSymbol.Type;
  1071. SetDefinedExt(pext, TRUE, pst);
  1072. pext->Flags |= (EXTERN_DEFINED|EXTERN_DIRTY);
  1073. pext->pcon = pextWeakDefault->pcon;
  1074. pext->FinalValue = pextWeakDefault->FinalValue;
  1075. // chain up extern to mod defining it
  1076. pmod = PmodPCON(pext->pcon);
  1077. assert(pmod);
  1078. if (pmod->pextFirstDefined) {
  1079. pext->pextNextDefined = pmod->pextFirstDefined;
  1080. }
  1081. pmod->pextFirstDefined = pext;
  1082. }
  1083. }
  1084. // All existing weak & lazy externs can be resolved. The 'lazy' because
  1085. // ilink assumes libs haven't changed and so there is no need to search
  1086. // the libs.
  1087. void
  1088. ResolveExistingWeakAndLazyExterns (
  1089. PIMAGE pimage
  1090. )
  1091. {
  1092. ENM_EXT_LIST enmExtList;
  1093. PST pst = pimage->pst;
  1094. // walk the list of existing weak/lazy externs
  1095. InitEnmExtList(&enmExtList, plpextWeak);
  1096. while (FNextEnmExtList(&enmExtList)) {
  1097. PEXTERNAL pext;
  1098. pext = enmExtList.pext;
  1099. // no longer referenced or marked as ignore
  1100. if (!FPextRef(pext) ||
  1101. (pext->Flags & EXTERN_IGNORE) )
  1102. continue;
  1103. // it is still weak/lazy
  1104. // if it is defined nothing to do (already been asigned to weak defn)
  1105. // else assign to weak defn
  1106. if (pext->Flags & (EXTERN_WEAK|EXTERN_LAZY)) {
  1107. PEXTERNAL pextWeakDefault;
  1108. if (pext->Flags & EXTERN_DEFINED) {
  1109. continue;
  1110. }
  1111. pextWeakDefault = PextWeakDefaultFind(pext);
  1112. AssignWeakDefinition(pext, pextWeakDefault, pst);
  1113. continue;
  1114. }
  1115. // weak/lazy has changed from weak definition to strong - punt
  1116. #ifdef INSTRUMENT
  1117. {
  1118. char *szOutSymName;
  1119. szOutSymName = SzOutputSymbolName(SzNamePext(pext, pst), TRUE);
  1120. LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "weak/lazy extern (w 2 s): %s", szOutSymName);
  1121. if (szOutSymName != SzNamePext(pext, pst)) {
  1122. free(szOutSymName);
  1123. }
  1124. }
  1125. #endif // INSTRUMENT
  1126. errInc = errWeakExtern;
  1127. return;
  1128. } // end while
  1129. EndEnmExtList(&enmExtList);
  1130. }
  1131. // assign weak externs to their default definitions
  1132. // new weak/lazy are permitted on an ilink
  1133. // change in state from weak to strong or vice-versa isn't allowed
  1134. void
  1135. ResolveWeakExterns (
  1136. PIMAGE pimage,
  1137. DWORD Type
  1138. )
  1139. {
  1140. WEAK_EXTERN_LIST *pwel;
  1141. PST pst = pimage->pst;
  1142. // now walk the global list for any new weak/lazy externs
  1143. pwel = pwelHead;
  1144. for (; pwel; pwel = pwel->pwelNext) {
  1145. // look at ones of interest
  1146. if (!(pwel->pext->Flags & Type)) {
  1147. continue;
  1148. }
  1149. // skip ones already done in the prior pass
  1150. if (pwel->pext->Flags & EXTERN_DEFINED) {
  1151. continue;
  1152. }
  1153. // rest are ones which haven't been handled yet; new are ok
  1154. if (pwel->pext->Flags & EXTERN_NEWFUNC ||
  1155. pwel->pext->Flags & EXTERN_NEWDATA) {
  1156. AssignWeakDefinition(pwel->pext, pwel->pextWeakDefault, pst);
  1157. continue;
  1158. }
  1159. // weak and not new (=> a strong defn became a weak one)
  1160. errInc = errWeakExtern;
  1161. return;
  1162. }
  1163. }
  1164. void
  1165. RestoreWeakSymVals (
  1166. PIMAGE /* pimage */
  1167. )
  1168. /*++
  1169. Routine Description:
  1170. Restore weak sym values of externs that were modified just
  1171. before emit to map file.
  1172. Arguments:
  1173. pimage - ptr to image.
  1174. Return Value:
  1175. None.
  1176. --*/
  1177. {
  1178. WEAK_EXTERN_LIST *pwel;
  1179. for (pwel = pwelHead; pwel != NULL; pwel = pwel->pwelNext) {
  1180. if (pwel->pext->Flags & (EXTERN_WEAK | EXTERN_LAZY | EXTERN_ALIAS)) {
  1181. assert(pwel->pextWeakDefault);
  1182. pwel->pext->ImageSymbol.Value -=
  1183. PsecPCON(pwel->pextWeakDefault->pcon)->rva;
  1184. }
  1185. }
  1186. }
  1187. DWORD
  1188. CThunks (
  1189. PIMAGE pimage
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. Returns count of thunks required.
  1194. Arguments:
  1195. pimage - ptr to image.
  1196. Return Value:
  1197. None.
  1198. --*/
  1199. {
  1200. PEXTERNAL pext;
  1201. DWORD cext = 0UL;
  1202. // walk the external symbol table
  1203. InitEnumerateExternals(pimage->pst);
  1204. while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
  1205. // ignore undefined externs
  1206. if (!(pext->Flags & EXTERN_DEFINED) || !pext->pcon || FIsLibPCON(pext->pcon)) {
  1207. continue;
  1208. }
  1209. // check to see if this is a function
  1210. if (ISFCN(pext->ImageSymbol.Type)) {
  1211. DBEXEC(DB_DUMPJMPTBL,
  1212. DBPRINT("sym=%s\n", SzNamePext(pext, pimage->pst)));
  1213. cext++;
  1214. }
  1215. }
  1216. TerminateEnumerateExternals(pimage->pst);
  1217. // done
  1218. return cext;
  1219. }
  1220. PCON
  1221. PconCreateJumpTable (
  1222. PIMAGE pimage
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. Creates a dummy pcon for the jump table.
  1227. Arguments:
  1228. pimage - ptr to image.
  1229. Return Value:
  1230. None.
  1231. --*/
  1232. {
  1233. PCON pcon = NULL;
  1234. PSEC psecText;
  1235. PGRP pgrpBase;
  1236. // get count of functions
  1237. cextFCNs = CThunks(pimage);
  1238. if (cextFCNs == 0) {
  1239. return NULL;
  1240. }
  1241. // find .text section
  1242. psecText = PsecFind(NULL,
  1243. ".text",
  1244. IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
  1245. &pimage->secs,
  1246. &pimage->ImgOptHdr);
  1247. assert(psecText);
  1248. pgrpBase = psecText->pgrpNext;
  1249. assert(pgrpBase);
  1250. assert(pgrpBase->pconNext);
  1251. // create a pcon
  1252. pcon = (PCON) Calloc(1, sizeof(CON));
  1253. switch (pimage->ImgFileHdr.Machine) {
  1254. case IMAGE_FILE_MACHINE_ALPHA :
  1255. ilink_info = &ALPHA_ilink;
  1256. cbJumpEntry = ilink_info->cbJumpEntry;
  1257. break;
  1258. case IMAGE_FILE_MACHINE_I386 :
  1259. ilink_info = &I386_ilink;
  1260. cbJumpEntry = ilink_info->cbJumpEntry;
  1261. break;
  1262. case IMAGE_FILE_MACHINE_R4000 :
  1263. case IMAGE_FILE_MACHINE_R10000 :
  1264. ilink_info = &MIPS_ilink;
  1265. cbJumpEntry = ilink_info->cbJumpEntry;
  1266. break;
  1267. case IMAGE_FILE_MACHINE_MPPC_601 :
  1268. ilink_info = &MPPC_ilink;
  1269. cbJumpEntry = ilink_info->cbJumpEntry;
  1270. break;
  1271. default:
  1272. assert(FALSE);
  1273. break;
  1274. }
  1275. // fill in structure
  1276. pcon->cbPad = __min(cextFCNs * CbJumpEntry(), USHRT_MAX);
  1277. pcon->cbRawData = cextFCNs * CbJumpEntry() + pcon->cbPad;
  1278. pcon->pgrpBack = pgrpBase;
  1279. pcon->pmodBack = pmodLinkerDefined;
  1280. pcon->pconNext = NULL;
  1281. pmodLinkerDefined->icon++;
  1282. // attach the pcon at the front of the list
  1283. pcon->pconNext = pgrpBase->pconNext;
  1284. pgrpBase->pconNext = pcon;
  1285. return(pcon);
  1286. }
  1287. void
  1288. BuildThunkMap (
  1289. PVOID pvThunkTable,
  1290. DWORD **prgThunkMapOff,
  1291. DWORD cThunk
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. Builds the thunk map o be passed onto dbi.
  1296. Arguments:
  1297. pimage - ptr to image.
  1298. pvThunkTable - ptr to raw thunk table
  1299. prgThunkMapOff - ptr to array of file offsets of jmp destinations in
  1300. thunk table on return.
  1301. cThunk - count of thunks.
  1302. Return Value:
  1303. None.
  1304. --*/
  1305. {
  1306. BYTE *p;
  1307. DWORD i;
  1308. // Alloc space for the array of offsets
  1309. *prgThunkMapOff = (DWORD *) PvAlloc(cThunk * (sizeof(DWORD)));
  1310. // Fill the array with the offset values
  1311. p = (BYTE *) pvThunkTable;
  1312. if (fPowerMac) {
  1313. // The first entry in the Jump Table is not used
  1314. // for PowerMac. So get past it!
  1315. p += CbJumpEntry();
  1316. }
  1317. p += ilink_info->address_offset; // get past first opcode
  1318. for (i = 0; i < cThunk; i++) {
  1319. LONG offset = *(LONG UNALIGNED *) p;
  1320. if (fPowerMac) {
  1321. // If it is PowerMac, remove the opcode in the first 6 bits
  1322. SwapBytes(&offset, 4);
  1323. offset = (offset << 6) >> 6;
  1324. }
  1325. // Calculate file offset of jmp destination
  1326. (*prgThunkMapOff)[i] = pconJmpTbl->foRawDataDest +
  1327. ((i+1) * CbJumpEntry()) + offset;
  1328. p += CbJumpEntry();
  1329. }
  1330. }
  1331. void
  1332. WriteJumpTable (
  1333. PIMAGE pimage,
  1334. PCON pconJmpTbl,
  1335. DWORD **prgThunkMapOff,
  1336. DWORD *pcThunk
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. Builds the jump table & writes it out.
  1341. Arguments:
  1342. pimage - ptr to image.
  1343. pconJmpTbl - pcon to write out
  1344. prgThunkMap - ptr to array of addresses on return.
  1345. pcThunkAddr - on return has countof thunks.
  1346. Return Value:
  1347. None.
  1348. --*/
  1349. {
  1350. PVOID pvRaw = NULL;
  1351. DWORD cfuncs, i;
  1352. LONG offset;
  1353. BYTE *p;
  1354. PEXTERNAL pext;
  1355. // check for any thunks
  1356. if (!pconJmpTbl || !cextFCNs) {
  1357. return;
  1358. }
  1359. // allocate space for raw data
  1360. pvRaw = PvAllocZ(pconJmpTbl->cbRawData);
  1361. // hammer thunks into the space
  1362. switch (pimage->ImgFileHdr.Machine) {
  1363. case IMAGE_FILE_MACHINE_ALPHA:
  1364. ilink_info = &ALPHA_ilink;
  1365. cbJumpEntry = ilink_info->cbJumpEntry;
  1366. break;
  1367. case IMAGE_FILE_MACHINE_I386:
  1368. ilink_info = &I386_ilink;
  1369. cbJumpEntry = ilink_info->cbJumpEntry;
  1370. break;
  1371. case IMAGE_FILE_MACHINE_MPPC_601:
  1372. ilink_info = &MPPC_ilink;
  1373. cbJumpEntry = ilink_info->cbJumpEntry;
  1374. break;
  1375. case IMAGE_FILE_MACHINE_R4000:
  1376. case IMAGE_FILE_MACHINE_R10000:
  1377. ilink_info = &MIPS_ilink;
  1378. cbJumpEntry = ilink_info->cbJumpEntry;
  1379. break;
  1380. default:
  1381. assert(FALSE);
  1382. break;
  1383. }
  1384. cfuncs = cextFCNs;
  1385. p = (BYTE *) pvRaw;
  1386. for (i = 0; i < cfuncs; i++) {
  1387. memcpy(p, ilink_info->pvJumpEntry, ilink_info->cbJumpEntry);
  1388. p += ilink_info->cbJumpEntry;
  1389. }
  1390. p = (BYTE *) pvRaw + ilink_info->address_offset;
  1391. if (fPowerMac) {
  1392. // In PowerMac we never want to use the first entry
  1393. // because we rely on the offset being not zero
  1394. // for any of the function that goes thru jump table
  1395. p += CbJumpEntry();
  1396. // So the pad is decreased by that amount
  1397. pconJmpTbl->cbPad -= CbJumpEntry();
  1398. }
  1399. // Walk the external symbol table
  1400. InitEnumerateExternals(pimage->pst);
  1401. cfuncs = 0;
  1402. while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
  1403. if (!(pext->Flags & EXTERN_DEFINED) || !pext->pcon || FIsLibPCON(pext->pcon)) {
  1404. // Ignore undefined externs
  1405. continue;
  1406. }
  1407. // check to see if this is a function
  1408. if (ISFCN(pext->ImageSymbol.Type)) {
  1409. // Hammer in func addr
  1410. offset = (LONG)(pext->pcon->rva + pext->ImageSymbol.Value) -
  1411. (LONG)(pconJmpTbl->rva + (p - (BYTE *) pvRaw) +
  1412. (fPowerMac ? 0 : sizeof(LONG)) );
  1413. DBEXEC(DB_DUMPJMPTBL, DBPRINT("Offset= %.8lx, symval=%.8lx, pconrva=%.8lx, sym=%s\n",
  1414. offset, pext->ImageSymbol.Value,pext->pcon->rva,
  1415. SzNamePext(pext, pimage->pst)));
  1416. if (fPowerMac) {
  1417. if (!TEST32MBCODERANGE(offset)) {
  1418. // Bail out of linking because the offset is greater than 26 bits
  1419. Error(NULL, TOOFAR, SzNamePext(pext, pimage->pst));
  1420. } else {
  1421. offset = DwSwap(PPC_BRANCH | (offset & PPC_ADDR_MASK));
  1422. }
  1423. }
  1424. *(LONG UNALIGNED *) p = offset;
  1425. p += CbJumpEntry();
  1426. // store the offset in pconjmptbl for the symbol
  1427. pext->Offset =
  1428. p - (BYTE *) pvRaw - CbJumpEntry(); // offset is to addr
  1429. assert(pext->Offset);
  1430. cfuncs++;
  1431. }
  1432. }
  1433. TerminateEnumerateExternals(pimage->pst);
  1434. // Just checking
  1435. assert(cfuncs == cextFCNs);
  1436. if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R4000) &&
  1437. (pimage->Switch.Link.fPadMipsCode == TRUE)) {
  1438. DWORD cbAdjust;
  1439. if (!ComputeTextPad(pconJmpTbl->rva,
  1440. (DWORD *) pvRaw,
  1441. pconJmpTbl->cbRawData,
  1442. 4096L,
  1443. &cbAdjust)) {
  1444. // Cannot adjust text, we're in big trouble
  1445. FatalPcon(pconJmpTbl, TEXTPADFAILED, cbAdjust, pconJmpTbl->rva);
  1446. }
  1447. assert(cbAdjust == 0);
  1448. }
  1449. // Pad the the remaining space with int3
  1450. p = (BYTE *) pvRaw + pconJmpTbl->cbRawData - pconJmpTbl->cbPad;
  1451. memset(p, ilink_info->bPad, pconJmpTbl->cbPad);
  1452. // Build the array of addr to which the thunks point to
  1453. if (pimage->Switch.Link.DebugInfo != None) {
  1454. *pcThunk = cfuncs;
  1455. BuildThunkMap(pvRaw, prgThunkMapOff, *pcThunk);
  1456. }
  1457. // Write out jump table
  1458. FileSeek(FileWriteHandle, pconJmpTbl->foRawDataDest, SEEK_SET);
  1459. FileWrite(FileWriteHandle, pvRaw, pconJmpTbl->cbRawData);
  1460. FileSeek(FileWriteHandle, 0, SEEK_SET);
  1461. DBEXEC(DB_DUMPJMPTBL, DBPRINT("cextFCNs= %.8lx, cfuncs= %.8lx\n", cextFCNs, cfuncs));
  1462. DBEXEC(DB_DUMPJMPTBL, DumpJmpTbl(pconJmpTbl, pvRaw));
  1463. FreePv(pvRaw);
  1464. }
  1465. void
  1466. UpdateJumpTable (
  1467. PIMAGE pimage,
  1468. DWORD **prgThunkMapOff,
  1469. DWORD *pcThunk
  1470. )
  1471. /*++
  1472. Routine Description:
  1473. Updates the existing jmp table with new addr of old
  1474. functions and adds entries for the new functions.
  1475. Is it faster to just write out the individual thunks?
  1476. Arguments:
  1477. pimage - ptr to image.
  1478. Return Value:
  1479. None.
  1480. --*/
  1481. {
  1482. PVOID pvRaw = NULL;
  1483. LONG offset;
  1484. BYTE *p;
  1485. PEXTERNAL pext;
  1486. BYTE *pvNew; // new thunks get written here
  1487. if (!pconJmpTbl) {
  1488. return;
  1489. }
  1490. // allocate space for raw data
  1491. pvRaw = PvAllocZ(pconJmpTbl->cbRawData);
  1492. // read in jump table
  1493. FileSeek(FileWriteHandle, pconJmpTbl->foRawDataDest, SEEK_SET);
  1494. FileRead(FileWriteHandle, pvRaw, pconJmpTbl->cbRawData);
  1495. DBEXEC(DB_DUMPJMPTBL, DBPRINT("\n---BEFORE---\n"));
  1496. DBEXEC(DB_DUMPJMPTBL, DumpJmpTbl(pconJmpTbl, pvRaw));
  1497. pvNew = (BYTE *) pvRaw + (pconJmpTbl->cbRawData - pconJmpTbl->cbPad);
  1498. // Walk the external symbol table
  1499. InitEnumerateExternals(pimage->pst);
  1500. while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
  1501. // consider only the dirty & new funcs
  1502. if (!(pext->Flags & EXTERN_DIRTY) && !(pext->Flags & EXTERN_NEWFUNC)) {
  1503. continue;
  1504. }
  1505. if (FIsLibPCON(pext->pcon)) {
  1506. // We ignore lib functions
  1507. continue;
  1508. }
  1509. // Check to see if this is a function
  1510. if (pext->Flags & EXTERN_NEWFUNC) {
  1511. assert(!pext->Offset);
  1512. pext->Flags &= ~(EXTERN_NEWFUNC);
  1513. // Check to see if we are about to run over jmp tbl space
  1514. if ((pvNew + ilink_info->cbJumpEntry) > (BYTE *) pvRaw + pconJmpTbl->cbRawData) {
  1515. TerminateEnumerateExternals(pimage->pst);
  1516. FreePv(pvRaw);
  1517. errInc = errJmpTblOverflow;
  1518. return;
  1519. }
  1520. if (fPowerMac) {
  1521. RESET_BIT (pext, sy_NEWSYMBOL);
  1522. }
  1523. // Hammer in thunk & new func addr
  1524. memcpy(pvNew, ilink_info->pvJumpEntry, ilink_info->cbJumpEntry);
  1525. pvNew += ilink_info->address_offset;
  1526. offset = (LONG)(pext->pcon->rva + pext->ImageSymbol.Value) -
  1527. (LONG)(pconJmpTbl->rva + (pvNew - (BYTE *) pvRaw) +
  1528. (fPowerMac ? 0 : sizeof(LONG)) );
  1529. if (fPowerMac) {
  1530. if (!TEST32MBCODERANGE(offset)) {
  1531. // Bail out of linking because the offset is greater than 26 bits
  1532. Error(NULL, TOOFAR, SzNamePext(pext, pimage->pst));
  1533. } else {
  1534. offset = DwSwap(PPC_BRANCH | (offset & PPC_ADDR_MASK));
  1535. }
  1536. }
  1537. *(LONG UNALIGNED *) pvNew = offset;
  1538. pvNew += 4;
  1539. // store the offset in pconjmptbl for the symbol
  1540. pext->Offset =
  1541. pvNew - (BYTE *) pvRaw - CbJumpEntry() + ilink_info->address_offset; // +N to go past opcode
  1542. // reduce the pad available
  1543. pconJmpTbl->cbPad -= CbJumpEntry();
  1544. } else {
  1545. // Old func whose addr has changed
  1546. assert(pext->Offset);
  1547. pext->Flags &= ~(EXTERN_DIRTY);
  1548. // Hammer in new address
  1549. p = (BYTE *) pvRaw + pext->Offset;
  1550. offset = (LONG)(pext->pcon->rva + pext->ImageSymbol.Value) -
  1551. (LONG)(pconJmpTbl->rva + (p - (BYTE *) pvRaw) +
  1552. (fPowerMac ? 0 : sizeof(LONG)) );
  1553. if (fPowerMac) {
  1554. if ( !TEST32MBCODERANGE(offset)) {
  1555. // Bail out of linking because the offset is greater than 26 bits
  1556. Error(NULL, TOOFAR, SzNamePext(pext, pimage->pst));
  1557. } else {
  1558. offset = (offset & PPC_ADDR_MASK) | PPC_BRANCH;
  1559. SwapBytes(&offset, 4);
  1560. }
  1561. }
  1562. *(LONG UNALIGNED *) p = offset;
  1563. }
  1564. }
  1565. TerminateEnumerateExternals(pimage->pst);
  1566. if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R4000) &&
  1567. (pimage->Switch.Link.fPadMipsCode == TRUE)) {
  1568. DWORD cbAdjust;
  1569. if (!ComputeTextPad(pconJmpTbl->rva,
  1570. (DWORD *) pvRaw,
  1571. pconJmpTbl->cbRawData,
  1572. 4096L,
  1573. &cbAdjust)) {
  1574. // Cannot adjust text, we're in big trouble
  1575. FatalPcon(pconJmpTbl, TEXTPADFAILED, cbAdjust, pconJmpTbl->rva);
  1576. }
  1577. assert(cbAdjust == 0);
  1578. }
  1579. // Write out jump table
  1580. FileSeek(FileWriteHandle, pconJmpTbl->foRawDataDest, SEEK_SET);
  1581. FileWrite(FileWriteHandle, pvRaw, pconJmpTbl->cbRawData);
  1582. FileSeek(FileWriteHandle, 0, SEEK_SET);
  1583. // Build array of addr for disasm support
  1584. if (pimage->Switch.Link.DebugInfo != None) {
  1585. *pcThunk = ((BYTE *) pvNew - (BYTE *) pvRaw) / CbJumpEntry();
  1586. BuildThunkMap(pvRaw, prgThunkMapOff, *pcThunk);
  1587. }
  1588. DBEXEC(DB_DUMPJMPTBL, DBPRINT("\n---AFTER---\n"));
  1589. DBEXEC(DB_DUMPJMPTBL, DumpJmpTbl(pconJmpTbl, pvRaw));
  1590. FreePv(pvRaw);
  1591. }
  1592. PMOD
  1593. PmodFindPrevPMOD (
  1594. PMOD pmod
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. Finds the mod before this.
  1599. Arguments:
  1600. pmod - pmod
  1601. Return Value:
  1602. PMOD prior to this or NULL
  1603. --*/
  1604. {
  1605. ENM_MOD enm_mod;
  1606. PMOD pmodP = NULL;
  1607. assert(pmod);
  1608. // walk the list of pmods
  1609. InitEnmMod(&enm_mod, pmod->plibBack);
  1610. while (FNextEnmMod(&enm_mod)) {
  1611. if (enm_mod.pmod == pmod) {
  1612. return pmodP;
  1613. }
  1614. pmodP = enm_mod.pmod;
  1615. }
  1616. EndEnmMod(&enm_mod);
  1617. return(NULL);
  1618. }
  1619. PCON
  1620. PconFindPrevPCON (
  1621. PCON pcon
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. Finds the previous pcon.
  1626. Arguments:
  1627. pcon - pcon
  1628. Return Value:
  1629. None.
  1630. --*/
  1631. {
  1632. PGRP pgrp;
  1633. PCON pconP = NULL;
  1634. ENM_DST enm_dst;
  1635. assert(pcon);
  1636. // start at the top of the group
  1637. pgrp = pcon->pgrpBack;
  1638. InitEnmDst(&enm_dst, pgrp);
  1639. while (FNextEnmDst(&enm_dst)) {
  1640. if (enm_dst.pcon == pcon) {
  1641. return pconP;
  1642. }
  1643. pconP = enm_dst.pcon;
  1644. }
  1645. EndEnmDst(&enm_dst);
  1646. assert(0);
  1647. return(NULL);
  1648. }
  1649. PCON
  1650. PconFindOldPMOD (
  1651. PMOD pmodO,
  1652. PCON pconN
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. Finds a matching PCON in the old mod
  1657. Arguments:
  1658. pmodO - old mod
  1659. pconN - con from new mod
  1660. Return Value:
  1661. Matching PCON in old mod or NULL
  1662. --*/
  1663. {
  1664. PCON pcon;
  1665. DWORD i;
  1666. if (!pmodO) {
  1667. return NULL;
  1668. }
  1669. assert(pmodO);
  1670. // walk the list of pcons
  1671. for (i = 0; i < pmodO->ccon; i++) {
  1672. pcon = RgconPMOD(pmodO) + i;
  1673. // seen already?
  1674. if (!pcon->foRawDataDest) {
  1675. continue;
  1676. }
  1677. // pcons match if they belong to same
  1678. // group & have same flags (turn off FIXED bit)
  1679. if (pcon->pgrpBack == pconN->pgrpBack &&
  1680. pcon->flags == pconN->flags) {
  1681. return(pcon);
  1682. }
  1683. }
  1684. // didn't find a match
  1685. return NULL;
  1686. }
  1687. void
  1688. ZeroPCONSpace (
  1689. PCON pcon
  1690. )
  1691. /*++
  1692. Routine Description:
  1693. Zeros out space occupied by a pcon in the output file.
  1694. Arguments:
  1695. pcon - pcon to be zeroed out.
  1696. Return Value:
  1697. None.
  1698. --*/
  1699. {
  1700. PVOID pvRawData;
  1701. assert(pcon);
  1702. // ignore PCONs that don't get written out to the output file.
  1703. if (pcon->flags & IMAGE_SCN_LNK_REMOVE ||
  1704. !pcon->cbRawData ||
  1705. FetchContent(pcon->flags) == IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
  1706. return;
  1707. }
  1708. assert(pcon->foRawDataDest != 0);
  1709. // allocate a chunk for pcon and set to either int3 or zero
  1710. pvRawData = PvAlloc(pcon->cbRawData);
  1711. if (FetchContent(pcon->flags) == IMAGE_SCN_CNT_CODE) {
  1712. memset(pvRawData, ilink_info->bPad, pcon->cbRawData);
  1713. }
  1714. // zero out space in output file
  1715. FileSeek(FileWriteHandle, pcon->foRawDataDest, SEEK_SET);
  1716. FileWrite(FileWriteHandle, pvRawData, pcon->cbRawData);
  1717. FreePv(pvRawData);
  1718. }
  1719. void
  1720. FreePCONSpace(
  1721. PCON pconP,
  1722. PCON pconC,
  1723. PIMAGE pimage
  1724. )
  1725. /*++
  1726. Routine Description:
  1727. Frees up space. Makes it pad of the prior pcon.
  1728. Arguments:
  1729. pconP - previous pcon
  1730. pconC - pcon to be free'd (space) up
  1731. pimage - ptr to IMAGE
  1732. Return Value:
  1733. None.
  1734. --*/
  1735. {
  1736. assert(pconC);
  1737. if (!(fPowerMac && (PgrpPCON(pconC) == pgrpPdata))) {
  1738. // Pdata (C++ EH for PowerMac), do not zero out pcon
  1739. // because this is done in PDATAUpdate in ipdata.cpp
  1740. ZeroPCONSpace(pconC);
  1741. }
  1742. if (pconP) {
  1743. // A previous pcon exists
  1744. assert((pconP->flags & IMAGE_SCN_LNK_REMOVE) == 0);
  1745. pconP->cbRawData += pconC->cbRawData;
  1746. pconP->cbPad += (WORD) pconC->cbRawData;
  1747. pconP->pconNext = pconC->pconNext;
  1748. } else {
  1749. PCON pcon;
  1750. // This is the first pcon in the grp
  1751. // create a dummy PCON at the front of the group
  1752. // check to make sure that the first PCON in the image
  1753. // is pconC.
  1754. if (pconC != pconC->pgrpBack->pconNext) {
  1755. pcon = pconC->pgrpBack->pconNext;
  1756. while (pcon != pconC) {
  1757. assert(pcon->flags & IMAGE_SCN_LNK_REMOVE);
  1758. pcon = pcon->pconNext;
  1759. }
  1760. }
  1761. pcon = (PCON) Calloc(1, sizeof(CON));
  1762. pcon->pgrpBack = pconC->pgrpBack;
  1763. pcon->pmodBack = pmodLinkerDefined;
  1764. pmodLinkerDefined->icon++;
  1765. pcon->cbPad = pcon->cbRawData = pconC->cbRawData;
  1766. pcon->rva = pconC->rva;
  1767. pcon->foRawDataDest = pconC->foRawDataDest;
  1768. pcon->pconNext = pconC->pconNext; // unused cons bypassed - that's ok
  1769. pconC->pgrpBack->pconNext = pcon;
  1770. }
  1771. }
  1772. void
  1773. OverflowInPCON (
  1774. PCON pconN,
  1775. PCON pconO,
  1776. PIMAGE pimage
  1777. )
  1778. /*++
  1779. Routine Description:
  1780. Handles the case where a CON has overflowed its pad.
  1781. Arguments:
  1782. pconN - new pcon of the changed module
  1783. pconO - old pcon
  1784. pimage - ptr to IMAGE
  1785. Return Value:
  1786. None.
  1787. --*/
  1788. {
  1789. PCON pconP;
  1790. // Free up the space occupied currently by the pcon
  1791. pconP = PconFindPrevPCON(pconO);
  1792. while (pconP && ((pconP->flags & IMAGE_SCN_LNK_REMOVE) != 0)) {
  1793. pconP = PconFindPrevPCON(pconP);
  1794. }
  1795. FreePCONSpace(pconP, pconO, pimage);
  1796. // Find a slot for the new pcon
  1797. FindSlotForPCON(pconN);
  1798. // Mark pcon as seen
  1799. pconO->foRawDataDest = 0;
  1800. }
  1801. void
  1802. GrowPCON (
  1803. PCON pconN,
  1804. PCON pconO
  1805. )
  1806. /*++
  1807. Routine Description:
  1808. pcon has grown (incr/decr) to fit the current spot
  1809. Arguments:
  1810. pconN(ew) - pcon of the modified mod
  1811. pconO(ld) - pcon of the old mod
  1812. Return Value:
  1813. None.
  1814. --*/
  1815. {
  1816. PCON pconP;
  1817. // assign values
  1818. pconN->foRawDataDest = pconO->foRawDataDest;
  1819. pconN->rva = pconO->rva;
  1820. pconN->cbPad = (WORD) (pconO->cbRawData - pconN->cbRawData);
  1821. pconN->cbRawData += pconN->cbPad;
  1822. // find prev pcon and chain up the
  1823. // new pcon into the image map
  1824. pconP = PconFindPrevPCON(pconO);
  1825. if (pconP) {
  1826. pconP->pconNext = pconN;
  1827. } else {
  1828. pconN->pgrpBack->pconNext = pconN;
  1829. }
  1830. pconN->pconNext = pconO->pconNext;
  1831. // mark old pcon as seen.
  1832. pconO->foRawDataDest = 0;
  1833. }
  1834. void
  1835. FindSlotForPCON (
  1836. PCON pcon
  1837. )
  1838. /*++
  1839. Routine Description:
  1840. Moves pcon to the first available slot (alternative
  1841. strategies? best fit?)
  1842. Assumes that pcons are in proper rva order.
  1843. Arguments:
  1844. pcon - pcon that is to be moved
  1845. Return Value:
  1846. None.
  1847. --*/
  1848. {
  1849. PGRP pgrp;
  1850. PCON pconC;
  1851. BOOL fFound = 0;
  1852. DWORD rva, cbPad, cbRaw;
  1853. ENM_DST enm_dst;
  1854. assert(pcon);
  1855. assert(pcon->pgrpBack);
  1856. pgrp = pcon->pgrpBack;
  1857. // search within the group
  1858. InitEnmDst(&enm_dst, pgrp);
  1859. while (FNextEnmDst(&enm_dst)) {
  1860. pconC = enm_dst.pcon;
  1861. // skip unusable pcons
  1862. if (pconC->flags & IMAGE_SCN_LNK_REMOVE) {
  1863. continue;
  1864. }
  1865. // cannot use the pad of jmptbl pcon. It is committed space.
  1866. if (pconC == pconJmpTbl) {
  1867. continue;
  1868. }
  1869. if (fPowerMac) {
  1870. // cannot use the pad of PowerMacLoader, TOC Table,
  1871. // TOC descriptors, Glue Code pcons. They are all committed space.
  1872. if (pconC == pconPowerMacLoader || pconC == pconTocTable ||
  1873. pconC == pconTocDescriptors || pconC == pconGlueCode ||
  1874. pconC == pconMppcFuncTable) {
  1875. continue;
  1876. }
  1877. }
  1878. // do we have enough room for this pcon
  1879. if (pcon->cbRawData > pconC->cbPad ) {
  1880. continue;
  1881. }
  1882. // one more check to ensure padding requirements
  1883. cbRaw = pconC->cbRawData - pconC->cbPad; // raw data of existing PCON
  1884. rva = pconC->rva + cbRaw;
  1885. cbPad = RvaAlign(rva, pcon->flags) - rva; // pad for PCON being inserted
  1886. if (pcon->cbRawData + cbPad > pconC->cbPad) {
  1887. continue;
  1888. }
  1889. // found a slot
  1890. fFound = 1;
  1891. // assign values for PCON being inserted. Note that the pad
  1892. // calculated above becomes part of the existing PCON.
  1893. assert ((pconC->flags & IMAGE_SCN_LNK_REMOVE) == 0);
  1894. assert(pconC->rva != 0);
  1895. pcon->rva = pconC->rva + cbRaw + cbPad;
  1896. pcon->foRawDataDest = pconC->foRawDataDest + cbRaw + cbPad;
  1897. pcon->cbPad = (WORD)((DWORD)pconC->cbPad - (cbPad + pcon->cbRawData));
  1898. pcon->cbRawData += pcon->cbPad;
  1899. pcon->pconNext = pconC->pconNext;
  1900. // update values for existing CON
  1901. pconC->cbPad = (WORD)cbPad;
  1902. pconC->cbRawData = cbRaw + cbPad;
  1903. pconC->pconNext = pcon;
  1904. break;
  1905. }
  1906. EndEnmDst(&enm_dst);
  1907. // done
  1908. if (!fFound) {
  1909. #ifdef INSTRUMENT
  1910. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEvent, "failed to find a slot for pcon: %-8.8s",
  1911. pcon->pgrpBack->szName);
  1912. #endif // INSTRUMENT
  1913. errInc = errCalcPtrs;
  1914. }
  1915. }
  1916. void
  1917. FreePMOD (
  1918. PIMAGE pimage,
  1919. PMOD pmodO
  1920. )
  1921. /*++
  1922. Routine Description:
  1923. Frees up space.
  1924. Arguments:
  1925. pmodO - old mod
  1926. Return Value:
  1927. None.
  1928. --*/
  1929. {
  1930. DWORD i;
  1931. PCON pconP, pcon;
  1932. // free up space occupied by unseen pcons
  1933. for (i = 0; i < pmodO->ccon; i++) {
  1934. pcon = RgconPMOD(pmodO) + i;
  1935. // Seen already?
  1936. if (!pcon->foRawDataDest) {
  1937. continue;
  1938. }
  1939. pconP = PconFindPrevPCON(pcon);
  1940. while (pconP && ((pconP->flags & IMAGE_SCN_LNK_REMOVE) != 0)) {
  1941. pconP = PconFindPrevPCON(pconP);
  1942. }
  1943. FreePCONSpace(pconP, pcon, pimage);
  1944. if (fPowerMac && (PgrpPCON(pcon) == pgrpPdata)) {
  1945. // Pdata (C++ EH for PowerMac), do not delete base relocs
  1946. continue;
  1947. }
  1948. // zap any base relocs
  1949. if (fPowerMac) {
  1950. CHAR szBuffer[12];
  1951. // Code is pure in PowerMac and so there won't be any
  1952. // relocations in .text and .drectve sections
  1953. if (!(pcon->flags & IMAGE_SCN_CNT_CODE ||
  1954. pcon->flags & IMAGE_SCN_LNK_INFO)) {
  1955. AddArgumentToList(&ZappedBaseRelocList,
  1956. SzDup(_itoa(pcon->rva, szBuffer, 10)),
  1957. SzDup(_itoa(pcon->cbRawData - pcon->cbPad, szBuffer, 10)) );
  1958. }
  1959. } else {
  1960. // Intel, MIPS, and others
  1961. DeleteBaseRelocs(&pimage->bri,
  1962. pcon->rva,
  1963. pcon->cbRawData - pcon->cbPad);
  1964. }
  1965. }
  1966. // Free up memory occupied by PMOD (LATER)
  1967. }
  1968. void
  1969. AllocSpaceForImportPCON (
  1970. PCON pcon
  1971. )
  1972. /*++
  1973. Routine Description:
  1974. Allocates space for this .idata PCON.
  1975. Arguments:
  1976. pcon - ptr to a .idata pcon
  1977. Return Value:
  1978. None.
  1979. --*/
  1980. {
  1981. ENM_DST enm_dst;
  1982. PPCON ppcon;
  1983. if (!pgrpIdata$4) {
  1984. pgrpIdata$4 = PgrpFind(psecImportDescriptor, ".idata$4");
  1985. pgrpIdata$5 = PgrpFind(psecImportDescriptor, ".idata$5");
  1986. pgrpIdata$6 = PgrpFind(psecImportDescriptor, ".idata$6");
  1987. if (!pgrpIdata$4 || !pgrpIdata$5 || !pgrpIdata$6) {
  1988. #ifdef INSTRUMENT
  1989. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEvent, "failed to find a slot for pcon: %-8.8s",
  1990. pcon->pgrpBack->szName);
  1991. #endif // INSTRUMENT
  1992. errInc = errCalcPtrs;
  1993. return;
  1994. }
  1995. } // end if
  1996. assert(pgrpIdata$5);
  1997. assert(pgrpIdata$6);
  1998. if (pcon->pgrpBack != pgrpIdata$4 &&
  1999. pcon->pgrpBack != pgrpIdata$5 &&
  2000. pcon->pgrpBack != pgrpIdata$6) {
  2001. // PCON belongs to groups other than .idata${4,5,6}
  2002. errInc = errCalcPtrs;
  2003. return;
  2004. }
  2005. // for .idata$6 pcon is inserted like any other pcon
  2006. if (pcon->pgrpBack == pgrpIdata$6) {
  2007. FindSlotForPCON(pcon);
  2008. return;
  2009. }
  2010. // for .idata$5, .idata$4 pcons inserted in proper
  2011. // place (same DLL) and order (before NULL entry)
  2012. InitEnmDst(&enm_dst, pcon->pgrpBack);
  2013. ppcon = &pcon->pgrpBack->pconNext;
  2014. while (FNextEnmDst(&enm_dst)) {
  2015. if (strcmp(SzObjNamePCON(enm_dst.pcon), SzObjNamePCON(pcon)) ||
  2016. enm_dst.pcon->cbPad < pcon->cbRawData) {
  2017. ppcon = &enm_dst.pcon->pconNext;
  2018. continue;
  2019. }
  2020. // fill in fields for new CON
  2021. pcon->rva = enm_dst.pcon->rva;
  2022. pcon->foRawDataDest = enm_dst.pcon->foRawDataDest;
  2023. pcon->pconNext = enm_dst.pcon;
  2024. // update existing pcon fields
  2025. enm_dst.pcon->foRawDataDest += pcon->cbRawData;
  2026. enm_dst.pcon->rva += pcon->cbRawData;
  2027. enm_dst.pcon->cbRawData -= pcon->cbRawData;
  2028. enm_dst.pcon->cbPad -= pcon->cbRawData;
  2029. // update previous con's next ptr
  2030. (*ppcon) = pcon;
  2031. EndEnmDst(&enm_dst);
  2032. return;
  2033. }
  2034. EndEnmDst(&enm_dst);
  2035. errInc = errCalcPtrs;
  2036. }
  2037. void
  2038. CalcPtrsPMOD (
  2039. PMOD pmodN,
  2040. PMOD pmodO,
  2041. PIMAGE pimage
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. Calculates new addresses for all the changed CONs.
  2046. If it is not possible to assign an address, function
  2047. returns after setting the appropriate error value in errInc.
  2048. Arguments:
  2049. pmodN - Current module (modified)
  2050. pmodO - Previous module by the same name (if any)
  2051. pimage - ptr to EXE image
  2052. Return Value:
  2053. None.
  2054. --*/
  2055. {
  2056. PMOD pmodP;
  2057. PCON pconN;
  2058. PCON pconO;
  2059. ENM_SRC enm_src;
  2060. PEXTERNAL pext;
  2061. DWORD AlphaBsrCount = 0;
  2062. SzComNamePMOD(pmodN, InternalError.CombinedFilenames);
  2063. DBEXEC(DB_INCRCALCPTRS, DBPRINT("\nMODULE = %s\n", InternalError.CombinedFilenames));
  2064. #ifdef INSTRUMENT
  2065. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEvent, "mod: %s", InternalError.CombinedFilenames);
  2066. #endif // INSTRUMENT
  2067. // for each pcon in new mod, find a matching con
  2068. // in the old module if possible
  2069. InitEnmSrc(&enm_src, pmodN);
  2070. while (FNextEnmSrc(&enm_src)) {
  2071. pconN = enm_src.pcon;
  2072. // Ignore ignoreable pcons. eg zero-sized pcons OR COMDATs not included;
  2073. // debug sections can be ignored as well.
  2074. if (pconN->flags & IMAGE_SCN_LNK_REMOVE || PsecPCON(pconN) == psecDebug) {
  2075. continue;
  2076. }
  2077. // Check to see if this pcon is an import data pcon
  2078. if (PsecPCON(pconN) == psecImportDescriptor) {
  2079. AllocSpaceForImportPCON(pconN);
  2080. if (errInc != errNone) {
  2081. return;
  2082. }
  2083. continue;
  2084. }
  2085. // Find a matching pcon
  2086. pconO = PconFindOldPMOD(pmodO, pconN);
  2087. if (!pconO) {
  2088. // New pcon
  2089. DBEXEC(DB_INCRCALCPTRS, DBPRINT("NEW %.8s cb=%.8lx\n",
  2090. pconN->pgrpBack->szName,
  2091. pconN->cbRawData));
  2092. #ifdef INSTRUMENT
  2093. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEvent, "new pcon %.8s cb=0x%.8lx",
  2094. pconN->pgrpBack->szName, pconN->cbRawData);
  2095. #endif // INSTRUMENT
  2096. FindSlotForPCON(pconN);
  2097. } else {
  2098. // Zap any relocs right away
  2099. if (fPowerMac) {
  2100. CHAR szBuffer[12];
  2101. // Code is pure in PowerMac and so there won't be any
  2102. // relocations in .text and .drectve sections
  2103. if (!(pconO->flags & IMAGE_SCN_CNT_CODE ||
  2104. pconO->flags & IMAGE_SCN_LNK_INFO ||
  2105. (PgrpPCON(pconO) == pgrpPdata))) {
  2106. AddArgumentToList(&ZappedBaseRelocList,
  2107. SzDup(_itoa(pconO->rva, szBuffer, 10)),
  2108. SzDup(_itoa(pconO->cbRawData - pconO->cbPad, szBuffer, 10)) );
  2109. }
  2110. } else {
  2111. // Intel, MIPS, and others
  2112. DeleteBaseRelocs(&pimage->bri, pconO->rva, pconO->cbRawData - pconO->cbPad);
  2113. }
  2114. if (pconN->cbRawData <= pconO->cbRawData) {
  2115. // Got enough room
  2116. DBEXEC(DB_INCRCALCPTRS, DBPRINT("GRW %.8s cb(o)=%.8lx cb(n)=%.8lx\n",
  2117. pconN->pgrpBack->szName,
  2118. pconO->cbRawData,
  2119. pconN->cbRawData));
  2120. #ifdef INSTRUMENT
  2121. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEvent, "pad %.8s cb(n):0x%.8lx cb(o):0x%.8lx cb(pad):0x%.4x",
  2122. pconN->pgrpBack->szName, pconN->cbRawData, pconO->cbRawData-pconO->cbPad,
  2123. pconO->cbPad);
  2124. #endif // INSTRUMENT
  2125. GrowPCON(pconN, pconO);
  2126. } else {
  2127. // Not enough room
  2128. DBEXEC(DB_INCRCALCPTRS, DBPRINT("OVF %.8s cb(o)=%.8lx cb(n)=%.8lx\n",
  2129. pconN->pgrpBack->szName,
  2130. pconO->cbRawData,
  2131. pconN->cbRawData));
  2132. #ifdef INSTRUMENT
  2133. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEvent, "ovf %.8s cb(n):0x%.8lx cb(o):0x%.8lx cb(pad):0x%.4x",
  2134. pconN->pgrpBack->szName, pconN->cbRawData, pconO->cbRawData-pconO->cbPad,
  2135. pconO->cbPad);
  2136. #endif // INSTRUMENT
  2137. OverflowInPCON(pconN, pconO, pimage);
  2138. }
  2139. }
  2140. if ((FetchContent(pconN->flags) == IMAGE_SCN_CNT_CODE) &&
  2141. (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R4000) &&
  2142. (pimage->Switch.Link.fPadMipsCode == TRUE) ) {
  2143. extern DWORD CheckMIPSCode(PCON);
  2144. DWORD cbAdjust = CheckMIPSCode(pconN);
  2145. if (cbAdjust != 0) {
  2146. if (cbAdjust <= pconN->cbPad) {
  2147. PCON pconP;
  2148. pconP = PconFindPrevPCON(pconN);
  2149. if (pconP) {
  2150. pconN->cbPad -= cbAdjust;
  2151. pconN->cbRawData -= cbAdjust;
  2152. pconN->foRawDataDest += cbAdjust;
  2153. pconN->rva += cbAdjust;
  2154. pconP->cbPad += cbAdjust;
  2155. pconP->cbRawData += cbAdjust;
  2156. } else {
  2157. DBEXEC(DB_INCRCALCPTRS, DBPRINT("CheckMIPSCode returned %d in first pcon\n", cbAdjust));
  2158. errInc = errPdata;
  2159. }
  2160. } else {
  2161. DBEXEC(DB_INCRCALCPTRS, DBPRINT("CheckMIPSCode returned %d\n", cbAdjust));
  2162. errInc = errPdata;
  2163. }
  2164. }
  2165. }
  2166. // Check status
  2167. if (errInc != errNone) {
  2168. return;
  2169. }
  2170. }
  2171. EndEnmSrc(&enm_src);
  2172. // Alloc space for COMMON data
  2173. pext = pmodN->pextFirstDefined;
  2174. while (pext) {
  2175. if (pext->Flags & EXTERN_COMMON) {
  2176. assert(pext->pcon);
  2177. FindSlotForPCON(pext->pcon);
  2178. }
  2179. pext = pext->pextNextDefined;
  2180. }
  2181. // Link in the new module & cut out the old (cmdline objs)
  2182. if (!FIsLibPMOD(pmodN)) {
  2183. pmodP = PmodFindPrevPMOD(pmodO);
  2184. if (pmodP) {
  2185. pmodP->pmodNext = pmodN;
  2186. } else {
  2187. pmodO->plibBack->pmodNext = pmodN;
  2188. }
  2189. pmodN->pmodNext = pmodO->pmodNext;
  2190. pmodN->plibBack = pmodO->plibBack;
  2191. assert(pmodN->imod == 0);
  2192. pmodN->imod = pmodO->imod;
  2193. FreePMOD(pimage, pmodO);
  2194. } else {
  2195. // New objects (from lib search)
  2196. assert(pmodN->plibBack);
  2197. pmodN->imod = NewIModIdx();
  2198. if (pmodN->imod >= IMODIDXMAC) {
  2199. Fatal(NULL, PDBLIMIT, NULL);
  2200. }
  2201. }
  2202. }
  2203. void
  2204. IncrCalcPtrsPMOD (
  2205. PMOD pmod,
  2206. PLIB plib,
  2207. PIMAGE pimage
  2208. )
  2209. {
  2210. PMOD pmodO;
  2211. // for modules from libs there is no existing MOD, we just add new MODs
  2212. if (plib) {
  2213. pmodO = PmodFind(plib, SzOrigFilePMOD(pmod), FoMemberPMOD(pmod));
  2214. } else {
  2215. pmodO = NULL;
  2216. }
  2217. CalcPtrsPMOD(pmod, pmodO, pimage);
  2218. // check for failures
  2219. if (errInc != errNone) {
  2220. #ifdef INSTRUMENT
  2221. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEvent,
  2222. "failed calcptrs, file: %s", SzOrigFilePMOD(pmod));
  2223. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEnd, NULL);
  2224. #endif // INSTRUMENT
  2225. return;
  2226. }
  2227. // add it to the pass2 list
  2228. DoPass2PMOD(pmod, TRUE);
  2229. // Set flag to tell them they have gone through pass1
  2230. pmod->LnkFlags |= MOD_DidPass1;
  2231. }
  2232. void
  2233. IncrCalcPtrs (
  2234. PIMAGE pimage
  2235. )
  2236. /*++
  2237. Routine Description:
  2238. Calculates new addresses for all the changed mods.
  2239. If it is not possible to assign an address, function
  2240. returns after setting the appropriate error value in errInc.
  2241. Arguments:
  2242. pimage - ptr to EXE image
  2243. Return Value:
  2244. None.
  2245. --*/
  2246. {
  2247. PMOD pmod;
  2248. PMOD pmodNext;
  2249. PLMOD plmod;
  2250. InternalError.Phase = "CalcPtrs";
  2251. InternalError.CombinedFilenames[0] = '\0';
  2252. #ifdef INSTRUMENT
  2253. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeBegin, NULL);
  2254. #endif // INSTRUMENT
  2255. if (!fPowerMac) {
  2256. // setup psec pointers
  2257. psecBaseReloc = PsecFindNoFlags(ReservedSection.BaseReloc.Name, &pimage->secs);
  2258. psecImportDescriptor = PsecFind(NULL,
  2259. ".idata",
  2260. ReservedSection.ImportDescriptor.Characteristics,
  2261. &pimage->secs,
  2262. &pimage->ImgOptHdr);
  2263. }
  2264. // walk the list of modified cmdline objects
  2265. pmod = plibModObjs->pmodNext;
  2266. while (pmod) {
  2267. pmodNext = pmod->pmodNext;
  2268. IncrCalcPtrsPMOD(pmod, pimage->plibCmdLineObjs, pimage);
  2269. if (errInc != errNone) {
  2270. return;
  2271. }
  2272. pmod = pmodNext;
  2273. }
  2274. plibModObjs->pmodNext = NULL;
  2275. // walk the list of new objs (added as aresult of lib srch)
  2276. plmod = plmodNewModsFromLibSrch;
  2277. while (plmod) {
  2278. IncrCalcPtrsPMOD(plmod->pmod, NULL, pimage);
  2279. plmod = plmod->plmodNext;
  2280. }
  2281. FreePLMODList(&plmodNewModsFromLibSrch);
  2282. // check if there is enough space for base relocs
  2283. // For PowerMac this is done at the end in MppcUpdateRelocTable in ppc.c
  2284. fNoBaseRelocs = (pimage->bri.rgfoBlk == NULL);
  2285. if (!fPowerMac && !pimage->Switch.Link.fFixed && pimage->bri.crelFree <
  2286. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) {
  2287. errInc = errBaseReloc;
  2288. #ifdef INSTRUMENT
  2289. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "not enough space for base relocs");
  2290. #endif // INSTRUMENT
  2291. }
  2292. #ifdef INSTRUMENT
  2293. LogNoteEvent(Log, SZILINK, SZCALCPTRS, letypeEnd, NULL);
  2294. #endif // INSTRUMENT
  2295. }
  2296. void
  2297. CollectWeakAndLazyExterns (
  2298. PMOD pmod
  2299. )
  2300. /*++
  2301. Routine Description:
  2302. Collect any weak & lazy externs defined by this mod.
  2303. Arguments:
  2304. pmod - pmod to delete from list
  2305. Return Value:
  2306. None.
  2307. --*/
  2308. {
  2309. PEXTERNAL pext = pmod->pextFirstDefined;
  2310. while (pext) {
  2311. if ((pext->Flags & (EXTERN_WEAK|EXTERN_LAZY)) && pext->Offset) {
  2312. AddExtToList(plpextWeak, TRUE, pext);
  2313. }
  2314. pext = pext->pextNextDefined;
  2315. }
  2316. }
  2317. void
  2318. DeletePMODFromRefList (
  2319. PMODS pmods,
  2320. PMOD pmod
  2321. )
  2322. /*++
  2323. Routine Description:
  2324. Deletes PMODs representing the modified files from the specified list.
  2325. Arguments:
  2326. pmods - ptr to first chunk of PMODs
  2327. pmod - pmod to delete from list
  2328. Return Value:
  2329. None.
  2330. --*/
  2331. {
  2332. while (pmods) {
  2333. PMOD *rgpmod = RgpmodPMODS(pmods);
  2334. DWORD i;
  2335. // is it referenced by a modified file?
  2336. for (i = 0; i < CPMODS; i++) {
  2337. if (rgpmod[i] == pmod) {
  2338. rgpmod[i] = NULL;
  2339. return;
  2340. }
  2341. }
  2342. // next chunk
  2343. pmods = pmods->pmodsNext;
  2344. }
  2345. }
  2346. void
  2347. DeleteReference (
  2348. PEXTERNAL pext,
  2349. PMOD pmod
  2350. )
  2351. /*++
  2352. Routine Description:
  2353. Deletes references to this symbol from modified files.
  2354. Arguments:
  2355. pext - ptr to external
  2356. pmod - ptr to MOD referencing this extern.
  2357. Return Value:
  2358. None.
  2359. --*/
  2360. {
  2361. assert(pext);
  2362. assert(pext->pmodOnly);
  2363. if (pext->Flags & EXTERN_MULT_REFS) {
  2364. DeletePMODFromRefList(pext->pmodsFirst, pmod);
  2365. } else {
  2366. assert(pext->pmodOnly == pmod);
  2367. pext->pmodOnly = NULL;
  2368. }
  2369. }
  2370. void
  2371. RemoveReferencesPMOD (
  2372. PMOD pmod
  2373. )
  2374. /*++
  2375. Routine Description:
  2376. 2) remove references by modified objs to any
  2377. of the symbols.
  2378. Arguments:
  2379. pmod - ptr to a MOD
  2380. Return Value:
  2381. None.
  2382. --*/
  2383. {
  2384. ENM_EXT_LIST enmExtList;
  2385. InitEnmExtList(&enmExtList, pmod->plpextRef);
  2386. while (FNextEnmExtList(&enmExtList)) {
  2387. if (!enmExtList.pext) {
  2388. continue; // sometimes linker removes references (for bss)
  2389. }
  2390. DeleteReference(enmExtList.pext, pmod);
  2391. }
  2392. EndEnmExtList(&enmExtList);
  2393. }
  2394. void
  2395. MarkSymbolsUndefinedPMOD (
  2396. PIMAGE pimage,
  2397. PMOD pmod
  2398. )
  2399. /*++
  2400. Routine Description:
  2401. 1) mark all symbols that were defined in the
  2402. modified objs as UNDEFINED.
  2403. Arguments:
  2404. pimage - ptr to IMAGE
  2405. pmod - ptr to a MOD
  2406. Return Value:
  2407. None.
  2408. --*/
  2409. {
  2410. PEXTERNAL pext = pmod->pextFirstDefined;
  2411. while (pext) {
  2412. PEXTERNAL pextNext = pext->pextNextDefined;
  2413. // if symbol was common free up space used
  2414. if (pext->Flags & EXTERN_COMMON) {
  2415. assert(PmodPCON(pext->pcon) == pmodLinkerDefined);
  2416. // free up space here itself so that we don't have to save the list
  2417. FreePCONSpace(PconFindPrevPCON(pext->pcon), pext->pcon, pimage);
  2418. pext->pcon = NULL;
  2419. }
  2420. // mark symbol as undefined
  2421. SetDefinedExt(pext, FALSE, pimage->pst);
  2422. pext->Flags &= ~(EXTERN_DEFINED | EXTERN_EMITTED);
  2423. pext = pextNext;
  2424. }
  2425. }
  2426. void
  2427. MarkSymbols (
  2428. PIMAGE pimage
  2429. )
  2430. /*++
  2431. Routine Description:
  2432. 1) mark all symbols that were defined in the
  2433. modified objs as UNDEFINED and
  2434. 2) remove references by modified objs to any
  2435. of the symbols.
  2436. Arguments:
  2437. pimage - ptr to EXE image
  2438. Return Value:
  2439. None.
  2440. --*/
  2441. {
  2442. ENM_MOD enm_mod;
  2443. // walk the cmdline objs.
  2444. InitEnmMod(&enm_mod, pimage->plibCmdLineObjs);
  2445. while (FNextEnmMod(&enm_mod)) {
  2446. // gather all "weak" & "lazy" externs.
  2447. CollectWeakAndLazyExterns(enm_mod.pmod);
  2448. // if dirty, undef symbols & remove references
  2449. if (IsDirtyPMOD(enm_mod.pmod)) {
  2450. MarkSymbolsUndefinedPMOD(pimage, enm_mod.pmod);
  2451. RemoveReferencesPMOD(enm_mod.pmod);
  2452. }
  2453. }
  2454. EndEnmMod(&enm_mod);
  2455. // walk the external symbol table
  2456. // REVIEW: we should remove this walk altogether
  2457. if (fPowerMac) {
  2458. PEXTERNAL pext;
  2459. InitEnumerateExternals(pimage->pst);
  2460. while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
  2461. // ignore whatever needs to be ignored
  2462. if ((pext->Flags & EXTERN_IGNORE) || !(pext->Flags & EXTERN_DEFINED) || !pext->pcon) {
  2463. continue;
  2464. }
  2465. // Reset bit for sy_TOCENTRYFIXEDUP so that it will be
  2466. // processed later
  2467. RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
  2468. }
  2469. TerminateEnumerateExternals(pimage->pst);
  2470. }
  2471. }
  2472. ERRINC
  2473. ChckExtSym (
  2474. const char *szSym,
  2475. PIMAGE_SYMBOL psymObj,
  2476. PEXTERNAL pext,
  2477. BOOL fNewSymbol
  2478. )
  2479. /*++
  2480. Routine Description:
  2481. Checks to see if the extern has changed address.
  2482. Arguments:
  2483. szSym = symbol name
  2484. pext - ptr to external (values represent prior link)
  2485. psymObj - symbol being processed
  2486. fNewSymbol - TRUE if new symbol
  2487. Return Value:
  2488. One of the values of ERRINC (errNone, errDataMoved, errJmpTblOverflow)
  2489. --*/
  2490. {
  2491. // is it a func?
  2492. if (ISFCN(psymObj->Type)) {
  2493. // is it new? make sure we have room for one more thunk
  2494. if (fNewSymbol) {
  2495. DBEXEC(DB_SYMPROCESS,DBPRINT("sym= %s (NEW func)\n", szSym));
  2496. pext->Flags |= EXTERN_NEWFUNC;
  2497. // old function
  2498. } else {
  2499. if (pext->ImageSymbol.Value != psymObj->Value) {
  2500. DBEXEC(DB_SYMPROCESS,DBPRINT("sym= %s (func chng)", szSym));
  2501. DBEXEC(DB_SYMPROCESS,DBPRINT(" old addr= %.8lx, new addr= %.8lx\n",
  2502. pext->ImageSymbol.Value, psymObj->Value));
  2503. } else {
  2504. DBEXEC(DB_SYMPROCESS,DBPRINT("sym= %s (func unchng)\n", szSym));
  2505. }
  2506. pext->Flags |= EXTERN_DIRTY;
  2507. // if extern has fixups to it that don't go thru the jump table,
  2508. // need to do a pass2 on all mods that reference it - add it to data list.
  2509. if (pext->Flags & EXTERN_FUNC_FIXUP) {
  2510. AddToLext(&plextMovedData, pext);
  2511. }
  2512. }
  2513. // not a function (data)
  2514. } else {
  2515. if (fNewSymbol) {
  2516. DBEXEC(DB_SYMPROCESS,DBPRINT("sym= %s (NEW data)\n", szSym));
  2517. pext->Flags |= EXTERN_NEWDATA;
  2518. // Log_ILOG1("NEW data sym........: %s", szSym);
  2519. // return(errInc = errDataMoved);
  2520. // not new? check to see if addr has changed.
  2521. } else {
  2522. if (pext->ImageSymbol.Value != psymObj->Value) {
  2523. DBEXEC(DB_SYMPROCESS,DBPRINT("sym= %s (data chng)", szSym));
  2524. DBEXEC(DB_SYMPROCESS,DBPRINT(" old addr= %.8lx, new addr= %.8lx\n",
  2525. pext->ImageSymbol.Value, psymObj->Value));
  2526. #ifdef INSTRUMENT
  2527. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "data moved:%s", szSym);
  2528. #endif // INSTRUMENT
  2529. // return(errInc = errDataMoved);
  2530. } else {
  2531. DBEXEC(DB_SYMPROCESS,DBPRINT("sym= %s (data unchng)\n", szSym));
  2532. }
  2533. // add to list of data whose addresses may change.
  2534. AddToLext(&plextMovedData, pext);
  2535. }
  2536. }
  2537. return errNone;
  2538. }
  2539. ERRINC
  2540. ChckAbsSym (
  2541. const char *szSym,
  2542. PIMAGE_SYMBOL psymObj,
  2543. PEXTERNAL pext,
  2544. BOOL fNewSymbol
  2545. )
  2546. /*++
  2547. Routine Description:
  2548. Checks to see if the absolute sym has changed address.
  2549. Arguments:
  2550. szSym = symbol name
  2551. pext - ptr to external (values represent prior link)
  2552. psymObj - symbol being processed
  2553. fNewSymbol - TRUE if new symbol
  2554. Return Value:
  2555. One of the values of ERRINC (errNone, errDataMoved, errJmpTblOverflow)
  2556. --*/
  2557. {
  2558. // new symbol
  2559. if (fNewSymbol) {
  2560. return errNone;
  2561. }
  2562. // old symbol
  2563. if (psymObj->Value != pext->ImageSymbol.Value) {
  2564. #ifdef INSTRUMENT
  2565. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "chng in abs value: %s", szSym);
  2566. #endif // INSTRUMENT
  2567. return(errInc = errAbsolute);
  2568. }
  2569. return(errNone);
  2570. }
  2571. void
  2572. IncrAllocCommonPMOD (
  2573. PMOD pmod,
  2574. PIMAGE pimage
  2575. )
  2576. {
  2577. PEXTERNAL pext = pmod->pextFirstDefined;
  2578. // alloc a CON for each COMMON symbol
  2579. while (pext) {
  2580. if (pext->Flags & EXTERN_COMMON) {
  2581. assert(!pext->pcon);
  2582. AllocateCommonPEXT(pimage, pext);
  2583. AddToLext(&plextMovedData, pext);
  2584. assert(pext->pcon);
  2585. }
  2586. pext = pext->pextNextDefined;
  2587. }
  2588. }
  2589. void
  2590. IncrAllocateCommon (
  2591. PIMAGE pimage
  2592. )
  2593. {
  2594. PLMOD plmod;
  2595. PMOD pmod, pmodNext;
  2596. // walk the list of modified cmd line objs
  2597. pmod = plibModObjs->pmodNext;
  2598. while (pmod) {
  2599. pmodNext = pmod->pmodNext;
  2600. IncrAllocCommonPMOD(pmod, pimage);
  2601. pmod = pmodNext;
  2602. }
  2603. // walk the list of new objs (added as aresult of lib srch)
  2604. plmod = plmodNewModsFromLibSrch;
  2605. while (plmod) {
  2606. IncrAllocCommonPMOD(plmod->pmod, pimage);
  2607. plmod = plmod->plmodNext;
  2608. }
  2609. }
  2610. void
  2611. InitPconJmpTbl (
  2612. PIMAGE pimage
  2613. )
  2614. /*++
  2615. Routine Description:
  2616. Estimates count of new functions that can be added
  2617. to jump table without overflow.
  2618. Arguments:
  2619. pimage - ptr to EXE image
  2620. Return Value:
  2621. None.
  2622. --*/
  2623. {
  2624. PSEC psecText;
  2625. PGRP pgrpBase;
  2626. // Find .text section
  2627. psecText = PsecFind(NULL,
  2628. ".text",
  2629. IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
  2630. &pimage->secs,
  2631. &pimage->ImgOptHdr);
  2632. if (psecText == NULL) {
  2633. pconJmpTbl = NULL;
  2634. return;
  2635. }
  2636. assert(psecText);
  2637. pgrpBase = psecText->pgrpNext;
  2638. assert(pgrpBase);
  2639. assert(pgrpBase->pconNext);
  2640. // first pcon is jmp tbl
  2641. pconJmpTbl = pgrpBase->pconNext;
  2642. }
  2643. void
  2644. IncrPass1 (
  2645. PIMAGE pimage
  2646. )
  2647. /*++
  2648. Routine Description:
  2649. Does an incremental Pass1.
  2650. Arguments:
  2651. pimage - ptr to EXE image
  2652. Return Value:
  2653. TRUE if it succeeded, FALSE on failure
  2654. --*/
  2655. {
  2656. DWORD i;
  2657. PARGUMENT_LIST arg;
  2658. switch (pimage->ImgFileHdr.Machine) {
  2659. case IMAGE_FILE_MACHINE_ALPHA:
  2660. ilink_info = &ALPHA_ilink;
  2661. cbJumpEntry = ilink_info->cbJumpEntry;
  2662. break;
  2663. case IMAGE_FILE_MACHINE_I386:
  2664. ilink_info = &I386_ilink;
  2665. cbJumpEntry = ilink_info->cbJumpEntry;
  2666. break;
  2667. case IMAGE_FILE_MACHINE_MPPC_601:
  2668. ilink_info = &MPPC_ilink;
  2669. cbJumpEntry = ilink_info->cbJumpEntry;
  2670. break;
  2671. case IMAGE_FILE_MACHINE_R4000:
  2672. case IMAGE_FILE_MACHINE_R10000:
  2673. ilink_info = &MIPS_ilink;
  2674. cbJumpEntry = ilink_info->cbJumpEntry;
  2675. break;
  2676. default:
  2677. assert(FALSE);
  2678. break;
  2679. }
  2680. // setup global ptrs to debug section (always)
  2681. psecDebug = PsecFindNoFlags(".debug", &pimage->secs);
  2682. assert(psecDebug);
  2683. pgrpCvSymbols = PgrpFind(psecDebug, ReservedSection.CvSymbols.Name);
  2684. pgrpCvTypes = PgrpFind(psecDebug, ReservedSection.CvTypes.Name);
  2685. pgrpCvPTypes = PgrpFind(psecDebug, ReservedSection.CvPTypes.Name);
  2686. pgrpFpoData = PgrpFind(psecDebug, ReservedSection.FpoData.Name);
  2687. psecException = PsecFindNoFlags(ReservedSection.Exception.Name, &pimage->secs);
  2688. // create a dummy library node for all modified command line objects
  2689. plibModObjs = PlibNew("inc_lib", 0L, &pimage->libs);
  2690. assert(plibModObjs);
  2691. // exclude dummy library from library search
  2692. plibModObjs->flags |= (LIB_DontSearch | LIB_LinkerDefined);
  2693. // estimate how many new functions can be handled before overflow
  2694. InitPconJmpTbl(pimage);
  2695. // reset count of relocs
  2696. // For PowerMac this is done in ppc.c in MppcDoIncrInit
  2697. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
  2698. #ifdef INSTRUMENT
  2699. LogNoteEvent(Log, SZILINK, SZPASS1, letypeBegin, NULL);
  2700. #endif // INSTRUMENT
  2701. // make a pass over all modified files
  2702. for (i = 0, arg = ModFileList.First;
  2703. i < ModFileList.Count;
  2704. i++, arg = arg->Next) {
  2705. Pass1Arg(arg, pimage, plibModObjs);
  2706. if (errInc != errNone) {
  2707. #ifdef INSTRUMENT
  2708. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "failed pass1, file: %s", arg->OriginalName);
  2709. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEnd, NULL);
  2710. #endif // INSTRUMENT
  2711. return;
  2712. }
  2713. }
  2714. InternalError.CombinedFilenames[0] = '\0';
  2715. // Allocate CONs for EXTERN_COMMON symbols
  2716. // AllocateCommon(pimage);
  2717. #ifdef INSTRUMENT
  2718. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEnd, NULL);
  2719. #endif // INSTRUMENT
  2720. }
  2721. void
  2722. CountBaseRelocsPMOD (
  2723. PMOD pmod,
  2724. DWORD *pcReloc
  2725. )
  2726. /*++
  2727. Routine Description:
  2728. Counts base reloc by counting relocs in each CON of pmod.
  2729. Arguments:
  2730. pmod - pointer to mod.
  2731. pcReloc - ptr to count of base relocs (approximate)
  2732. Return Value:
  2733. none.
  2734. --*/
  2735. {
  2736. (*pcReloc) += pmod->cReloc;
  2737. }
  2738. BOOL
  2739. FCheckRefByPMOD (
  2740. PEXTERNAL pext,
  2741. PMOD pmod,
  2742. PST pst,
  2743. DWORD *pcReloc
  2744. )
  2745. /*++
  2746. Routine Description:
  2747. Checks the reference by this mod.
  2748. Arguments:
  2749. pmod - ptr to a mod
  2750. Return Value:
  2751. FALSE if mod belongs to a lib.
  2752. --*/
  2753. {
  2754. BOOL fIsLib = FIsLibPMOD(pmod);
  2755. // if referenced by a lib - return
  2756. if (fIsLib) {
  2757. #ifdef INSTRUMENT
  2758. const char *szSym = SzNamePext(pext, pst);
  2759. LogNoteEvent(Log, SZILINK, "data-handling", letypeEvent,
  2760. "%s ref by lib %s", szSym, SzOrigFilePMOD(pmod));
  2761. #endif // INSTRUMENT
  2762. return(FALSE);
  2763. }
  2764. // is it referenced by a modified file?
  2765. if (!IsDirtyPMOD(pmod)) {
  2766. #ifdef INSTRUMENT
  2767. const char *szSym = SzNamePext(pext, pst);
  2768. LogNoteEvent(Log, SZILINK, "data-handling", letypeEvent,
  2769. "%s ref by unmod. file %s", szSym, SzOrigFilePMOD(pmod));
  2770. #endif // INSTRUMENT
  2771. // add the module to the pass2 list. no need to do pass1 on it.
  2772. assert (!FDidPass1PMOD(pmod));
  2773. if (!FDidPass1PMOD(pmod)) {
  2774. pmod->LnkFlags |= MOD_NoPass1;
  2775. }
  2776. DoPass2PMOD(pmod, FALSE);
  2777. // count number of base relocs
  2778. // This is no good for PowerMac
  2779. CountBaseRelocsPMOD(pmod, pcReloc);
  2780. }
  2781. return(TRUE);
  2782. }
  2783. BOOL
  2784. FRefByModFilesOnly (
  2785. PEXTERNAL pext,
  2786. PST pst,
  2787. DWORD *pcReloc
  2788. )
  2789. /*++
  2790. Routine Description:
  2791. checks if reference list is subset of modified list.
  2792. Arguments:
  2793. pext - extern (data).
  2794. pst - pointer to symbol table.
  2795. pcReloc - ptr to count of base relocs (approximate)
  2796. Return Value:
  2797. TRUE if reference list is a subset of modified list.
  2798. --*/
  2799. {
  2800. ENM_MOD_EXT enmModExt;
  2801. // no references
  2802. if (!pext->pmodsFirst) {
  2803. return(TRUE);
  2804. }
  2805. // walk the reference list
  2806. InitEnmModExt(&enmModExt, pext);
  2807. while (FNextEnmModExt(&enmModExt)) {
  2808. if (!enmModExt.pmod) {
  2809. // For ilink we remove references
  2810. continue;
  2811. }
  2812. if (!FCheckRefByPMOD(pext, enmModExt.pmod, pst, pcReloc)) {
  2813. return(FALSE);
  2814. }
  2815. }
  2816. return(TRUE);
  2817. }
  2818. void
  2819. CheckIfMovedDataRefByModFiles(
  2820. PST pst,
  2821. DWORD *pcReloc
  2822. )
  2823. /*++
  2824. Routine Description:
  2825. checks if public data moved is referenced only by some subset of modified files.
  2826. Arguments:
  2827. pst - pointer to symbol table.
  2828. pcReloc - On return will hold the count of base relocs on account of including
  2829. new objs for pass2.
  2830. Return Value:
  2831. None. Sets errInc as appropriate.
  2832. --*/
  2833. {
  2834. LEXT *plext = plextMovedData;
  2835. #ifdef INSTRUMENT
  2836. LogNoteEvent(Log, SZILINK, "data-handling", letypeBegin, NULL);
  2837. #endif // INSTRUMENT
  2838. // walk the public data list
  2839. while (plext) {
  2840. PEXTERNAL pext = plext->pext;
  2841. // if the address of extern data hasn't changed, go onto next
  2842. if (pext->FinalValue !=
  2843. (pext->ImageSymbol.Value+pext->pcon->rva)) {
  2844. // data moved!
  2845. if (fPowerMac && READ_BIT(pext, sy_TOCALLOCATED)) {
  2846. // Reset bit for sy_TOCENTRYFIXEDUP so that it will
  2847. // be fixed up in Pass2
  2848. RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
  2849. }
  2850. if (!FRefByModFilesOnly(pext, pst, pcReloc)) {
  2851. // So ensure all references are subset of modified mods.
  2852. // if not pull in objs for a pass2.
  2853. errInc = errDataMoved;
  2854. break;
  2855. }
  2856. #ifdef INSTRUMENT
  2857. {
  2858. const char *szSym = SzNamePext(pext, pst);
  2859. LogNoteEvent(Log, SZILINK, "data-handling", letypeEvent, "%s ref by mod files", szSym);
  2860. }
  2861. #endif // INSTRUMENT
  2862. }
  2863. plext = plext->plextNext;
  2864. }
  2865. #ifdef INSTRUMENT
  2866. LogNoteEvent(Log, SZILINK, "data-handling", letypeEnd, NULL);
  2867. #endif // INSTRUMENT
  2868. }
  2869. void
  2870. ReleaseMovedDataRefList (
  2871. PIMAGE pimage
  2872. )
  2873. /* ++
  2874. ++ */
  2875. {
  2876. LEXT *plext = plextMovedData;
  2877. // free the list of data externs
  2878. while (plextMovedData) {
  2879. if (fPowerMac) {
  2880. MppcFixIncrDataMove(plext->pext, pimage);
  2881. }
  2882. plext = plextMovedData->plextNext;
  2883. FreePv(plextMovedData);
  2884. plextMovedData = plext;
  2885. }
  2886. }
  2887. void
  2888. UpdateDebugDir (
  2889. PIMAGE pimage
  2890. )
  2891. /*++
  2892. Routine Description:
  2893. Updates the debug directory
  2894. Arguments:
  2895. pimage - ptr to EXE image
  2896. Return Value:
  2897. None.
  2898. --*/
  2899. {
  2900. PGRP pgrp;
  2901. PCON pcon;
  2902. PSEC psec;
  2903. if (pimage->Switch.Link.DebugInfo == None) {
  2904. // No debug info
  2905. return;
  2906. }
  2907. // find the cv signature pcon.
  2908. psec = PsecFindNoFlags(".debug", &pimage->secs);
  2909. assert(psec);
  2910. pgrp = PgrpFind(psec, ".debug$H");
  2911. assert(pgrp);
  2912. pcon = pgrp->pconNext;
  2913. assert(pcon);
  2914. // update the directory (assumes pdbfilename remains the same).
  2915. FileSeek(FileWriteHandle, pcon->foRawDataDest, SEEK_SET);
  2916. FileWrite(FileWriteHandle, &nb10i, sizeof(nb10i));
  2917. // update the fpo debug directory
  2918. if (pimage->fpoi.ifpoMax) {
  2919. IMAGE_DEBUG_DIRECTORY debugDir;
  2920. FileSeek(FileWriteHandle, pimage->fpoi.foDebugDir, SEEK_SET);
  2921. FileRead(FileWriteHandle, &debugDir, sizeof(IMAGE_DEBUG_DIRECTORY));
  2922. debugDir.SizeOfData = pimage->fpoi.ifpoMac * sizeof(FPO_DATA);
  2923. FileSeek(FileWriteHandle, -(LONG)sizeof(IMAGE_DEBUG_DIRECTORY), SEEK_CUR);
  2924. FileWrite(FileWriteHandle, &debugDir, sizeof(IMAGE_DEBUG_DIRECTORY));
  2925. }
  2926. }
  2927. void
  2928. UpdateImgHdrsAndComment (
  2929. PIMAGE pimage,
  2930. BOOL fStripRelocs
  2931. )
  2932. /*++
  2933. Routine Description:
  2934. Updates the image headers
  2935. Arguments:
  2936. pimage - ptr to EXE image
  2937. fStripRelocs - TRUE if base relocs need to be stripped.
  2938. Return Value:
  2939. None.
  2940. --*/
  2941. {
  2942. // update image hdr timestamp
  2943. _tzset();
  2944. time((time_t *)&pimage->ImgFileHdr.TimeDateStamp);
  2945. // mark it as fixed (!!!TEMPORARY!!!)
  2946. if (fStripRelocs) {
  2947. pimage->ImgFileHdr.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
  2948. }
  2949. // Is it a PE image.
  2950. if (pimage->Switch.Link.fPE) {
  2951. // Update the stub if necessary
  2952. if (OAStub & OA_UPDATE) {
  2953. FileSeek(FileWriteHandle, 0, SEEK_SET);
  2954. FileWrite(FileWriteHandle, pimage->pbDosHeader, pimage->cbDosHeader);
  2955. }
  2956. CoffHeaderSeek = pimage->cbDosHeader;
  2957. }
  2958. // seek and write out updated image headers
  2959. FileSeek(FileWriteHandle, CoffHeaderSeek, SEEK_SET);
  2960. WriteFileHeader(FileWriteHandle, &pimage->ImgFileHdr);
  2961. // Update optional header & write out as well
  2962. if (fStripRelocs) {
  2963. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
  2964. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
  2965. }
  2966. if (pextGp) {
  2967. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress = pextGp->FinalValue;
  2968. }
  2969. WriteOptionalHeader(FileWriteHandle, &pimage->ImgOptHdr,
  2970. pimage->ImgFileHdr.SizeOfOptionalHeader);
  2971. // update the comment as necessary
  2972. if (OAComment == OA_UPDATE || OAComment == OA_ZERO) {
  2973. DWORD cbComment = __max(pimage->SwitchInfo.cbComment, blkComment.cb);
  2974. BYTE *buf;
  2975. buf = (BYTE *) PvAllocZ(cbComment);
  2976. if (OAComment != OA_ZERO) {
  2977. memcpy(buf, blkComment.pb, blkComment.cb);
  2978. }
  2979. FileSeek(FileWriteHandle,
  2980. pimage->ImgFileHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER), SEEK_CUR);
  2981. FileWrite(FileWriteHandle, buf, cbComment);
  2982. FreePv(buf);
  2983. }
  2984. }
  2985. INT
  2986. IncrBuildImage (
  2987. PPIMAGE ppimage
  2988. )
  2989. /*++
  2990. Routine Description:
  2991. Main driving routine that does the incremental build.
  2992. Arguments:
  2993. pimage - ptr to EXE image
  2994. Return Value:
  2995. 0 on success, -1 on failure
  2996. --*/
  2997. {
  2998. BOOL fLib;
  2999. BOOL fNew;
  3000. BOOL fDel;
  3001. PIMAGE pimage = *ppimage;
  3002. // Instantiate value for linker defined mod
  3003. pmodLinkerDefined = pimage->pmodLinkerDefined;
  3004. // Init begins
  3005. #ifdef INSTRUMENT
  3006. LogNoteEvent(Log, SZILINK, SZINIT, letypeBegin, NULL);
  3007. #endif // INSTRUMENT
  3008. // Check to see if export object has changed
  3009. if (FExpFileChanged(&pimage->ExpInfo)) {
  3010. errInc = errExports;
  3011. #ifdef INSTRUMENT
  3012. LogNoteEvent(Log, SZILINK, SZINIT, letypeEnd, NULL);
  3013. #endif // INSTRUMENT
  3014. if (fTest) {
  3015. PostNote(NULL, EXPORTSCHANGED);
  3016. }
  3017. return CleanUp(ppimage);
  3018. }
  3019. // Determine set of changed files
  3020. InitModFileList(pimage, &fLib, &fNew, &fDel);
  3021. // Open the EXE image
  3022. FileWriteHandle = FileOpen(OutFilename, O_RDWR | O_BINARY, 0);
  3023. fOpenedOutFilename = TRUE;
  3024. // Any changes (LATER: should update the timestamp)
  3025. if (!ModFileList.Count) {
  3026. #ifdef INSTRUMENT
  3027. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "no mod changes");
  3028. #endif // INSTRUMENT
  3029. // Update the headers alone; timestamp and user values updated.
  3030. UpdateImgHdrsAndComment(pimage, FALSE);
  3031. #ifdef INSTRUMENT
  3032. LogNoteEvent(Log, SZILINK, SZINIT, letypeEnd, NULL);
  3033. #endif // INSTRUMENT
  3034. errInc = errNoChanges;
  3035. return CleanUp(ppimage);
  3036. }
  3037. #ifdef INSTRUMENT
  3038. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent,
  3039. "count of mod files: 0x%.4x", ModFileList.Count);
  3040. #endif // INSTRUMENT
  3041. #ifdef INSTRUMENT
  3042. LogNoteEvent(Log, SZILINK, SZINIT, letypeEnd, NULL);
  3043. #endif // INSTRUMENT
  3044. // New files OR deletion of objs OR mod of libs punt
  3045. if (fLib || fNew || fDel) {
  3046. if (fNew) {
  3047. errInc = errFileAdded;
  3048. if (fTest) {
  3049. PostNote(NULL, OBJADDED);
  3050. }
  3051. } else if (fDel) {
  3052. errInc = errFileDeleted;
  3053. if (fTest) {
  3054. PostNote(NULL, OBJREMOVED);
  3055. }
  3056. } else if (fLib) {
  3057. errInc = errLibChanged;
  3058. if (fTest) {
  3059. PostNote(NULL, LIBCHANGED);
  3060. }
  3061. }
  3062. return CleanUp(ppimage);
  3063. }
  3064. // Set up for cleanup
  3065. FilenameArguments = ModFileList;
  3066. if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) {
  3067. fPowerMac = TRUE;
  3068. // Do PowerMac Specific initialization
  3069. MppcDoIncrInit(pimage);
  3070. }
  3071. // Make a pass over symbol table
  3072. DBEXEC(DB_SYMREFS, DumpReferences(pimage)); // DumpReferences() needs fixing.
  3073. MarkSymbols(*ppimage);
  3074. DBEXEC(DB_SYMREFS, DumpReferences(pimage));
  3075. // Do an incr pass1
  3076. InternalError.Phase = "Pass1";
  3077. IncrPass1(pimage);
  3078. if (errInc != errNone) {
  3079. return CleanUp(ppimage);
  3080. }
  3081. if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R4000) ||
  3082. (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R10000) ||
  3083. (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_ALPHA)) {
  3084. // Find the GP symbol
  3085. pextGp = SearchExternSz(pimage->pst, "_gp");
  3086. }
  3087. // Resolve weak externs
  3088. ResolveExistingWeakAndLazyExterns(pimage);
  3089. ResolveWeakExterns(pimage, EXTERN_WEAK);
  3090. if (errInc != errNone) {
  3091. return CleanUp(ppimage);
  3092. }
  3093. // Check for unresolved externals
  3094. ProcessUndefinedExternals(pimage);
  3095. // Check to see if we need to search libraries
  3096. if (errInc == errUndefinedSyms) {
  3097. errInc = errNone;
  3098. // Do the library search
  3099. ResolveExternalsInLibs(pimage);
  3100. if (errInc != errNone && errInc != errUndefinedSyms) {
  3101. return CleanUp(ppimage);
  3102. }
  3103. }
  3104. // Resolve weak/lazy externs
  3105. ResolveWeakExterns(pimage, (EXTERN_WEAK|EXTERN_LAZY|EXTERN_ALIAS));
  3106. if (errInc != errNone) {
  3107. return CleanUp(ppimage);
  3108. }
  3109. // Check to see if we have any undefined externals
  3110. PrintUndefinedExternals(pimage->pst);
  3111. // Fail link if we have undefined symbols as in full link
  3112. if (UndefinedSymbols && !(pimage->Switch.Link.Force & ftUnresolved)) {
  3113. Fatal(OutFilename, UNDEFINEDEXTERNALS, UndefinedSymbols);
  3114. }
  3115. // Encountered error or we were still left with undefined symbols (REVIEW?)
  3116. assert(errInc != errUndefinedSyms);
  3117. if (errInc != errNone) {
  3118. return CleanUp(ppimage);
  3119. }
  3120. // Alloc common PCONs
  3121. IncrAllocateCommon(pimage);
  3122. // Check to see if all the mods included need to be included
  3123. if (!fPowerMac && CheckForUnrefLibMods(pimage)) {
  3124. errInc = errLibRefSetChanged;
  3125. return CleanUp(ppimage);
  3126. }
  3127. // Check for any multiple definitions that may cause us to full-link
  3128. CheckForMultDefns(pimage, plpextMultDef);
  3129. if (errInc != errNone) {
  3130. return CleanUp(ppimage);
  3131. }
  3132. // no output file generated if there are multiply defined symbols unless
  3133. // /FORCE:multiple was specified. In the latter case we need to do a
  3134. // non-incremental build. Otherwise on ilinks it will give us grief.
  3135. // if (fMultipleDefinitions && !(pimage->Switch.Link.Force & ftMultiple)) {
  3136. // Fatal(OutFilename, MULTIPLYDEFINEDSYMS);
  3137. // } else if (fMultipleDefinitions && (pimage->Switch.Link.Force & ftMultiple)) {
  3138. // Warning(OutFilename, CANNOTILINKINFUTURE);
  3139. // }
  3140. if (fPowerMac) {
  3141. MppcCheckIncrTables();
  3142. if (errInc != errNone) {
  3143. return CleanUp(ppimage);
  3144. }
  3145. }
  3146. // Calculate new addresses
  3147. InternalError.Phase = "CalcPtrs";
  3148. InternalError.CombinedFilenames[0] = '\0';
  3149. IncrCalcPtrs(pimage);
  3150. if (errInc != errNone) {
  3151. return CleanUp(ppimage);
  3152. }
  3153. if (pextGp) {
  3154. psecGp = PsecFind(
  3155. NULL,
  3156. ReservedSection.GpData.Name,
  3157. ReservedSection.GpData.Characteristics,
  3158. &pimage->secs,
  3159. &pimage->ImgOptHdr);
  3160. CalculateGpRange();
  3161. // Align the GP pointer on a quad-word. This is assumed for Alpha.
  3162. pextGp->FinalValue = pextGp->ImageSymbol.Value = ((rvaGp + rvaGpMax) / 2) & ~7;
  3163. }
  3164. if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_ALPHA) {
  3165. DWORD rvaCur = pimage->ImgOptHdr.BaseOfCode;
  3166. if (CalculateTextSectionSize(pimage, rvaCur) >= 0x400000) {
  3167. fAlphaCheckLongBsr = TRUE;
  3168. }
  3169. }
  3170. if (fPowerMac) {
  3171. CollectAndSort(pimage);
  3172. }
  3173. // Check if data movement is a problem
  3174. CheckIfMovedDataRefByModFiles(pimage->pst, &cReloc);
  3175. if (errInc != errNone) {
  3176. return CleanUp(ppimage);
  3177. }
  3178. if (!fPowerMac && !fNoBaseRelocs) {
  3179. // alloc space for collecting the base relocs
  3180. // For PowerMac, this is done in MppcCheckIncrTables()
  3181. if (pimage->pdatai.ipdataMac) {
  3182. unsigned long oldCrelFree = pimage->bri.crelFree;
  3183. DeleteBaseRelocs(&pimage->bri, psecException->rva,
  3184. pimage->pdatai.ipdataMac * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY));
  3185. cReloc += pimage->bri.crelFree - oldCrelFree;
  3186. }
  3187. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size
  3188. += cReloc;
  3189. pbrCur = rgbr =
  3190. (BASE_RELOC *) PvAlloc(pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size
  3191. * sizeof(BASE_RELOC));
  3192. pbrEnd = rgbr +
  3193. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
  3194. }
  3195. if (pimage->fpoi.ifpoMax) {
  3196. // Init fpo handler
  3197. FPOInit(pimage->fpoi.ifpoMax);
  3198. }
  3199. if (pimage->pdatai.ipdataMax) {
  3200. // Init pdata handler
  3201. PDATAInit(pimage->pdatai.ipdataMax);
  3202. }
  3203. if (fPowerMac) {
  3204. FixupEntryInitTerm(pextEntry, pimage);
  3205. MppcIncrFixExportDescriptors(pimage);
  3206. }
  3207. // Pass2 of changed mods
  3208. InternalError.Phase = "IncrPass2";
  3209. #ifdef INSTRUMENT
  3210. // log begin of pass2
  3211. LogNoteEvent(Log, SZILINK, SZPASS2, letypeBegin, NULL);
  3212. #endif // INSTRUMENT
  3213. // Allocate space for CvInfo Structs: needed for linenum info
  3214. CvInfo = (PCVINFO) PvAllocZ(Cmod(pimage->libs.plibHead) * sizeof(CVINFO));
  3215. Pass2(pimage);
  3216. if (errInc != errNone) {
  3217. return CleanUp(ppimage);
  3218. }
  3219. ReleaseMovedDataRefList(pimage);
  3220. #ifdef INSTRUMENT
  3221. LogNoteEvent(Log, SZILINK, SZPASS2, letypeEnd, NULL);
  3222. #endif // INSTRUMENT
  3223. // update fpo info
  3224. if (pimage->fpoi.ifpoMax) {
  3225. WriteFpoRecords(&pimage->fpoi, pgrpFpoData->foRawData);
  3226. if (errInc != errNone) {
  3227. return CleanUp(ppimage);
  3228. }
  3229. }
  3230. // handle debug info
  3231. UpdateDebugDir(pimage);
  3232. if (pimage->pdatai.ipdataMax) {
  3233. if (fPowerMac) {
  3234. assert(pgrpPdata);
  3235. WritePdataRecords(&pimage->pdatai, pgrpPdata->foRawData);
  3236. MppcFixCxxEHTableOnILink (pimage);
  3237. } else {
  3238. WritePdataRecords(&pimage->pdatai, psecException->foRawData);
  3239. }
  3240. if (errInc != errNone) {
  3241. return CleanUp(ppimage);
  3242. }
  3243. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size =
  3244. pimage->pdatai.ipdataMac * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
  3245. assert(pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress ==
  3246. (fPowerMac ? pgrpPdata->rva : psecException->rva));
  3247. }
  3248. // map file changes (or regenerate a new one) (LATER)
  3249. // based relocs
  3250. InternalError.Phase = "EmitRelocations";
  3251. InternalError.CombinedFilenames[0] = '\0';
  3252. if (fPowerMac) {
  3253. MppcUpdateRelocTable(pimage);
  3254. // Free the deleted Base Reloc List for PowerMac
  3255. FreeArgumentList(&ZappedBaseRelocList);
  3256. } else if (!fNoBaseRelocs) {
  3257. EmitRelocations(pimage);
  3258. }
  3259. if (fAlphaCheckLongBsr) {
  3260. assert(pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_ALPHA);
  3261. EmitAlphaThunks();
  3262. }
  3263. if (errInc != errNone) {
  3264. return CleanUp(ppimage);
  3265. }
  3266. // Update image headers as needed
  3267. InternalError.Phase = "UpdateImgHdrsAndComment";
  3268. UpdateImgHdrsAndComment(pimage, FALSE);
  3269. return CleanUp(ppimage);
  3270. }
  3271. INT
  3272. CleanUp (
  3273. PPIMAGE ppimage
  3274. )
  3275. /*++
  3276. Routine Description:
  3277. cleanup routine. errInc is global.
  3278. Arguments:
  3279. pimage - ptr to EXE image
  3280. Return Value:
  3281. 0 on success, -1 on failure
  3282. --*/
  3283. {
  3284. BOOL fNotified = FALSE;
  3285. InternalError.Phase = "FinalPhase";
  3286. switch (errInc) {
  3287. case errOutOfDiskSpace:
  3288. fNotified = TRUE;
  3289. case errOutOfMemory:
  3290. if (!fNotified) {
  3291. if (fTest) {
  3292. PostNote(NULL, INTLIMITEXCEEDED);
  3293. }
  3294. fNotified = TRUE;
  3295. }
  3296. case errFpo:
  3297. case errPdata:
  3298. if (!fNotified) {
  3299. if (fTest) {
  3300. PostNote(NULL, PADEXHAUSTED);
  3301. }
  3302. fNotified = TRUE;
  3303. }
  3304. case errTypes:
  3305. if (!fNotified) {
  3306. if (fTest) {
  3307. PostNote(NULL, PRECOMPREQ);
  3308. }
  3309. fNotified = TRUE;
  3310. }
  3311. case errDbiFormat:
  3312. if (!fNotified) {
  3313. if (fTest) {
  3314. PostNote(NULL, DBIFORMAT);
  3315. }
  3316. fNotified = TRUE;
  3317. }
  3318. case errDataMoved:
  3319. if (!fNotified) {
  3320. if (fTest) {
  3321. PostNote(NULL, SYMREFSETCHNG);
  3322. }
  3323. fNotified = TRUE;
  3324. }
  3325. case errCalcPtrs:
  3326. if (!fNotified) {
  3327. if (fTest) {
  3328. PostNote(NULL, PADEXHAUSTED);
  3329. }
  3330. fNotified = TRUE;
  3331. }
  3332. // close up the image file
  3333. if (FileWriteHandle) {
  3334. FileClose(FileWriteHandle, TRUE);
  3335. FileWriteHandle = 0;
  3336. }
  3337. case errUndefinedSyms:
  3338. if (!fNotified) {
  3339. if (fTest) {
  3340. PostNote(NULL, SYMREFSETCHNG);
  3341. }
  3342. fNotified = TRUE;
  3343. }
  3344. case errWeakExtern:
  3345. if (!fNotified) {
  3346. if (fTest) {
  3347. PostNote(NULL, SYMREFSETCHNG);
  3348. }
  3349. fNotified = TRUE;
  3350. }
  3351. case errCommonSym:
  3352. if (!fNotified) {
  3353. if (fTest) {
  3354. PostNote(NULL, BSSCHNG);
  3355. }
  3356. fNotified = TRUE;
  3357. }
  3358. case errAbsolute:
  3359. if (!fNotified) {
  3360. if (fTest) {
  3361. PostNote(NULL, ABSSYMCHNG);
  3362. }
  3363. fNotified = TRUE;
  3364. }
  3365. case errMultDefFound:
  3366. if (!fNotified) {
  3367. fNotified = TRUE;
  3368. }
  3369. case errLibRefSetChanged:
  3370. if (!fNotified) {
  3371. if (fTest) {
  3372. PostNote(NULL, LIBREFSETCHNG);
  3373. }
  3374. fNotified = TRUE;
  3375. }
  3376. case errComdat:
  3377. if (!fNotified) {
  3378. if (fTest) {
  3379. PostNote(NULL, DIFFCOMDATS);
  3380. }
  3381. fNotified = TRUE;
  3382. }
  3383. case errJmpTblOverflow:
  3384. case errTocTblOverflow:
  3385. case errDescOverflow:
  3386. if (!fNotified) {
  3387. if (fTest) {
  3388. PostNote(NULL, PADEXHAUSTED, NULL, NULL);
  3389. }
  3390. fNotified = TRUE;
  3391. }
  3392. case errDirectives:
  3393. if (!fNotified) {
  3394. if (fTest) {
  3395. PostNote(NULL, DIFFDIRECTIVES, NULL, NULL);
  3396. }
  3397. fNotified = TRUE;
  3398. }
  3399. case errBaseReloc:
  3400. if (!fNotified) {
  3401. if (fTest) {
  3402. PostNote(NULL, PADEXHAUSTED);
  3403. }
  3404. fNotified = TRUE;
  3405. }
  3406. case errTooManyChanges:
  3407. case errFileAdded:
  3408. case errFileDeleted:
  3409. case errLibChanged:
  3410. case errExports:
  3411. #ifdef ILINKLOG
  3412. IlinkLog((UINT)-1);
  3413. #endif // ILINKLOG
  3414. // restore state
  3415. fIncrDbFile = FALSE;
  3416. // close up the inc file & delete it
  3417. FreeImage(ppimage, TRUE);
  3418. remove(szIncrDbFilename);
  3419. // remove any temporary files
  3420. FileCloseAll();
  3421. RemoveConvertTempFiles();
  3422. if (ModFileList.Count) {
  3423. FreeArgumentList(&ModFileList);
  3424. }
  3425. // return
  3426. #ifdef INSTRUMENT
  3427. LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "failed");
  3428. #endif // INSTRUMENT
  3429. return -1;
  3430. case errNone:
  3431. #ifdef INSTRUMENT
  3432. LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "success");
  3433. #endif // INSTRUMENT
  3434. case errNoChanges:
  3435. FileClose(FileWriteHandle, TRUE);
  3436. FileWriteHandle = 0;
  3437. SaveImage(*ppimage);
  3438. return 0;
  3439. default:
  3440. assert(0); // uhhuh!
  3441. } // end switch
  3442. assert(0); // nahnah!
  3443. return(-1);
  3444. }
  3445. #if DBG
  3446. void
  3447. DumpJmpTbl (
  3448. PCON pcon,
  3449. PVOID pvRaw
  3450. )
  3451. /*++
  3452. Routine Description:
  3453. Dumps the jump table contents.
  3454. Arguments:
  3455. pvRaw - pointer to raw data
  3456. Return Value:
  3457. None.
  3458. --*/
  3459. {
  3460. BYTE *p;
  3461. DumpPCON(pcon);
  3462. p = (BYTE *) pvRaw;
  3463. DBPRINT("---------BEGIN OF JMP TBL--------------\n");
  3464. for (;pcon->cbRawData > (DWORD) (p - (BYTE *) pvRaw);) {
  3465. if (fPowerMac) {
  3466. DWORD offset = DwSwap(*(DWORD *) p);
  3467. // Opcode is in the first 6 bits for PowerMac
  3468. DBPRINT("OP= 0x%.02x, ADDR=0x%.8lx\n",
  3469. (offset >> 24) & 0xFC,
  3470. (offset << 6) >> 6);
  3471. } else {
  3472. DBPRINT("OP= 0x%.02x, ADDR=0x%.8lx\n",
  3473. *p,
  3474. *(LONG UNALIGNED *) (p+ilink_info->address_offset));
  3475. }
  3476. p += CbJumpEntry();
  3477. }
  3478. DBPRINT("----------END OF JMP TBL---------------\n");
  3479. }
  3480. void
  3481. DumpReferences (
  3482. PIMAGE pimage
  3483. )
  3484. /*++
  3485. Routine Description:
  3486. Dumps all references.
  3487. Arguments:
  3488. pimage - ptr to EXE image
  3489. Return Value:
  3490. None.
  3491. --*/
  3492. {
  3493. PEXTERNAL pext;
  3494. INT i = 0;
  3495. DBPRINT("---------BEGIN OF SYMBOL REFERENCES--------------\n");
  3496. // walk the external symbol table
  3497. InitEnumerateExternals(pimage->pst);
  3498. while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
  3499. ENM_MOD_EXT enmModExt;
  3500. if ((pext->Flags & EXTERN_DEFINED) == 0) {
  3501. // Ignore whatever needs to be ignored
  3502. continue;
  3503. }
  3504. DBPRINT("sym= %s\n referenced by= ", SzNamePext(pext, pimage->pst));
  3505. // display references from modified files
  3506. InitEnmModExt(&enmModExt, pext);
  3507. while (FNextEnmModExt(&enmModExt)) {
  3508. PMOD pmod = enmModExt.pmod;
  3509. if (pmod == NULL) {
  3510. continue; // for ilink we remove references
  3511. }
  3512. DBPRINT("%s ", FIsLibPMOD(pmod) ?
  3513. pmod->plibBack->szName : SzOrigFilePMOD(pmod));
  3514. if (++i > 2) {
  3515. DBPRINT("\n");
  3516. i = 0;
  3517. }
  3518. }
  3519. if (i) {
  3520. DBPRINT("\n");
  3521. }
  3522. }
  3523. TerminateEnumerateExternals(pimage->pst);
  3524. DBPRINT("---------END OF SYMBOL REFERENCES--------------\n");
  3525. }
  3526. #endif // DBG
  3527. // REVIEW: assumes only one export object per DLL.
  3528. void
  3529. SaveExpFileInfo (
  3530. PEXPINFO pei,
  3531. const char *szFile,
  3532. DWORD ts,
  3533. BOOL fExpObj
  3534. )
  3535. /*++
  3536. Routine Description:
  3537. Saves export object info (DEF file or export object).
  3538. Arguments:
  3539. pei - ptr to export info
  3540. szFile - name of file
  3541. ts - timestamp
  3542. fExpObj - TRUE if file is an export object
  3543. Return Value:
  3544. None.
  3545. --*/
  3546. {
  3547. assert(szFile);
  3548. // an .exp file wasn't used
  3549. if (!fExpObj) {
  3550. struct _stat statfile;
  3551. szFile = Strdup(szFile);
  3552. assert(!ts);
  3553. if (_stat(szFile, &statfile) == -1) {
  3554. Fatal(NULL, CANTOPENFILE, szFile);
  3555. }
  3556. ts = statfile.st_mtime;
  3557. }
  3558. assert(ts);
  3559. // fill in fields
  3560. pei->szExpFile = szFile;
  3561. pei->tsExp = ts;
  3562. }
  3563. void
  3564. SaveExportInfo (
  3565. PIMAGE /* pimage */,
  3566. const char *szDef,
  3567. PEXPINFO pei
  3568. )
  3569. /*++
  3570. Routine Description:
  3571. Saves any exports for the dll/exe into the incr db (private heap)
  3572. Arguments:
  3573. psecs - pointer to sections list in image map
  3574. szDef - name of DEF file
  3575. pei - ptr to export info
  3576. Return Value:
  3577. None.
  3578. --*/
  3579. {
  3580. if (pgrpExport->pconNext != NULL) {
  3581. PMOD pmod;
  3582. // An export object was used
  3583. pmod = PmodPCON(pgrpExport->pconNext);
  3584. SaveExpFileInfo(pei, SzOrigFilePMOD(pmod), pmod->TimeStamp, 1);
  3585. return;
  3586. }
  3587. // DEF file was used
  3588. if (szDef && szDef[0] != '\0') {
  3589. SaveExpFileInfo(pei, szDef, 0, 0);
  3590. }
  3591. // save exports specified via cmd line only; directives checked separately
  3592. if (ExportSwitches.Count) {
  3593. PARGUMENT_LIST parg;
  3594. WORD i;
  3595. for (i = 0, parg = ExportSwitches.First;
  3596. i < ExportSwitches.Count;
  3597. i++, parg = parg->Next) {
  3598. if (parg->ModifiedName) {
  3599. // This export was specified in a directive
  3600. continue;
  3601. }
  3602. AddArgToListOnHeap(&pei->nlExports, parg);
  3603. }
  3604. }
  3605. }
  3606. BOOL
  3607. FExpFound (
  3608. PARGUMENT_LIST parg
  3609. )
  3610. /*++
  3611. Routine Description:
  3612. Looks for the export in the current export list.
  3613. Arguments:
  3614. parg - ptr to an export entry.
  3615. Return Value:
  3616. TRUE if found else FALSE
  3617. --*/
  3618. {
  3619. if (FArgOnList(&ExportSwitches, parg)) {
  3620. return(TRUE);
  3621. }
  3622. // Not found
  3623. #ifdef INSTRUMENT
  3624. LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "exports changed: %s not found", parg->OriginalName);
  3625. #endif // INSTRUMENT
  3626. return(FALSE);
  3627. }
  3628. BOOL
  3629. FIsModFile (
  3630. PARGUMENT_LIST parg
  3631. )
  3632. /*++
  3633. Routine Description:
  3634. Checks to see if this directive is from a modified file.
  3635. REVIEW: currently works for objs only & not libs.
  3636. Arguments:
  3637. parg - ptr to an export entry.
  3638. Return Value:
  3639. TRUE if export belongs to a modified file.
  3640. --*/
  3641. {
  3642. PMOD pmod;
  3643. char szBuf[_MAX_PATH * 2];
  3644. assert(parg);
  3645. assert(parg->ModifiedName);
  3646. pmod = plibModObjs->pmodNext;
  3647. // walk the list of modified objs
  3648. while (pmod) {
  3649. // generate the combined name
  3650. SzComNamePMOD(pmod, szBuf);
  3651. // compare names
  3652. if (!_tcsicmp(szBuf, parg->ModifiedName)) {
  3653. return 1;
  3654. }
  3655. pmod = pmod->pmodNext;
  3656. }
  3657. // didn't find mod
  3658. return 0;
  3659. }
  3660. BOOL
  3661. FExportsChanged (
  3662. PEXPINFO pei,
  3663. BOOL fCmd
  3664. )
  3665. /*++
  3666. Routine Description:
  3667. Checks to see if any exports have changed since last link.
  3668. REVIEW: assumes changes in DEF/export file detected already.
  3669. Arguments:
  3670. pei - ptr to export info
  3671. fCmd - TRUE if test is for cmdline exports only.
  3672. Return Value:
  3673. TRUE if there were changes else FALSE
  3674. --*/
  3675. {
  3676. NAME_LIST nl;
  3677. PARGUMENT_LIST parg;
  3678. WORD i, cexp;
  3679. // no exp file was gen.(=> cmdline & directives ignored)
  3680. if (!pei->pmodGen && pei->szExpFile) {
  3681. WarningIgnoredExports(pei->szExpFile);
  3682. return(FALSE);
  3683. }
  3684. nl = pei->nlExports;
  3685. // compare the two lists
  3686. cexp = 0;
  3687. for (i = 0, parg = nl.First;
  3688. i < nl.Count;
  3689. i++, parg = parg->Next) {
  3690. // ignore directives when checking cmdline exports
  3691. if (fCmd && parg->ModifiedName) {
  3692. continue;
  3693. }
  3694. // if we are not checking cmdline exports, ignore them
  3695. if (!fCmd && !parg->ModifiedName) {
  3696. ++cexp; // need to count
  3697. continue;
  3698. }
  3699. // check directives of modified files only
  3700. if (parg->ModifiedName && !FIsModFile(parg)) {
  3701. continue;
  3702. }
  3703. cexp++;
  3704. if (!FExpFound(parg)) {
  3705. return(TRUE);
  3706. }
  3707. }
  3708. // counts must be the same
  3709. if (cexp != ExportSwitches.Count) {
  3710. #ifdef INSTRUMENT
  3711. LogNoteEvent(Log, SZILINK, NULL, letypeEvent,
  3712. "export count was 0x%.4x, is 0x%.4x", cexp, ExportSwitches.Count);
  3713. #endif // INSTRUMENT
  3714. return(TRUE);
  3715. }
  3716. return(FALSE);
  3717. }
  3718. BOOL
  3719. FGenFileModified (
  3720. const char *szOrig,
  3721. const char *szNew,
  3722. DWORD ts
  3723. )
  3724. /*++
  3725. Routine Description:
  3726. Checks to see if linker generated files are same (name & ts).
  3727. Arguments:
  3728. szOrig - original name of file
  3729. szNew - newly specified name
  3730. ts - timestamp of original file
  3731. Return Value:
  3732. 1 if changed else 0
  3733. --*/
  3734. {
  3735. struct _stat statfile;
  3736. if (_tcsicmp(szOrig, szNew)) {
  3737. #ifdef INSTRUMENT
  3738. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "file %s replaced by %s", szOrig, szNew);
  3739. #endif // INSTRUMENT
  3740. return 1;
  3741. }
  3742. if (_stat(szOrig, &statfile) == -1) {
  3743. #ifdef INSTRUMENT
  3744. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "file not accessible: %s", szNew);
  3745. #endif // INSTRUMENT
  3746. return 1;
  3747. }
  3748. if (ts != (DWORD)statfile.st_mtime) {
  3749. #ifdef INSTRUMENT
  3750. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "file modified: %s", szOrig);
  3751. #endif // INSTRUMENT
  3752. return 1;
  3753. }
  3754. return 0; // no changes
  3755. }
  3756. BOOL
  3757. FExpFileChanged (
  3758. PEXPINFO pei
  3759. )
  3760. /*++
  3761. Routine Description:
  3762. Checks to see if export-object/DEF-file was updated between links.
  3763. Caveat: assumes that if export object was used, DEF file is
  3764. ignored.
  3765. Arguments:
  3766. pei - ptr to export info
  3767. Return Value:
  3768. 1 if changed else 0
  3769. --*/
  3770. {
  3771. // an export object was used; if a new exports obj is added it will get detected
  3772. // as a new file being added
  3773. if (!pei->pmodGen && pei->szExpFile) {
  3774. PARGUMENT_LIST parg;
  3775. parg = PargFindSz(pei->szExpFile, &FilenameArguments);
  3776. if (!parg) {
  3777. #ifdef INSTRUMENT
  3778. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "exp obj %s was used, now not", pei->szExpFile);
  3779. #endif // INSTRUMENT
  3780. return(TRUE);
  3781. }
  3782. assert(parg);
  3783. if (parg->TimeStamp != pei->tsExp) {
  3784. #ifdef INSTRUMENT
  3785. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "exp obj modified: %s", parg->OriginalName);
  3786. #endif // INSTRUMENT
  3787. return(TRUE);
  3788. }
  3789. return(FALSE);
  3790. }
  3791. // an exports object was generated. check for any changes to it and the correspodning import lib if any
  3792. if (pei->pmodGen) {
  3793. char szDrive[_MAX_DRIVE];
  3794. char szDir[_MAX_DIR];
  3795. char szFname[_MAX_FNAME];
  3796. char szExt[_MAX_EXT];
  3797. char szImplibFilename[_MAX_FNAME];
  3798. const char *szImplibT;
  3799. PMOD pmod;
  3800. pmod = pei->pmodGen;
  3801. if (FGenFileModified(SzOrigFilePMOD(pmod), SzOrigFilePMOD(pmod), pmod->TimeStamp)) {
  3802. return(TRUE);
  3803. }
  3804. assert(pei->szImpLib);
  3805. assert(pei->tsImpLib);
  3806. if ((szImplibT = ImplibFilename) == NULL) {
  3807. _splitpath(OutFilename, szDrive, szDir, szFname, szExt);
  3808. _makepath(szImplibFilename, szDrive, szDir, szFname, ".lib");
  3809. szImplibT = szImplibFilename;
  3810. }
  3811. if (FGenFileModified(pei->szImpLib, szImplibT, pei->tsImpLib)) {
  3812. return(TRUE);
  3813. }
  3814. }
  3815. // a DEF file was used previously;
  3816. if (pei->pmodGen && pei->szExpFile) {
  3817. struct _stat statfile;
  3818. if (DefFilename == NULL || DefFilename[0] == '\0') {
  3819. #ifdef INSTRUMENT
  3820. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, ".def file %s no longer used", DefFilename, 0);
  3821. #endif // INSTRUMENT
  3822. return(TRUE); // DEF file no longer used
  3823. }
  3824. if (_tcsicmp(pei->szExpFile, DefFilename)) {
  3825. #ifdef INSTRUMENT
  3826. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, "file %s replaced by %s", pei->szExpFile, DefFilename);
  3827. #endif // INSTRUMENT
  3828. return(TRUE); // DEF file replaced
  3829. }
  3830. if (_stat(pei->szExpFile, &statfile) == -1) {
  3831. Fatal(NULL, CANTOPENFILE, DefFilename); // DEf file not found
  3832. }
  3833. if (pei->tsExp != (DWORD)statfile.st_mtime) {
  3834. #ifdef INSTRUMENT
  3835. LogNoteEvent(Log, SZILINK, SZINIT, letypeEvent, ".def file modified %s", pei->szExpFile, 0);
  3836. #endif // INSTRUMENT
  3837. return(TRUE);
  3838. }
  3839. return(FALSE); // no changes
  3840. }
  3841. // check if a DEF file was specified for the first time
  3842. if (DefFilename != NULL && DefFilename[0] != '\0') {
  3843. return(TRUE);
  3844. }
  3845. // neither was used (note: changes in export specs via
  3846. // cmdline get detected while pocessing cmdline options).
  3847. return(FALSE);
  3848. }
  3849. void
  3850. WriteFpoRecords (
  3851. FPOI *pfpoi,
  3852. DWORD foFpo
  3853. )
  3854. /*++
  3855. Routine Description:
  3856. Updates/writes out the fpo information.
  3857. Arguments:
  3858. pfpoi - ptr to fpo info.
  3859. foFpo - file ptr to fpo.
  3860. Return Value:
  3861. None.
  3862. --*/
  3863. {
  3864. BOOL fMapped;
  3865. DWORD cbFpo = pfpoi->ifpoMax * sizeof(FPO_DATA);
  3866. PVOID pvRawData = PbMappedRegion(FileWriteHandle,
  3867. foFpo,
  3868. cbFpo);
  3869. fMapped = pvRawData != NULL ? TRUE : FALSE;
  3870. // if not mapped, alloc space for fpo records
  3871. if (!fMapped) {
  3872. pvRawData = PvAlloc(cbFpo);
  3873. // on an ilink read in fpo records
  3874. if (fIncrDbFile) {
  3875. FileSeek(FileWriteHandle, foFpo, SEEK_SET);
  3876. FileRead(FileWriteHandle, pvRawData, cbFpo);
  3877. }
  3878. }
  3879. pfpoi->rgfpo = (PFPO_DATA) pvRawData;
  3880. if (!FPOUpdate(pfpoi)) {
  3881. // on a full build, no failures expected
  3882. if (!fIncrDbFile) {
  3883. Fatal(NULL, INTERNAL_ERR);
  3884. }
  3885. errInc = errFpo;
  3886. #ifdef INSTRUMENT
  3887. LogNoteEvent(Log, SZILINK, "fpo", letypeEvent, "fpo pad overflow");
  3888. #endif // INSTRUMENT
  3889. if (!fMapped) {
  3890. FreePv(pvRawData);
  3891. }
  3892. return;
  3893. }
  3894. // zero out unused fpo entries (padding)
  3895. memset((BYTE *)pvRawData + (pfpoi->ifpoMac * sizeof(FPO_DATA)),
  3896. 0,
  3897. cbFpo - (pfpoi->ifpoMac * sizeof(FPO_DATA)));
  3898. // if not mapped, need to write out the updated fpo records
  3899. if (!fMapped) {
  3900. FileSeek(FileWriteHandle, foFpo, SEEK_SET);
  3901. FileWrite(FileWriteHandle, pvRawData, cbFpo);
  3902. FreePv(pvRawData);
  3903. }
  3904. }
  3905. void
  3906. WritePdataRecords (
  3907. PDATAI *ppdatai,
  3908. DWORD foPdata
  3909. )
  3910. /*++
  3911. Routine Description:
  3912. Updates/writes out the pdata information.
  3913. Arguments:
  3914. ppdatai - ptr to pdata info.
  3915. foPdata - file ptr to pdata.
  3916. Return Value:
  3917. None.
  3918. --*/
  3919. {
  3920. BOOL fMapped;
  3921. DWORD cbPdata = ppdatai->ipdataMax * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
  3922. PVOID pvRawData = PbMappedRegion(FileWriteHandle,
  3923. foPdata,
  3924. cbPdata);
  3925. fMapped = (pvRawData != NULL);
  3926. // if not mapped, alloc space for Pdata records
  3927. if (!fMapped) {
  3928. pvRawData = PvAlloc(cbPdata);
  3929. // on an ilink read in Pdata records
  3930. if (fIncrDbFile) {
  3931. FileSeek(FileWriteHandle, foPdata, SEEK_SET);
  3932. FileRead(FileWriteHandle, pvRawData, cbPdata);
  3933. }
  3934. }
  3935. ppdatai->rgpdata = (PIMAGE_RUNTIME_FUNCTION_ENTRY) pvRawData;
  3936. if (!PDATAUpdate(ppdatai)) {
  3937. // On a full build, no failures expected
  3938. if (!fIncrDbFile) {
  3939. Fatal(NULL, INTERNAL_ERR);
  3940. }
  3941. errInc = errPdata;
  3942. #ifdef INSTRUMENT
  3943. LogNoteEvent(Log, SZILINK, "pdata", letypeEvent, "pdata pad overflow");
  3944. #endif // INSTRUMENT
  3945. if (!fMapped) {
  3946. FreePv(pvRawData);
  3947. }
  3948. return;
  3949. }
  3950. // if not mapped, need to write out the updated fpo records
  3951. if (!fMapped) {
  3952. FileSeek(FileWriteHandle, foPdata, SEEK_SET);
  3953. FileWrite(FileWriteHandle, pvRawData, cbPdata);
  3954. FreePv(pvRawData);
  3955. }
  3956. }
  3957. void
  3958. SaveDirectiveSz (
  3959. const char *Sz,
  3960. PST pstDirective,
  3961. PMOD pmod
  3962. )
  3963. /*++
  3964. Routine Description:
  3965. Save the directive.
  3966. Arguments:
  3967. Sz - directive string.
  3968. pstDirective - symbol table holding all directives.
  3969. pmod - ptr to mod that had the directives
  3970. Return Value:
  3971. None.
  3972. --*/
  3973. {
  3974. PEXTERNAL pext = LookupExternSz(pstDirective, Sz, NULL);
  3975. PLEXT plextNew = (PLEXT) Malloc(sizeof(LEXT));
  3976. plextNew->pext = pext;
  3977. plextNew->plextNext = pmod->plextDirectives;
  3978. pmod->plextDirectives = plextNew;
  3979. pmod->cDirectives++;
  3980. }
  3981. BOOL
  3982. FVerifyDirectivesPMOD (
  3983. PIMAGE pimage,
  3984. PMOD pmod,
  3985. PNAME_LIST pnl
  3986. )
  3987. /*++
  3988. Routine Description:
  3989. Verifies that the directives for the given mod haven't changed.
  3990. Arguments:
  3991. pimage - ptr to image.
  3992. pmod - ptr to mod that had the directives
  3993. pnl - the new set of directives seen in this mod.
  3994. Return Value:
  3995. None.
  3996. --*/
  3997. {
  3998. WORD i;
  3999. PARGUMENT_LIST pal;
  4000. PMOD pmodO;
  4001. // For library modules, ensure no new directives encountered (no changes possible)
  4002. if (FIsLibPMOD(pmod)) {
  4003. for (i = 0, pal = pnl->First;
  4004. i < pnl->Count;
  4005. i++, pal = pal->Next) {
  4006. PEXTERNAL pext = SearchExternSz(pimage->pstDirective, pal->OriginalName);
  4007. if (!pext) {
  4008. errInc = errDirectives;
  4009. return(FALSE);
  4010. }
  4011. } // end for
  4012. return(TRUE);
  4013. }
  4014. pmodO = PmodFind(pimage->plibCmdLineObjs, SzOrigFilePMOD(pmod), 0);
  4015. assert(pmodO);
  4016. pmod->cDirectives = pmodO->cDirectives;
  4017. pmod->plextDirectives = pmodO->plextDirectives;
  4018. // check the count
  4019. if (pnl->Count != pmod->cDirectives) {
  4020. errInc = errDirectives;
  4021. return(FALSE);
  4022. }
  4023. // compare individual directives
  4024. for (i = 0, pal = pnl->First;
  4025. i < pnl->Count;
  4026. i++, pal = pal->Next) {
  4027. PEXTERNAL pext = SearchExternSz(pimage->pstDirective, pal->OriginalName);
  4028. if (!pext) {
  4029. errInc = errDirectives;
  4030. return(FALSE);
  4031. }
  4032. if (!PlextFind(pmod->plextDirectives, pext)) {
  4033. errInc = errDirectives;
  4034. return(FALSE);
  4035. }
  4036. }
  4037. return(TRUE);
  4038. }
  4039. void
  4040. MarkExtern_FuncFixup (
  4041. PIMAGE_SYMBOL psym,
  4042. PIMAGE pimage,
  4043. PCON pcon
  4044. )
  4045. /*++
  4046. Routine Description:
  4047. Mark the extern representing this symbol as having a non-lego kind of
  4048. fixup (eg. func_sym+offset).
  4049. Arguments:
  4050. psym - ptr to symbols
  4051. pimage - ptr to image
  4052. pcon - contribution of the fixup
  4053. Return Value:
  4054. None.
  4055. --*/
  4056. {
  4057. PEXTERNAL pext;
  4058. const char *szName;
  4059. // fetch the extern representing this sym. Note that the offsets to
  4060. // long names are into the image long name table & not the object's.
  4061. szName = SzNameSymPst((*psym), pimage->pst);
  4062. pext = SearchExternSz(pimage->pst, szName);
  4063. assert(pext);
  4064. assert(pext->pcon);
  4065. // If the fixup is in the same mod as the definition, nothing to do
  4066. if (PmodPCON(pext->pcon) == PmodPCON(pcon)) {
  4067. return;
  4068. }
  4069. // mark the extern
  4070. pext->Flags |= EXTERN_FUNC_FIXUP;
  4071. }
  4072. //
  4073. // support routines for ensuring that all modules currently included in image
  4074. // as a result of library search are still required/accessed
  4075. //
  4076. // Algorithm: A garbage collection algorithm "mark & sweep" is used here
  4077. // to figure out if any mods are unreferenced.
  4078. //
  4079. static PLMOD plmodRefModList;
  4080. void
  4081. WalkRefListPMOD (
  4082. PMOD pmod,
  4083. PIMAGE pimage
  4084. )
  4085. /*++
  4086. Routine Description:
  4087. walks the list of all references made by this MOD.
  4088. Arguments:
  4089. pmod - ptr to MOD
  4090. pimage - ptr to image
  4091. Return Value:
  4092. None.
  4093. --*/
  4094. {
  4095. ENM_EXT_LIST enmExtList;
  4096. pmod->fInclude = TRUE;
  4097. InitEnmExtList(&enmExtList, pmod->plpextRef);
  4098. while (FNextEnmExtList(&enmExtList)) {
  4099. PMOD pmodT;
  4100. if (!enmExtList.pext) {
  4101. continue; // sometimes linker removes references (for bss)
  4102. }
  4103. if (enmExtList.pext->Flags & EXTERN_IGNORE) {
  4104. continue; // ignorable syms eg. syms no longer in use
  4105. }
  4106. if (enmExtList.pext->ImageSymbol.SectionNumber == IMAGE_SYM_ABSOLUTE) {
  4107. pmodT = FindPmodDefiningSym(pimage->psdAbsolute, enmExtList.pext);
  4108. } else {
  4109. pmodT = PmodPCON(enmExtList.pext->pcon);
  4110. }
  4111. // if pmod is pmodLinkerDefined find actual mod defining it (for bss)
  4112. if (pmodT == pmodLinkerDefined) {
  4113. pmodT = FindPmodDefiningSym(pimage->psdCommon, enmExtList.pext);
  4114. if (!pmodT) {
  4115. continue; // common was defined in a cmdline obj; we don't care
  4116. }
  4117. }
  4118. // add the referenced MOD to list if it hasn't been processed
  4119. assert(pmodT);
  4120. if (!pmodT->fInclude) {
  4121. AddToPLMODList(&plmodRefModList, pmodT);
  4122. }
  4123. }
  4124. EndEnmExtList(&enmExtList);
  4125. }
  4126. void
  4127. MarkAllRefPMODs (
  4128. PIMAGE pimage
  4129. )
  4130. /*++
  4131. Routine Description:
  4132. marks all MODs in libs that are referenced
  4133. Arguments:
  4134. pimage - ptr to image
  4135. Return Value:
  4136. None.
  4137. --*/
  4138. {
  4139. ENM_MOD enm_mod;
  4140. PLMOD plmod;
  4141. // Add all command line objs to list of referenced objs
  4142. InitEnmMod(&enm_mod, pimage->plibCmdLineObjs);
  4143. while (FNextEnmMod(&enm_mod)) {
  4144. AddToPLMODList(&plmodRefModList, enm_mod.pmod);
  4145. }
  4146. EndEnmMod(&enm_mod);
  4147. // Add the mod contributing the entrypoint
  4148. if (pimage->pmodEntryPoint) {
  4149. AddToPLMODList(&plmodRefModList, pimage->pmodEntryPoint);
  4150. }
  4151. // walk the list of MODs that are referenced
  4152. while (plmodRefModList) {
  4153. // pop the mod from the list
  4154. plmod = plmodRefModList;
  4155. plmodRefModList = plmodRefModList->plmodNext;
  4156. // walk its references
  4157. WalkRefListPMOD(plmod->pmod, pimage);
  4158. FreePv(plmod);
  4159. }
  4160. }
  4161. // Currently this is to handle the case where objs from oldnames.lib
  4162. // always appear to be not referenced.
  4163. BOOL
  4164. FHasSideEffectsPMOD(
  4165. PMOD pmod
  4166. )
  4167. {
  4168. ENM_SRC enmSrc;
  4169. // For now even if 1 contrib is in the image, assume
  4170. // it could have side effects
  4171. InitEnmSrc(&enmSrc, pmod);
  4172. while (FNextEnmSrc(&enmSrc)) {
  4173. if (!(enmSrc.pcon->flags & IMAGE_SCN_LNK_REMOVE) &&
  4174. enmSrc.pcon->cbRawData)
  4175. return(TRUE);
  4176. }
  4177. return(FALSE);
  4178. }
  4179. BOOL
  4180. AnyUnrefLibMods(
  4181. PIMAGE pimage
  4182. )
  4183. /*++
  4184. Routine Description:
  4185. checks to see if there are any unreferenced lib mods
  4186. Arguments:
  4187. pimage - ptr to image
  4188. Return Value:
  4189. TRUE if there is even 1 mod not referenced anymore.
  4190. --*/
  4191. {
  4192. ENM_LIB enm_lib;
  4193. InitEnmLib(&enm_lib, pimage->libs.plibHead);
  4194. while (FNextEnmLib(&enm_lib)) {
  4195. ENM_MOD enm_mod;
  4196. if (enm_lib.plib->flags & LIB_DontSearch) {
  4197. continue;
  4198. }
  4199. InitEnmMod(&enm_mod, enm_lib.plib);
  4200. while (FNextEnmMod(&enm_mod)) {
  4201. if (!enm_mod.pmod->fInclude && FHasSideEffectsPMOD(enm_mod.pmod)) {
  4202. EndEnmMod(&enm_mod);
  4203. EndEnmLib(&enm_lib);
  4204. return(TRUE);
  4205. }
  4206. }
  4207. EndEnmMod(&enm_mod);
  4208. }
  4209. EndEnmLib(&enm_lib);
  4210. return(FALSE);
  4211. }
  4212. BOOL
  4213. CheckForUnrefLibMods (
  4214. PIMAGE pimage
  4215. )
  4216. /*++
  4217. Routine Description:
  4218. checks to see if there are any unreferenced lib mods
  4219. Arguments:
  4220. pimage - ptr to image
  4221. Return Value:
  4222. TRUE if there is a library MOD no longer referenced
  4223. --*/
  4224. {
  4225. InternalError.Phase = "CheckForUnrefLibMods";
  4226. InternalError.CombinedFilenames[0] = '\0';
  4227. MarkAllRefPMODs(pimage);
  4228. return AnyUnrefLibMods(pimage);
  4229. }
  4230. //
  4231. // support for sym defn handling
  4232. //
  4233. void
  4234. RecordSymDef (
  4235. SYM_DEF **ppsd,
  4236. PEXTERNAL pext,
  4237. PMOD pmod
  4238. )
  4239. {
  4240. PSYM_DEF psd = (*ppsd);
  4241. while (psd) {
  4242. if (psd->pext == pext) {
  4243. psd->pmod = pmod; // update pmod if already in list (for bss redfn)
  4244. return;
  4245. }
  4246. psd = psd->psdNext;
  4247. }
  4248. psd = (SYM_DEF *) Malloc(sizeof(SYM_DEF));
  4249. psd->pext = pext;
  4250. psd->pmod = pmod;
  4251. psd->psdNext = (*ppsd);
  4252. (*ppsd) = psd;
  4253. }
  4254. PMOD
  4255. FindPmodDefiningSym (
  4256. SYM_DEF *psd,
  4257. PEXTERNAL pext
  4258. )
  4259. {
  4260. while (psd) {
  4261. if (psd->pext == pext) {
  4262. return psd->pmod;
  4263. }
  4264. psd = psd->psdNext;
  4265. }
  4266. return NULL;
  4267. }
  4268. // functions for ensuring that multiple definitions in libs aren't a problem
  4269. //
  4270. // Algorithm: The linker builds up a list of externs. If any on this list have
  4271. // multiple definitions than the behavior of the linker could be different on
  4272. // a full build. The list comprises only the symbols that are referenced by cmdline
  4273. // objs, already defined in a lib that weren't referenced by cmdline objs till now.
  4274. // These externs potentially can cause differences in behavior if they have definitions
  4275. // in a library before the library they were found in.
  4276. BOOL
  4277. IsSameDefn (
  4278. PEXTERNAL pext,
  4279. DWORD foMember,
  4280. PLIB plib
  4281. )
  4282. {
  4283. assert(FIsLibPCON(pext->pcon));
  4284. // convert foMember to value past arhive member (see ReadArchiveMemberHeader())
  4285. foMember = EvenByteAlign(foMember) + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
  4286. // two defns are same if they came from same lib & mod
  4287. return(PmodPCON(pext->pcon)->plibBack == plib &&
  4288. PmodPCON(pext->pcon)->foMember == foMember);
  4289. }
  4290. void
  4291. MultDefFound (
  4292. PIMAGE pimage,
  4293. PLIB plib,
  4294. PLPEXT plpext
  4295. )
  4296. {
  4297. ENM_EXT_LIST enmExtList;
  4298. if (plib->szName != NULL) { // hack-o-rama: temp temp
  4299. char szFname[_MAX_FNAME];
  4300. char szExt[_MAX_EXT];
  4301. char szPath[_MAX_PATH];
  4302. _splitpath(plib->szName, NULL, NULL, szFname, szExt);
  4303. strcpy(szPath, szFname);
  4304. strcat(szPath, szExt);
  4305. if (!_ftcsicmp(szPath, "oldnames.lib")) {
  4306. return;
  4307. }
  4308. }
  4309. // prep lib for searching
  4310. PrepLibForSearching(pimage, plib);
  4311. // walk the list of symbols that could potentially have multiple defns.
  4312. InitEnmExtList(&enmExtList, plpext);
  4313. while (FNextEnmExtList(&enmExtList)) {
  4314. const char *szSym;
  4315. char **pszEntry;
  4316. DWORD isz;
  4317. BOOL fFound;
  4318. WORD iszIntMem;
  4319. DWORD iusOffIndex;
  4320. DWORD foMember;
  4321. if (!enmExtList.pext) {
  4322. continue;
  4323. }
  4324. szSym = SzNamePext(enmExtList.pext, pimage->pst);
  4325. // search for the sym
  4326. if (plib->flags & LIB_NewIntMem) {
  4327. pszEntry = (char **) bsearch(&szSym, plib->rgszSym,
  4328. (size_t) plib->csymIntMem, sizeof(char *), Compare);
  4329. fFound = (pszEntry != NULL);
  4330. } else {
  4331. fFound = FALSE;
  4332. for (isz = 0; isz < plib->csymIntMem; isz++) {
  4333. if (!strcmp(plib->rgszSym[isz], szSym)) {
  4334. fFound = TRUE;
  4335. break;
  4336. }
  4337. }
  4338. }
  4339. if (!fFound) {
  4340. continue;
  4341. }
  4342. // get the offset of mod that defines it
  4343. if (plib->flags & LIB_NewIntMem) {
  4344. iszIntMem = (WORD) (pszEntry - plib->rgszSym);
  4345. iusOffIndex = plib->rgusOffIndex[iszIntMem];
  4346. foMember = plib->rgulSymMemOff[iusOffIndex];
  4347. } else {
  4348. iszIntMem = (WORD) isz;
  4349. foMember = sgetl(&plib->rgulSymMemOff[iszIntMem]);
  4350. }
  4351. // does the current defn match with the defn just found?
  4352. if (!IsSameDefn(enmExtList.pext, foMember, plib)) {
  4353. errInc = errMultDefFound;
  4354. if (fTest) {
  4355. char *szOutput = SzOutputSymbolName(szSym, TRUE);
  4356. PostNote(NULL, MULTDEFNFOUND, szOutput);
  4357. if (szSym != szOutput) {
  4358. FreePv(szOutput);
  4359. }
  4360. }
  4361. return;
  4362. }
  4363. DelExtFromList(plpext, enmExtList.pext);
  4364. }
  4365. }
  4366. void
  4367. CheckForMultDefns (
  4368. PIMAGE pimage,
  4369. PLPEXT plpextMultDef
  4370. )
  4371. {
  4372. ENM_LIB enm_lib;
  4373. InternalError.Phase = "CheckForMultDefns";
  4374. InternalError.CombinedFilenames[0] = '\0';
  4375. // list empty
  4376. if (IsExtListEmpty(plpextMultDef)) {
  4377. return;
  4378. }
  4379. // search the libs for any multiple definitions
  4380. InitEnmLib(&enm_lib, pimage->libs.plibHead);
  4381. while (FNextEnmLib(&enm_lib)) {
  4382. if (enm_lib.plib->flags & LIB_DontSearch) {
  4383. continue;
  4384. }
  4385. MultDefFound(pimage, enm_lib.plib, plpextMultDef);
  4386. // check if we hit a multiple defn
  4387. if (errInc != errNone) {
  4388. return;
  4389. }
  4390. // no more externs to lookup
  4391. if (IsExtListEmpty(plpextMultDef)) {
  4392. return;
  4393. }
  4394. }
  4395. }
  4396. BOOL
  4397. NoRefsByCmdLineObjs (
  4398. PEXTERNAL pext
  4399. )
  4400. {
  4401. ENM_MOD_EXT enmModExt;
  4402. if (!pext->pmodOnly) {
  4403. // No references
  4404. return(TRUE);
  4405. }
  4406. // walk the list of referencing MODs kept at each sym
  4407. InitEnmModExt(&enmModExt, pext);
  4408. while (FNextEnmModExt(&enmModExt)) {
  4409. if (!enmModExt.pmod) {
  4410. continue; // for ilink we remove references
  4411. }
  4412. if (!FIsLibPMOD(enmModExt.pmod)) {
  4413. return(FALSE);
  4414. }
  4415. }
  4416. return(TRUE);
  4417. }
  4418. void
  4419. AddExtToMultDefList (
  4420. PEXTERNAL pext,
  4421. PIMAGE pimage
  4422. )
  4423. {
  4424. assert(pext->Flags & EXTERN_DEFINED);
  4425. // ignore absolutes (REVIEW: ignore?)
  4426. if (pext->ImageSymbol.SectionNumber == IMAGE_SYM_ABSOLUTE) {
  4427. return;
  4428. }
  4429. // ignore COMMON (don't give rise to multiple definition errors)
  4430. if (pext->Flags & EXTERN_COMMON) {
  4431. return;
  4432. }
  4433. if (fPowerMac && !pext->pcon) {
  4434. // This could be a descriptor which just got created
  4435. // We are already making sure that there are no duplicates
  4436. char *szSym = SzNamePext(pext, pimage->pst);
  4437. if (*szSym == '.') {
  4438. return;
  4439. }
  4440. }
  4441. assert(pext->pcon);
  4442. if (FIsLibPMOD(PmodPCON(pext->pcon)) &&
  4443. NoRefsByCmdLineObjs(pext)) {
  4444. AddExtToList(plpextMultDef, TRUE, pext);
  4445. }
  4446. }