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.

6155 lines
162 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: shared.cpp
  7. *
  8. * File Comments:
  9. *
  10. * Functions which are common to the COFF Linker/Librarian/Dumper.
  11. *
  12. ***********************************************************************/
  13. #include "link.h"
  14. BOOL FIncludeComdat(PIMAGE, PCON, PIMAGE_SYMBOL, SHORT, const char **);
  15. static BLK blkSymbolTable;
  16. static BOOL fSymbolTableInUse;
  17. static BOOL fMappedSyms;
  18. static BLK blkStringTable;
  19. static BOOL fStringTableInUse;
  20. static BOOL fMappedStrings;
  21. static BLK blkRelocs;
  22. static BOOL fRelocsInUse;
  23. static BOOL fMappedRelocs;
  24. static BOOL fWeakToRegular = FALSE;
  25. typedef struct _COMDAT_ISYMS {
  26. DWORD isymSec;
  27. DWORD isymComdat;
  28. } COMDAT_ISYMS;
  29. static COMDAT_ISYMS *rgComdatIsyms = NULL;
  30. // Token parser. Same usage as strtok() but it also handles quotation marks.
  31. // Munges the source buffer.
  32. //
  33. // Return value *pfQuoted indicates whether the string had quotes in it.
  34. char *
  35. SzGetArgument(
  36. char *szText,
  37. BOOL *pfQuoted
  38. )
  39. {
  40. static unsigned char *pchCur = NULL;
  41. unsigned char *szResult;
  42. if (pfQuoted != NULL) {
  43. *pfQuoted = FALSE;
  44. }
  45. if (szText != NULL) {
  46. pchCur = (unsigned char *)szText;
  47. }
  48. assert(pchCur != NULL);
  49. // skip blanks
  50. while (*pchCur != '\0' && _istspace(*pchCur)) {
  51. pchCur++;
  52. }
  53. if (*pchCur == '\0') {
  54. return(char *)(pchCur = NULL);
  55. }
  56. szResult = pchCur;
  57. while (*pchCur != '\0' && !_istspace(*pchCur)) {
  58. if (*pchCur == '"') {
  59. // Found a quote mark ... delete it, delete its match if any,
  60. // and add all characters in between to the current token.
  61. unsigned char *pchOtherQuote;
  62. memmove(pchCur, pchCur + 1, strlen((char *)pchCur + 1) + 1);
  63. if ((pchOtherQuote = (unsigned char *)_tcschr((char *)pchCur, '"')) != NULL) {
  64. memmove(pchOtherQuote, pchOtherQuote + 1,
  65. strlen((char *)pchOtherQuote + 1) + 1);
  66. pchCur = pchOtherQuote;
  67. if (pfQuoted != NULL) {
  68. *pfQuoted = TRUE;
  69. }
  70. }
  71. } else {
  72. pchCur++;
  73. }
  74. }
  75. // pchCur is now pointing to a NULL or delimiter.
  76. if (*pchCur != '\0') {
  77. *pchCur++ = '\0';
  78. }
  79. return szResult[0] == '\0' ? SzGetArgument(NULL, pfQuoted)
  80. : (char *)szResult;
  81. }
  82. PCHAR
  83. _find (
  84. PCHAR szPattern
  85. )
  86. /*++
  87. Routine Description:
  88. Given a wildcard pattern, expand it and return one at a time.
  89. Arguments:
  90. szPattern - Wild card argument.
  91. --*/
  92. {
  93. static HANDLE _WildFindHandle;
  94. static LPWIN32_FIND_DATA pwfd;
  95. if (szPattern) {
  96. if (pwfd == NULL) {
  97. pwfd = (LPWIN32_FIND_DATA) PvAlloc(MAX_PATH + sizeof(*pwfd));
  98. }
  99. if (_WildFindHandle != NULL) {
  100. FindClose(_WildFindHandle);
  101. _WildFindHandle = NULL;
  102. }
  103. _WildFindHandle = FindFirstFile(szPattern, pwfd);
  104. if (_WildFindHandle == INVALID_HANDLE_VALUE) {
  105. _WildFindHandle = NULL;
  106. return NULL;
  107. }
  108. } else {
  109. Retry:
  110. if (!FindNextFile(_WildFindHandle, pwfd)) {
  111. FindClose(_WildFindHandle);
  112. _WildFindHandle = NULL;
  113. return NULL;
  114. }
  115. }
  116. if (pwfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  117. // Skip directories
  118. goto Retry;
  119. }
  120. return(pwfd->cFileName);
  121. }
  122. void
  123. ProcessWildCards (
  124. const char *Argument
  125. )
  126. /*++
  127. Routine Description:
  128. Expands wild cards in the argument and treats each matching file as
  129. an argument.
  130. Arguments:
  131. Argument - Wild card argument.
  132. CommandFile - If TRUE, then argument was read from a command file, and
  133. argument needs to be copied before adding to list.
  134. Return Value:
  135. None.
  136. --*/
  137. {
  138. char szDrive[_MAX_DRIVE];
  139. char szDir[_MAX_DIR];
  140. const char *pFilename;
  141. char szFullpath[_MAX_PATH];
  142. _splitpath(Argument, szDrive, szDir, NULL, NULL);
  143. while ((pFilename = _find((char *) Argument)) != NULL) {
  144. _makepath(szFullpath, szDrive, szDir, pFilename, NULL);
  145. ProcessArgument(szFullpath, TRUE);
  146. Argument = NULL;
  147. }
  148. }
  149. char *
  150. SzSearchEnv (
  151. const char *szEnv,
  152. const char *szFilename,
  153. const char *szDefaultExt
  154. )
  155. /*++
  156. Routine Description:
  157. Searches for szFilename, first in the current directory, then (if no
  158. explicit path specified) along the LIB path. If szDefaultExt is non-NULL
  159. it should start with a ".". It will be the extension if the original file
  160. doesn't have one.
  161. Arguments:
  162. szEnv - Name of environment variable containing path
  163. szFilename - file name
  164. szDefaultExt - default file extension to use, eg. ".lib"
  165. Return Value:
  166. Returns a malloc'ed buffer containing the pathname of the file which was
  167. found. If the file is not found, returns szFilename.
  168. --*/
  169. {
  170. char szDrive[_MAX_DRIVE];
  171. char szDir[_MAX_DIR];
  172. char szFname[_MAX_FNAME];
  173. char szExt[_MAX_EXT];
  174. char szFullFilename[_MAX_PATH];
  175. _splitpath(szFilename, szDrive, szDir, szFname, szExt);
  176. if ((szExt[0] == '\0') && (szDefaultExt != NULL)) {
  177. assert(szDefaultExt[0] == '.');
  178. assert(strlen(szDefaultExt) <= _MAX_EXT);
  179. _makepath(szFullFilename, szDrive, szDir, szFname, szDefaultExt);
  180. szFilename = szFullFilename;
  181. }
  182. if (_access(szFilename, 0) == 0) {
  183. return SzDup(szFilename);
  184. }
  185. // Don't search if drive or dir specified
  186. if ((szDrive[0] == '\0') && (szDir[0] == '\0')) {
  187. char szPath[_MAX_PATH];
  188. _searchenv(szFilename, szEnv, szPath);
  189. if (szPath[0] != '\0') {
  190. return SzDup(szPath);
  191. }
  192. }
  193. return SzDup(szFilename); // didn't find it on lib path
  194. }
  195. void
  196. ProcessArgument (
  197. char *Argument,
  198. BOOL CommandFile
  199. )
  200. /*++
  201. Routine Description:
  202. Determines if an argument is either a switch or a filename argument.
  203. Adds argument to either switch or filename list.
  204. Arguments:
  205. Argument - The argument to process.
  206. CommandFile - If TRUE, then argument was read from a command file, and
  207. argument needs to be copied before adding to list.
  208. Return Value:
  209. None.
  210. --*/
  211. {
  212. char c;
  213. char *name;
  214. PNAME_LIST ptrList;
  215. // Fetch first character of argument.
  216. c = Argument[0];
  217. // If argument is a switch, then add it to
  218. // the switch list (but don't include the switch character).
  219. if ((c == '/') || (c == '-')) {
  220. ptrList = &SwitchArguments;
  221. name = Argument+1;
  222. if (name[0] == '?' && name[1] != '\0') {
  223. name++; // ignore '?' before non-null arg (temporary)
  224. }
  225. // Dup the string if it came from a file. Since dup allocates
  226. // memory, this memory is never freed by the program.
  227. // It is only recovered when the program terminates.
  228. if (CommandFile) {
  229. name = SzDup(name);
  230. }
  231. } else if (_tcspbrk(Argument, "?*")) {
  232. ProcessWildCards(Argument);
  233. return;
  234. } else {
  235. const char *szExt;
  236. // If not a switch, then treat the argument as a filename.
  237. // The linker has a default extension of ".obj";
  238. if (Tool == Linker) {
  239. szExt = ".obj";
  240. } else {
  241. szExt = NULL;
  242. }
  243. // Search for file in current directory and along LIB path
  244. name = SzSearchEnv("LIB", Argument, szExt);
  245. // Add filename to list. In the case of the linker it adds
  246. // it to filename list. For the rest the files get classified
  247. // as objs/libs and get added to corresponding lists.
  248. if ((Tool == Linker) || (Tool == Dumper)) {
  249. ptrList = &FilenameArguments;
  250. } else {
  251. FileReadHandle = FileOpen(name, O_RDONLY | O_BINARY, 0);
  252. // If file is an archive, then add filename to archive list.
  253. if (IsArchiveFile(name, FileReadHandle)) {
  254. ptrList = &ArchiveFilenameArguments;
  255. } else {
  256. // Not an archive, so treat it as an object
  257. // and add filename to object list.
  258. ptrList = &ObjectFilenameArguments;
  259. }
  260. // Close the file.
  261. FileClose(FileReadHandle, FALSE);
  262. }
  263. }
  264. // Add the argument to list.
  265. AddArgument(ptrList, name);
  266. }
  267. void
  268. ParseCommandString(
  269. char *szCommands
  270. )
  271. // Parses a string of commands (calling ProcessArgument on each token).
  272. //
  273. // Note: clobbers SzGetArgument's static data.
  274. {
  275. char *token;
  276. BOOL fQuoted;
  277. if ((token = SzGetArgument(szCommands, &fQuoted)) != NULL) {
  278. while (token) {
  279. if (fQuoted) {
  280. IbAppendBlk(&blkResponseFileEcho, "\"", 1);
  281. }
  282. IbAppendBlk(&blkResponseFileEcho, token, strlen(token));
  283. if (fQuoted) {
  284. IbAppendBlk(&blkResponseFileEcho, "\"", 1);
  285. }
  286. IbAppendBlk(&blkResponseFileEcho, " ", 1);
  287. ProcessArgument(token, TRUE);
  288. token = SzGetArgument(NULL, &fQuoted);
  289. }
  290. IbAppendBlk(&blkResponseFileEcho, "\n", 1);
  291. }
  292. }
  293. void
  294. ParseCommandLine(
  295. int Argc,
  296. char *Argv[],
  297. const char *szEnvVar
  298. )
  299. /*++
  300. Routine Description:
  301. Parse the command line (or command file) placing all switches into
  302. SwitchArguments list, all object files into ObjectFilenameArguments list,
  303. and all archives into ArchiveFilenameArguments list. Switches start with
  304. either a hypen (-) or slash (/). A command file is specified with
  305. the first character being an at (@) sign.
  306. Arguments:
  307. Argc - Argument count.
  308. Argv - Array of argument strings.
  309. Return Value:
  310. None.
  311. --*/
  312. {
  313. INT i;
  314. char *argument;
  315. FILE *file_read_stream;
  316. // Process the environment variable if any.
  317. if (szEnvVar) {
  318. char *szEnvValue = getenv(szEnvVar);
  319. if (szEnvValue) {
  320. szEnvValue = SzDup(szEnvValue);
  321. ParseCommandString(szEnvValue);
  322. FreePv(szEnvValue);
  323. }
  324. }
  325. // Process every argument.
  326. pargFirst = NULL; // global variable to inform caller
  327. for (i = 1; i < Argc; i++) {
  328. // Fetch first character of argument and determine
  329. // if argument specifies a command file.
  330. if (*Argv[i] == '@') {
  331. // Argument is a command file, so open it.
  332. if (!(file_read_stream = fopen(Argv[i]+1, "rt"))) {
  333. Fatal(NULL, CANTOPENFILE, Argv[i]+1);
  334. }
  335. // Allocate big buffer for read a line of text
  336. argument = (char *) PvAlloc(4*_4K);
  337. // Process all arguments from command file.
  338. // fgets() fetches next argument from command file.
  339. while (fgets(argument, (INT)(4*_4K), file_read_stream)) {
  340. size_t len = strlen(argument);
  341. // check if we didn't get the entire line
  342. if (len >= ((4*_4K) - 1) && argument[len-1] != '\n') {
  343. Fatal(Argv[i]+1, LINETOOLONG,((4*_4K) - 1));
  344. }
  345. if (argument[len-1] == '\n') {
  346. // Replace \n with \0.
  347. argument[len-1] = '\0';
  348. }
  349. ParseCommandString(argument);
  350. }
  351. // Free memory use for line buffer
  352. FreePv(argument);
  353. // flush stdout. has effect only on the linker.
  354. fflush(stdout);
  355. // Processed all arguments from the command file,
  356. // so close the command file.
  357. fclose(file_read_stream);
  358. } else {
  359. // No command file.
  360. ProcessArgument(Argv[i], FALSE);
  361. }
  362. }
  363. }
  364. void
  365. AddArgumentToNumList (
  366. PNUMBER_LIST PtrNumList,
  367. char *szOriginalName,
  368. char *szModifiedName,
  369. DWORD dwNumber
  370. )
  371. /*++
  372. Routine Description:
  373. Adds name and number to a simple linked list.
  374. Arguments:
  375. PtrNumList - List to add to.
  376. szName - Original name of argument to add to list.
  377. dwNumber - The number to add
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. PNUM_ARGUMENT_LIST ptrNumList;
  383. // Allocate next member of list.
  384. ptrNumList = (PNUM_ARGUMENT_LIST) PvAllocZ(sizeof(NUM_ARGUMENT_LIST));
  385. // Set the fields of the new member.
  386. ptrNumList->szOriginalName = szOriginalName;
  387. ptrNumList->szModifiedName = szModifiedName;
  388. ptrNumList->dwNumber = dwNumber;
  389. // If first member in list, remember first member.
  390. if (!PtrNumList->First) {
  391. PtrNumList->First = ptrNumList;
  392. } else {
  393. // Not first member, so append to end of list.
  394. PtrNumList->Last->Next = ptrNumList;
  395. }
  396. // Increment number of members in list.
  397. PtrNumList->Count++;
  398. // Remember last member in list.
  399. PtrNumList->Last = ptrNumList;
  400. // If this is the first arg seen (in whichever list), should we report to caller
  401. // via global variable?
  402. }
  403. void
  404. AddArgumentToList (
  405. PNAME_LIST PtrList,
  406. char *OriginalName,
  407. char *ModifiedName
  408. )
  409. /*++
  410. Routine Description:
  411. Adds name, to a simple linked list.
  412. Arguments:
  413. PtrList - List to add to.
  414. OriginalName - Original name of argument to add to list.
  415. ModifiedName - Modified name of argument to add to list.
  416. Return Value:
  417. None.
  418. --*/
  419. {
  420. PARGUMENT_LIST ptrList;
  421. // Allocate next member of list.
  422. ptrList = (PARGUMENT_LIST) PvAllocZ(sizeof(ARGUMENT_LIST));
  423. // Set the fields of the new member.
  424. ptrList->OriginalName = OriginalName;
  425. ptrList->ModifiedName = ModifiedName;
  426. // If first member in list, remember first member.
  427. if (!PtrList->First) {
  428. PtrList->First = ptrList;
  429. } else {
  430. // Not first member, so append to end of list.
  431. PtrList->Last->Next = ptrList;
  432. }
  433. // Increment number of members in list.
  434. PtrList->Count++;
  435. // Remember last member in list.
  436. PtrList->Last = ptrList;
  437. // If this is the first arg seen (in whichever list), report to caller
  438. // via global variable.
  439. if (pargFirst == NULL && PtrList != &SwitchArguments) {
  440. pargFirst = ptrList;
  441. }
  442. }
  443. BOOL
  444. FArgumentInList (
  445. const char *szName,
  446. PNAME_LIST PtrList
  447. )
  448. /*++
  449. Routine Description:
  450. Checks for name in a simple linked list.
  451. Arguments:
  452. szName - Name to be checked
  453. PtrList - List to check with.
  454. Return Value:
  455. TRUE if present and FALSE if not.
  456. --*/
  457. {
  458. PARGUMENT_LIST pal;
  459. DWORD i;
  460. for (i = 0, pal = PtrList->First;
  461. i < PtrList->Count;
  462. i++, pal = pal->Next) {
  463. // Case in-sensitive comparison
  464. // UNDONE: Should this be _tcsicmp
  465. if (!_stricmp(pal->OriginalName, szName)) {
  466. return TRUE;
  467. }
  468. }
  469. return FALSE;
  470. }
  471. void
  472. AddArgument (
  473. PNAME_LIST PtrList,
  474. char *Name
  475. )
  476. /*++
  477. Routine Description:
  478. Arguments:
  479. PtrList - List to add to.
  480. Name - Original name of argument to add to list.
  481. Return Value:
  482. None.
  483. --*/
  484. {
  485. AddArgumentToList(PtrList, Name, Name);
  486. }
  487. void
  488. FreeArgumentNumberList (
  489. PNUMBER_LIST PtrNumList
  490. )
  491. /*++
  492. Routine Description:
  493. Frees up list elements.
  494. Arguments:
  495. PtrList - List to free.
  496. Return Value:
  497. None.
  498. --*/
  499. {
  500. PNUM_ARGUMENT_LIST ptrListCurr, ptrListNext;
  501. if (!PtrNumList->Count) {
  502. return;
  503. }
  504. ptrListCurr = PtrNumList->First;
  505. while (ptrListCurr) {
  506. ptrListNext = ptrListCurr->Next;
  507. FreePv(ptrListCurr);
  508. ptrListCurr = ptrListNext;
  509. }
  510. PtrNumList->Count = 0;
  511. PtrNumList->First = PtrNumList->Last = NULL;
  512. }
  513. void
  514. FreeArgumentList (
  515. PNAME_LIST PtrList
  516. )
  517. /*++
  518. Routine Description:
  519. Frees up list elements.
  520. Arguments:
  521. PtrList - List to free.
  522. Return Value:
  523. None.
  524. --*/
  525. {
  526. PARGUMENT_LIST ptrListCurr, ptrListNext;
  527. if (!PtrList->Count) {
  528. return;
  529. }
  530. ptrListCurr = PtrList->First;
  531. while (ptrListCurr) {
  532. ptrListNext = ptrListCurr->Next;
  533. FreePv(ptrListCurr);
  534. ptrListCurr = ptrListNext;
  535. }
  536. PtrList->Count = 0;
  537. PtrList->First = PtrList->Last = NULL;
  538. }
  539. BOOL
  540. IsArchiveFile (
  541. const char *szName,
  542. INT Handle
  543. )
  544. /*++
  545. Routine Description:
  546. Determines if a file is an object or archive file.
  547. Arguments:
  548. szName - name of file.
  549. Handle - An open file handle. File pointer should be positioned
  550. at beginning of file before calling this routine.
  551. Return Value:
  552. TRUE if file is an archive.
  553. FALSE if file isn't an archive.
  554. If TRUE, then global variable MemberSeekBase is set to next
  555. file position after archive header.
  556. --*/
  557. {
  558. BYTE archive_header[IMAGE_ARCHIVE_START_SIZE];
  559. if (FileRead(Handle, archive_header, IMAGE_ARCHIVE_START_SIZE) !=
  560. IMAGE_ARCHIVE_START_SIZE) {
  561. Fatal(szName, CANTREADFILE, FileTell(Handle));
  562. }
  563. // If strings match, then this is an archive file, so advance
  564. // MemberSeekBase.
  565. if (!memcmp(archive_header, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE)) {
  566. MemberSeekBase = IMAGE_ARCHIVE_START_SIZE;
  567. return(TRUE);
  568. }
  569. return(FALSE);
  570. }
  571. void
  572. VerifyMachine (
  573. const char *Filename,
  574. WORD MachineType,
  575. PIMAGE_FILE_HEADER pImgFileHdr
  576. )
  577. /*++
  578. Routine Description:
  579. Verifys target machine type. Assumes ImageFileHdr.Machine has
  580. been set.
  581. Arguments:
  582. Filename - Filename of file to verify.
  583. MachineType - Machine value to verify.
  584. Return Value:
  585. None.
  586. --*/
  587. {
  588. const char *szTargetMachine;
  589. const char *szCurrentMachine;
  590. if (pImgFileHdr->Machine == MachineType) {
  591. return;
  592. }
  593. switch (MachineType) {
  594. case IMAGE_FILE_MACHINE_I386:
  595. szCurrentMachine = "IX86";
  596. break;
  597. case IMAGE_FILE_MACHINE_R3000:
  598. if (pImgFileHdr->Machine == IMAGE_FILE_MACHINE_R4000) {
  599. // R3000 code is acceptable for R4000 image
  600. return;
  601. }
  602. // Fall through
  603. case IMAGE_FILE_MACHINE_R4000 :
  604. if (pImgFileHdr->Machine == IMAGE_FILE_MACHINE_R10000) {
  605. // R3000/R4000 code is acceptable for a R10000 image
  606. return;
  607. }
  608. szCurrentMachine = "MIPS";
  609. break;
  610. case IMAGE_FILE_MACHINE_R10000 :
  611. if (pImgFileHdr->Machine == IMAGE_FILE_MACHINE_R4000) {
  612. // A T5 object requires a T5 image
  613. Warning(NULL, PROMOTEMIPS);
  614. pImgFileHdr->Machine = IMAGE_FILE_MACHINE_R10000;
  615. return;
  616. }
  617. szCurrentMachine = "MIPSR10";
  618. break;
  619. case IMAGE_FILE_MACHINE_ALPHA :
  620. szCurrentMachine = "ALPHA";
  621. break;
  622. case IMAGE_FILE_MACHINE_POWERPC :
  623. szCurrentMachine = "PPC";
  624. break;
  625. case IMAGE_FILE_MACHINE_M68K :
  626. szCurrentMachine = "M68K";
  627. break;
  628. case IMAGE_FILE_MACHINE_MPPC_601 :
  629. szCurrentMachine = "MPPC";
  630. break;
  631. default :
  632. Fatal(Filename, UNKNOWNMACHINETYPE, MachineType);
  633. }
  634. switch (pImgFileHdr->Machine) {
  635. case IMAGE_FILE_MACHINE_I386:
  636. szTargetMachine = "IX86";
  637. break;
  638. case IMAGE_FILE_MACHINE_R4000 :
  639. szTargetMachine = "MIPS";
  640. break;
  641. case IMAGE_FILE_MACHINE_R10000 :
  642. szTargetMachine = "MIPSR10"; // UNDONE: Same message as MIPS?
  643. break;
  644. case IMAGE_FILE_MACHINE_ALPHA :
  645. szTargetMachine = "ALPHA";
  646. break;
  647. case IMAGE_FILE_MACHINE_POWERPC :
  648. szTargetMachine = "PPC";
  649. break;
  650. case IMAGE_FILE_MACHINE_M68K :
  651. szTargetMachine = "M68K";
  652. break;
  653. case IMAGE_FILE_MACHINE_MPPC_601 :
  654. szTargetMachine = "MPPC";
  655. break;
  656. }
  657. Fatal(Filename, CONFLICTINGMACHINETYPE, szCurrentMachine, szTargetMachine);
  658. }
  659. void
  660. ReadSpecialLinkerInterfaceMembers(
  661. PLIB plib,
  662. PIMAGE pimage
  663. )
  664. /*++
  665. Routine Description:
  666. Reads the linker interface member out of an archive file, and adds
  667. its extern symbols to the archive list. A linker member must exist in an
  668. archive file, or the archive file will not be searched for undefined
  669. externals. A warning is given if no linker member exits. The optional
  670. header from the first member is read to determine what machine and
  671. subsystem the library is targeted for.
  672. An achive file may contain 2 linker members. The first would be that
  673. of standard coff. The offsets are sorted, the strings aren't. The
  674. second linker member is a slightly different format, and is sorted
  675. by symbol names. If the second linker member is present, it will be
  676. used for symbol lookup since it is faster.
  677. The members long file name table is also read if it exits.
  678. Arguments:
  679. plib - library node for the driver map to be updated
  680. pimage - ptr to image
  681. Return Value:
  682. None.
  683. --*/
  684. {
  685. PIMAGE_ARCHIVE_MEMBER_HEADER pImArcMemHdr;
  686. IMAGE_ARCHIVE_MEMBER_HEADER ImArcMemHdrPos;
  687. IMAGE_OPTIONAL_HEADER ImObjOptFileHdr;
  688. IMAGE_FILE_HEADER ImObjFileHdr;
  689. BYTE *pbST;
  690. DWORD csymIntMem;
  691. DWORD cMemberOffsets;
  692. DWORD foNewMem, foOldMem;
  693. DWORD foSymNew;
  694. DWORD cbST;
  695. DWORD isym;
  696. DWORD cblib;
  697. MemberSeekBase = IMAGE_ARCHIVE_START_SIZE;
  698. MemberSize = 0;
  699. // Read member and verify it is a linker member.
  700. pImArcMemHdr = ReadArchiveMemberHeader();
  701. if (memcmp(pImArcMemHdr->Name, IMAGE_ARCHIVE_LINKER_MEMBER, 16)) {
  702. if (Tool != Librarian) {
  703. Warning(plib->szName, NOLINKERMEMBER);
  704. }
  705. return;
  706. }
  707. // Read the number of public symbols defined in linker member.
  708. FileRead(FileReadHandle, &csymIntMem, sizeof(DWORD));
  709. // All fields in member headers are stored machine independent
  710. // integers (4 bytes). Convert numbers to current machine long word.
  711. csymIntMem = plib->csymIntMem = sgetl(&csymIntMem);
  712. // remember where we were in the file
  713. foOldMem = FileTell(FileReadHandle);
  714. // Peek ahead and see if there is a second linker member.
  715. // Remember member headers always start on an even byte.
  716. foNewMem = EvenByteAlign(MemberSeekBase + MemberSize);
  717. FileSeek(FileReadHandle, foNewMem, SEEK_SET);
  718. FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
  719. cblib = FileLength(FileReadHandle);
  720. if (!memcmp(ImArcMemHdrPos.Name, IMAGE_ARCHIVE_LINKER_MEMBER, 16)) {
  721. // Second linker member was found so read it.
  722. pImArcMemHdr = ReadArchiveMemberHeader();
  723. plib->flags |= LIB_NewIntMem;
  724. // Free offsets for first linker member and malloc new offsets
  725. // for the second linker member. Can't store new offsets over
  726. // the old offsets because even though the second linker
  727. // member offsets are unique and are not repeated like they are
  728. // for the first linker member, you can't assume there will
  729. // never be more offsets in the second linker member that there
  730. // are in the first. This wouldn't be true if there were four
  731. // members, the first and last members each had a public symbol,
  732. // but the second and third had no public symbols. Of course there
  733. // is no way the linker would extract the second and third members,
  734. // but it would still be a valid library.
  735. FileRead(FileReadHandle, &cMemberOffsets, sizeof(DWORD));
  736. plib->rgulSymMemOff = (DWORD *) PvAlloc((size_t) (cMemberOffsets + 1) * sizeof(DWORD));
  737. if (cblib < ((cMemberOffsets * sizeof(DWORD)) + FileTell(FileReadHandle))) {
  738. Fatal(plib->szName, BADLIBRARY, NULL);
  739. }
  740. FileRead(FileReadHandle, &plib->rgulSymMemOff[1], cMemberOffsets * sizeof(DWORD));
  741. // Unlike the first linker member, the second linker member has an
  742. // additional table. This table is used to index into the offset table.
  743. // So make space for the offset index table and read it in.
  744. FileRead(FileReadHandle, &csymIntMem, sizeof(DWORD));
  745. plib->rgusOffIndex = (WORD *) PvAlloc((size_t) csymIntMem * sizeof(WORD));
  746. if (cblib < ((csymIntMem * sizeof(WORD)) + FileTell(FileReadHandle))) {
  747. Fatal(plib->szName, BADLIBRARY, NULL);
  748. }
  749. FileRead(FileReadHandle, plib->rgusOffIndex, csymIntMem * sizeof(WORD));
  750. // Read the sorted string table over the top of the string table stored
  751. // for the first linker member. Unlike the first linker member, strings
  752. // aren't repeated, thus the table will never be larger than that of
  753. // the first linker member.
  754. cbST = MemberSize - (FileTell(FileReadHandle) - (foNewMem + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)));
  755. plib->rgbST = (BYTE *) PvAlloc((size_t) cbST);
  756. FileRead(FileReadHandle, plib->rgbST, cbST);
  757. } else {
  758. // There was no new member; so set the filepointer to back where it was
  759. FileSeek(FileReadHandle, foOldMem, SEEK_SET);
  760. // Create space to store linker member offsets and read it in.
  761. plib->rgulSymMemOff = (DWORD *) PvAlloc((size_t) (csymIntMem + 1) * sizeof(DWORD));
  762. FileRead(FileReadHandle, plib->rgulSymMemOff, csymIntMem * sizeof(DWORD));
  763. // Calculate size of linker member string table. The string table is
  764. // the last part of a linker member and follows the offsets (which
  765. // were just read in), thus the total size of the strings is the
  766. // total size of the member minus the current position of the file
  767. // pointer.
  768. cbST = IMAGE_ARCHIVE_START_SIZE + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER) +
  769. (MemberSize - FileTell(FileReadHandle));
  770. // Now that we know the size of the linker member string table, lets
  771. // make space for it and read it in.
  772. plib->rgbST = (BYTE *) PvAlloc((size_t) cbST);
  773. FileRead(FileReadHandle, plib->rgbST, cbST);
  774. }
  775. // Since we are going to use an index to reference into the
  776. // offset table, we will make a string table, in which the
  777. // same index can be used to find the symbol name or visa versa.
  778. plib->rgszSym = (char **) PvAlloc((size_t) plib->csymIntMem * sizeof(char *));
  779. for (isym = 0, pbST = plib->rgbST; isym < plib->csymIntMem; isym++) {
  780. plib->rgszSym[isym] = (char *) pbST;
  781. while (*pbST++) {
  782. }
  783. }
  784. // Read the member long file name table if it exits.
  785. // Peek ahead and see if there is a long filename table.
  786. // Remember member headers always start on an even byte.
  787. foNewMem = EvenByteAlign(MemberSeekBase + MemberSize);
  788. FileSeek(FileReadHandle, foNewMem, SEEK_SET);
  789. FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
  790. if (!memcmp(ImArcMemHdrPos.Name, IMAGE_ARCHIVE_LONGNAMES_MEMBER, 16)) {
  791. // Long filename table was found so read it.
  792. pImArcMemHdr = ReadArchiveMemberHeader();
  793. // Read the strings.
  794. pbST = (BYTE *) PvAlloc((size_t) MemberSize);
  795. if (cblib < (MemberSize + FileTell(FileReadHandle))) {
  796. Fatal(plib->szName, BADLIBRARY, NULL);
  797. }
  798. FileRead(FileReadHandle, pbST, MemberSize);
  799. plib->rgbLongFileNames = pbST;
  800. } else {
  801. plib->rgbLongFileNames = NULL;
  802. }
  803. // Peek ahead and see if there is an optional header in the
  804. // first member. If there is, determine the target machine & subsystem.
  805. if (pimage->ImgFileHdr.Machine) {
  806. foSymNew = EvenByteAlign(MemberSeekBase + MemberSize);
  807. FileSeek(FileReadHandle, foSymNew, SEEK_SET);
  808. FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
  809. ReadFileHeader(FileReadHandle, &ImObjFileHdr);
  810. if (ImObjFileHdr.Machine) {
  811. VerifyMachine(plib->szName, ImObjFileHdr.Machine, &pimage->ImgFileHdr);
  812. }
  813. if (ImObjFileHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER)) {
  814. ReadOptionalHeader(FileReadHandle, &ImObjOptFileHdr,
  815. ImObjFileHdr.SizeOfOptionalHeader);
  816. // UNDONE: Why perform this check. Is there value in having
  817. // UNDONE: a library tied to a subsystem?
  818. if (ImObjOptFileHdr.Subsystem &&
  819. (ImObjOptFileHdr.Subsystem != pimage->ImgOptHdr.Subsystem)) {
  820. // no warning if the two differing subsystems are windows gui & console
  821. if (!((ImObjOptFileHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI && pimage->ImgOptHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) ||
  822. (ImObjOptFileHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI && pimage->ImgOptHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)))
  823. Warning(plib->szName, CONFLICTINGSUBSYSTEM);
  824. }
  825. }
  826. }
  827. }
  828. PIMAGE_ARCHIVE_MEMBER_HEADER
  829. ReadArchiveMemberHeader (
  830. VOID
  831. )
  832. /*++
  833. Routine Description:
  834. Reads the member header.
  835. Arguments:
  836. PtrLinkerArchive - Used to expand the member name.
  837. Return Value:
  838. Member name.
  839. --*/
  840. {
  841. LONG seek;
  842. static IMAGE_ARCHIVE_MEMBER_HEADER ArchiveMemberHdr;
  843. seek = EvenByteAlign(MemberSeekBase + MemberSize);
  844. FileSeek(FileReadHandle, seek, SEEK_SET);
  845. FileRead(FileReadHandle, &ArchiveMemberHdr, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
  846. // Calculate the current file pointer (same as tell(FileReadHandle)).
  847. MemberSeekBase = seek + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
  848. sscanf((char *) ArchiveMemberHdr.Size, "%ld", &MemberSize);
  849. return(&ArchiveMemberHdr);
  850. }
  851. const char *
  852. ExpandMemberName (
  853. PLIB plib,
  854. const char *szMemberName
  855. )
  856. /*++
  857. Routine Description:
  858. Expands a member name if it has a long filename.
  859. Arguments:
  860. plib - Used to expand the member name.
  861. szMemberName - Member name (padded with NULLs, no null).
  862. Return Value:
  863. Member name.
  864. --*/
  865. {
  866. static char szName[_MAX_PATH];
  867. char *p;
  868. strncpy(szName, szMemberName, 16);
  869. szName[16] = '\0';
  870. if (szName[0] == '/') {
  871. if (szName[1] != ' ' && szName[1] != '/') {
  872. p = strchr(szName, ' ');
  873. if (!p) {
  874. return(p);
  875. }
  876. *p = '\0';
  877. p = (char *) (plib->rgbLongFileNames + atoi(&szName[1]));
  878. } else {
  879. // UNDONE: This can be an MBCS string. Use _tcschr?
  880. p = strchr(szName, ' ');
  881. if (!p) {
  882. return(p);
  883. }
  884. *p = '\0';
  885. p = szName;
  886. }
  887. } else {
  888. // UNDONE: This can be an MBCS string. Use _tcschr?
  889. p = strrchr(szName, '/'); // find the last occurence
  890. if (!p) {
  891. return(p);
  892. }
  893. *p = '\0';
  894. p = szName;
  895. }
  896. return(p);
  897. }
  898. DWORD
  899. sgetl (
  900. DWORD *Value
  901. )
  902. /*++
  903. Routine Description:
  904. Converts a four-byte machine independent integer into a long.
  905. Arguments:
  906. Value - Four-byte machine independent integer
  907. Return Value:
  908. Value of four-byte machine independent integer.
  909. --*/
  910. {
  911. BYTE *pb;
  912. union {
  913. LONG new_value;
  914. BYTE x[4];
  915. } temp;
  916. pb = (BYTE *) Value;
  917. temp.x[0] = pb[3];
  918. temp.x[1] = pb[2];
  919. temp.x[2] = pb[1];
  920. temp.x[3] = pb[0];
  921. return(temp.new_value);
  922. }
  923. DWORD
  924. sputl (
  925. DWORD *Value
  926. )
  927. /*++
  928. Routine Description:
  929. Converts a long into a four-byte machine independent integer.
  930. Arguments:
  931. Value - value to convert.
  932. Return Value:
  933. Four-byte machine independent integer.
  934. --*/
  935. {
  936. return(sgetl(Value));
  937. }
  938. WORD WSwap(WORD w)
  939. {
  940. WORD wSwap;
  941. ((BYTE *) &wSwap)[1] = ((BYTE *) &w)[0];
  942. ((BYTE *) &wSwap)[0] = ((BYTE *) &w)[1];
  943. return(wSwap);
  944. }
  945. DWORD DwSwap(DWORD dw)
  946. {
  947. DWORD dwSwap;
  948. ((BYTE *) &dwSwap)[3] = ((BYTE *) &dw)[0];
  949. ((BYTE *) &dwSwap)[2] = ((BYTE *) &dw)[1];
  950. ((BYTE *) &dwSwap)[1] = ((BYTE *) &dw)[2];
  951. ((BYTE *) &dwSwap)[0] = ((BYTE *) &dw)[3];
  952. return(dwSwap);
  953. }
  954. void SwapBytes(void *pv, DWORD cb)
  955. {
  956. BYTE *pb = (BYTE *) pv;
  957. while (cb > 0) {
  958. BYTE rgbT[4];
  959. DWORD n;
  960. DWORD i;
  961. n = (cb > 3) ? 4 : cb;
  962. memcpy(rgbT, pb, n);
  963. for (i = n; i > 0; i--) {
  964. pb[i-1] = rgbT[n - i];
  965. }
  966. pb += n;
  967. cb -= n;
  968. }
  969. }
  970. void
  971. ApplyCommandLineSectionAttributes(
  972. PSEC psec
  973. )
  974. /*++
  975. Routine Description:
  976. Apply any specified command line section attributes to a section header.
  977. Arguments:
  978. pimsechdr - section header
  979. Return Value:
  980. None.
  981. --*/
  982. {
  983. PARGUMENT_LIST parg;
  984. const char *szSecName = psec->szName;
  985. char *pb;
  986. WORD iarg;
  987. size_t cb;
  988. for (iarg = 0, parg = SectionNames.First;
  989. iarg < SectionNames.Count;
  990. iarg++, parg = parg->Next) {
  991. pb = strchr(parg->OriginalName, ',');
  992. if (pb) {
  993. cb = (size_t) (pb - parg->OriginalName);
  994. ++pb;
  995. // Use strncmp here for matching section names, because we want
  996. // to ignore the comma in parg->OriginalName (which precedes
  997. // the attributes).
  998. if (!strncmp(parg->OriginalName, szSecName, cb) &&
  999. szSecName[cb] == '\0')
  1000. {
  1001. parg->Flags |= ARG_Processed;
  1002. if (*pb != ',') {
  1003. BOOL fYes;
  1004. DWORD dwReset;
  1005. DWORD dwSet;
  1006. fYes = TRUE;
  1007. dwReset = 0;
  1008. dwSet = 0;
  1009. // Check for end of argument or the second comma,
  1010. // which starts the Mac resource info.
  1011. while (pb && *pb && *pb != ',') {
  1012. BOOL fReversed;
  1013. DWORD f = 0; // init because not all cases set it
  1014. fReversed = FALSE;
  1015. switch (toupper(*pb)) {
  1016. case '!':
  1017. case 'N':
  1018. fYes = !fYes;
  1019. f = 0;
  1020. break;
  1021. case 'D':
  1022. f = IMAGE_SCN_MEM_DISCARDABLE;
  1023. break;
  1024. case 'E' :
  1025. if (fYes) {
  1026. // For compatibility with VC++ 1.0
  1027. dwReset |= IMAGE_SCN_MEM_READ;
  1028. dwReset |= IMAGE_SCN_MEM_WRITE;
  1029. }
  1030. f = IMAGE_SCN_MEM_EXECUTE;
  1031. break;
  1032. case 'K':
  1033. fReversed = TRUE;
  1034. f = IMAGE_SCN_MEM_NOT_CACHED;
  1035. break;
  1036. case 'P':
  1037. fReversed = TRUE;
  1038. f = IMAGE_SCN_MEM_NOT_PAGED;
  1039. break;
  1040. case 'R' :
  1041. if (fYes) {
  1042. // For compatibility with VC++ 1.0
  1043. dwReset |= IMAGE_SCN_MEM_EXECUTE;
  1044. dwReset |= IMAGE_SCN_MEM_WRITE;
  1045. }
  1046. f = IMAGE_SCN_MEM_READ;
  1047. break;
  1048. case 'S' :
  1049. f = IMAGE_SCN_MEM_SHARED;
  1050. break;
  1051. case 'W' :
  1052. if (fYes) {
  1053. // For compatibility with VC++ 1.0
  1054. dwReset |= IMAGE_SCN_MEM_EXECUTE;
  1055. dwReset |= IMAGE_SCN_MEM_READ;
  1056. }
  1057. f = IMAGE_SCN_MEM_WRITE;
  1058. break;
  1059. // VXD specific options
  1060. case 'L':
  1061. // VXDs only
  1062. psec->fPreload = (CHAR) fYes;
  1063. break;
  1064. case 'X' :
  1065. // VXDs only
  1066. f = IMAGE_SCN_MEM_RESIDENT;
  1067. break;
  1068. case 'I':
  1069. psec->fIopl = (CHAR) fYes;
  1070. break;
  1071. case 'C':
  1072. psec->fConforming = (CHAR) fYes;
  1073. break;
  1074. default:
  1075. Fatal(NULL, BADSECTIONSWITCH, parg->OriginalName);
  1076. break;
  1077. }
  1078. dwReset |= f;
  1079. if (fYes ^ fReversed) {
  1080. dwSet |= f;
  1081. } else {
  1082. dwSet &= ~f;
  1083. }
  1084. pb++;
  1085. }
  1086. psec->flags &= ~dwReset;
  1087. psec->flags |= dwSet;
  1088. psec->fDiscardable = (CHAR) ((psec->flags & IMAGE_SCN_MEM_DISCARDABLE) != 0);
  1089. }
  1090. }
  1091. }
  1092. }
  1093. }
  1094. void
  1095. PrintUndefinedExternals(
  1096. PST pst
  1097. )
  1098. /*++
  1099. Routine Description:
  1100. Writes undefined external symbols to standard out.
  1101. Arguments:
  1102. pst - pointer to external structure
  1103. Return Value:
  1104. none
  1105. --*/
  1106. {
  1107. ENM_UNDEF_EXT enmUndefExt;
  1108. if (fPowerMac && fMPPCVersionConflict && !Verbose) {
  1109. Warning (NULL, MACVERSIONCONFLICT);
  1110. }
  1111. InitEnmUndefExt(&enmUndefExt, pst);
  1112. while (FNextEnmUndefExt(&enmUndefExt)) {
  1113. PEXTERNAL pext;
  1114. const char *szName;
  1115. char *szOutput;
  1116. BOOL fRef;
  1117. ENM_MOD_EXT enmModExt;
  1118. pext = enmUndefExt.pext;
  1119. if (pext->Flags & EXTERN_IGNORE) {
  1120. continue;
  1121. }
  1122. if (pext->Flags & EXTERN_DEFINED) {
  1123. continue;
  1124. }
  1125. UndefinedSymbols++;
  1126. if (pext->szOtherName != NULL) {
  1127. // This case can occur with a forwarder when building an import lib
  1128. if (pext->Flags & EXTERN_FORWARDER) {
  1129. szName = strchr(pext->szOtherName, '.') + 1;
  1130. if (szName[0] == '#') {
  1131. // When forwarding by ordinal, the local name is searched for.
  1132. szName = SzNamePext(pext, pst);
  1133. }
  1134. } else {
  1135. szName = pext->szOtherName;
  1136. }
  1137. } else {
  1138. szName = SzNamePext(pext, pst);
  1139. }
  1140. szOutput = SzOutputSymbolName(szName, TRUE);
  1141. fRef = FALSE;
  1142. InitEnmModExt(&enmModExt, pext);
  1143. while (FNextEnmModExt(&enmModExt)) {
  1144. char szBuf[_MAX_PATH * 2];
  1145. fRef = TRUE;
  1146. // look out for the special pch symbol
  1147. if (!strncmp(szName, "___@@_PchSym_@", 14) ||
  1148. !strncmp(szName, "__@@_PchSym_@", 13) ) {
  1149. Error(SzComNamePMOD(enmModExt.pmod, szBuf), MISSINGPCTOBJ);
  1150. EndEnmModExt(&enmModExt);
  1151. break;
  1152. }
  1153. Error(SzComNamePMOD(enmModExt.pmod, szBuf), UNDEFINED, szOutput);
  1154. }
  1155. if (!fRef) {
  1156. Error(NULL, UNDEFINED, szOutput);
  1157. }
  1158. if (szOutput != szName) {
  1159. free(szOutput);
  1160. }
  1161. // Check for ^C because this loop produce a great deal of output
  1162. if (fCtrlCSignal) {
  1163. BadExitCleanup();
  1164. }
  1165. }
  1166. EndEnmUndefExt(&enmUndefExt);
  1167. AllowInserts(pst);
  1168. }
  1169. void
  1170. SearchLib (
  1171. PIMAGE pimage,
  1172. PLIB plib,
  1173. PBOOL pfNewSymbol,
  1174. PBOOL pfUnresolved
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. Searches thru a library for symbols that match any undefined external
  1179. symbols.
  1180. Arguments:
  1181. pst - pointer to external structure
  1182. plib - library to search
  1183. pfNewSymbols - any new symbols added as a result of this search
  1184. pfUnresolved - any unresolved externals left
  1185. Return Value:
  1186. None.
  1187. --*/
  1188. {
  1189. ENM_UNDEF_EXT enmUndefExt;
  1190. if (plib->flags & LIB_DontSearch) {
  1191. return;
  1192. }
  1193. if (plib->szName != NULL) {
  1194. if (fVerboseLib) {
  1195. fputs(" ", stdout);
  1196. Message(LIBSRCH, plib->szName);
  1197. }
  1198. }
  1199. *pfUnresolved = 0;
  1200. // Enumerate all undefined symbols.
  1201. InitEnmUndefExt(&enmUndefExt, pimage->pst);
  1202. while (FNextEnmUndefExt(&enmUndefExt)) {
  1203. PEXTERNAL pext;
  1204. const char *szName;
  1205. char **pszEntry;
  1206. DWORD isz;
  1207. BOOL fFound;
  1208. PEXTERNAL pextPrev;
  1209. WORD iszIntMem;
  1210. DWORD iusOffIndex;
  1211. PIMAGE_ARCHIVE_MEMBER_HEADER parcMemHdr;
  1212. IMAGE_FILE_HEADER ImObjFileHdr;
  1213. PMOD pmod;
  1214. BOOL fNewSymbol;
  1215. pext = enmUndefExt.pext;
  1216. if (pext->Flags & EXTERN_IGNORE) {
  1217. continue;
  1218. }
  1219. if (pext->Flags & (EXTERN_WEAK | EXTERN_ALIAS)) {
  1220. // Do not search for definitions of weak and alias symbols
  1221. continue;
  1222. }
  1223. if ((pext->ImageSymbol.SectionNumber != 0) ||
  1224. (pext->ImageSymbol.Value != 0)) {
  1225. continue;
  1226. }
  1227. szName = SzNamePext(pext, pimage->pst);
  1228. if (plib->flags & LIB_NewIntMem) {
  1229. pszEntry = (char **) bsearch(&szName, plib->rgszSym,
  1230. (size_t) plib->csymIntMem, sizeof(char *), Compare);
  1231. fFound = (pszEntry != NULL);
  1232. } else {
  1233. fFound = FALSE;
  1234. for (isz = 0; isz < plib->csymIntMem; isz++) {
  1235. if (!strcmp(plib->rgszSym[isz], szName)) {
  1236. fFound = TRUE;
  1237. break;
  1238. }
  1239. }
  1240. }
  1241. if (!fFound) {
  1242. // An external was not found
  1243. *pfUnresolved = TRUE;
  1244. continue;
  1245. }
  1246. if (Verbose) {
  1247. ENM_MOD_EXT enmModExt;
  1248. fputs(" ", stdout);
  1249. Message(FNDSYM, szName);
  1250. InitEnmModExt(&enmModExt, pext);
  1251. while (FNextEnmModExt(&enmModExt)) {
  1252. char szBuf[_MAX_PATH * 2];
  1253. fputs(" ", stdout);
  1254. Message(SYMREF, SzComNamePMOD(enmModExt.pmod, szBuf));
  1255. }
  1256. }
  1257. // Back up one symbol in enumerator
  1258. if (pext == pimage->pst->pextFirstUndefined) {
  1259. pextPrev = NULL;
  1260. } else {
  1261. pextPrev = (PEXTERNAL) ((char *) pext->ppextPrevUndefined - offsetof(EXTERNAL, pextNextUndefined));
  1262. }
  1263. plib->flags |= LIB_Extract;
  1264. if (plib->flags & LIB_NewIntMem) {
  1265. iszIntMem = (WORD) (pszEntry - plib->rgszSym);
  1266. iusOffIndex = plib->rgusOffIndex[iszIntMem];
  1267. MemberSeekBase = plib->rgulSymMemOff[iusOffIndex];
  1268. } else {
  1269. iszIntMem = (WORD) isz;
  1270. MemberSeekBase = sgetl(&plib->rgulSymMemOff[iszIntMem]);
  1271. }
  1272. FileReadHandle = FileOpen(plib->szName, O_RDONLY | O_BINARY, 0);
  1273. MemberSize = 0;
  1274. // check for invalid lib
  1275. DWORD cblib = FileLength(FileReadHandle);
  1276. if (cblib < MemberSeekBase) {
  1277. Fatal(plib->szName, BADLIBRARY, NULL);
  1278. }
  1279. parcMemHdr = ReadArchiveMemberHeader();
  1280. if (cblib < (MemberSeekBase + MemberSize)) {
  1281. Fatal(plib->szName, BADLIBRARY, NULL);
  1282. }
  1283. if (!(szName = ExpandMemberName(plib, (char *) parcMemHdr->Name))) {
  1284. Fatal(plib->szName, BADLIBRARY, NULL);
  1285. }
  1286. ReadFileHeader(FileReadHandle, &ImObjFileHdr);
  1287. pmod = PmodNew(NULL,
  1288. szName,
  1289. MemberSeekBase,
  1290. ImObjFileHdr.PointerToSymbolTable,
  1291. ImObjFileHdr.NumberOfSymbols,
  1292. ImObjFileHdr.SizeOfOptionalHeader,
  1293. ImObjFileHdr.Characteristics,
  1294. ImObjFileHdr.NumberOfSections,
  1295. plib,
  1296. NULL);
  1297. // add it to list of new mods
  1298. if (fIncrDbFile) {
  1299. AddToPLMODList(&plmodNewModsFromLibSrch, pmod);
  1300. }
  1301. if (Verbose) {
  1302. char szBuf[_MAX_PATH * 2];
  1303. fputs(" ", stdout);
  1304. Message(LOADOBJ, SzComNamePMOD(pmod, szBuf));
  1305. }
  1306. if (pimage->Switch.Link.fTCE) {
  1307. // Allocate memory for TCE data structures
  1308. InitNodPmod(pmod);
  1309. }
  1310. fNewSymbol = FALSE;
  1311. BuildExternalSymbolTable(pimage,
  1312. &fNewSymbol,
  1313. pmod,
  1314. (WORD) (ARCHIVE + iszIntMem),
  1315. ImObjFileHdr.Machine);
  1316. FileClose(FileReadHandle, FALSE);
  1317. if (fIncrDbFile && errInc != errNone) {
  1318. return;
  1319. }
  1320. // if new externs were added re-start symbol search
  1321. if (fNewSymbol) {
  1322. *pfNewSymbol = TRUE;
  1323. }
  1324. if ((pextPrev == NULL) || (pextPrev->Flags & EXTERN_DEFINED)
  1325. // if it is previously weak extern and is not anymore
  1326. // when processing ProcessSymbolsInModule
  1327. || fWeakToRegular) {
  1328. enmUndefExt.pextNext = pimage->pst->pextFirstUndefined;
  1329. fWeakToRegular = FALSE;
  1330. } else {
  1331. enmUndefExt.pextNext = pextPrev->pextNextUndefined;
  1332. }
  1333. }
  1334. }
  1335. #if DBG
  1336. void
  1337. DumpExternals(
  1338. PST pst,
  1339. BOOL fDefined
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. Writes to standard out all external symbols
  1344. (used for debugging)
  1345. Arguments:
  1346. pst - pointer to external structure
  1347. Return Value:
  1348. None.
  1349. --*/
  1350. {
  1351. PPEXTERNAL rgpexternal;
  1352. DWORD cexternal;
  1353. DWORD i;
  1354. rgpexternal = RgpexternalByName(pst);
  1355. cexternal = Cexternal(pst);
  1356. for (i = 0; i < cexternal; i++) {
  1357. PEXTERNAL pexternal;
  1358. BOOL fExternDefined;
  1359. pexternal = rgpexternal[i];
  1360. if (pexternal->Flags & EXTERN_IGNORE) {
  1361. continue;
  1362. }
  1363. if (pexternal->Flags & EXTERN_FORWARDER) {
  1364. continue;
  1365. }
  1366. fExternDefined = (pexternal->Flags & EXTERN_DEFINED) != 0;
  1367. if (fExternDefined != fDefined) {
  1368. continue;
  1369. }
  1370. printf("%8lX %s\n", pexternal->ImageSymbol.Value,
  1371. SzNamePext(pexternal, pst));
  1372. }
  1373. }
  1374. void
  1375. DumpExternTable(
  1376. PST pst
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Writes to standard out all external symbols
  1381. (used for debugging)
  1382. Arguments:
  1383. pst - pointer to external structure
  1384. Return Value:
  1385. None.
  1386. --*/
  1387. {
  1388. printf("Defined Externals\n");
  1389. DumpExternals(pst, TRUE);
  1390. printf("Undefined Externals\n");
  1391. DumpExternals(pst, FALSE);
  1392. }
  1393. #endif // DBG
  1394. void
  1395. CountRelocsInSection(
  1396. PIMAGE pimage,
  1397. PCON pcon,
  1398. PIMAGE_SYMBOL rgsym,
  1399. PMOD pmod,
  1400. WORD wMachine
  1401. )
  1402. /*++
  1403. Routine Description:
  1404. Count the number of base relocations in a section and put the result
  1405. in the optional header. This routine uses the global ImageOptionalHdr.
  1406. Arguments:
  1407. pcon - contribution
  1408. Return Value:
  1409. None.
  1410. --*/
  1411. {
  1412. DWORD creloc;
  1413. PIMAGE_RELOCATION rgrel;
  1414. PIMAGE_RELOCATION prel;
  1415. DWORD crel;
  1416. PIMAGE_RELOCATION prelNext;
  1417. PCON rgcon;
  1418. SHORT icon;
  1419. if (!FHasRelocSrcPCON(pcon)) {
  1420. return;
  1421. }
  1422. if (wMachine == IMAGE_FILE_MACHINE_UNKNOWN) {
  1423. FatalPcon(pcon, BADCOFF_NOMACHINE);
  1424. }
  1425. prel = rgrel = ReadRgrelPCON(pcon, &creloc);
  1426. // Accumulate count of relocations for size of pconFixupDebug
  1427. crelocTotal += creloc;
  1428. rgcon = RgconPMOD(pmod);
  1429. icon = (SHORT) (pcon - rgcon + 1);
  1430. // Count how many base relocations the image will have.
  1431. crel = 0;
  1432. switch (pimage->ImgFileHdr.Machine) {
  1433. case IMAGE_FILE_MACHINE_I386 :
  1434. for (prelNext = prel; creloc; prelNext++, creloc--) {
  1435. if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
  1436. IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
  1437. FatalPcon(pcon,
  1438. BADCOFF_BADRELOC,
  1439. SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
  1440. }
  1441. if (pimage->Switch.Link.fTCE) {
  1442. ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
  1443. }
  1444. if (pimage->imaget == imagetVXD) {
  1445. // For VXD's we count every fixup because inter-section
  1446. // relative fixups require a runtime reloc.
  1447. crel++;
  1448. continue;
  1449. }
  1450. if (pimage->Switch.Link.fFixed) {
  1451. continue;
  1452. }
  1453. switch (prelNext->Type) {
  1454. case IMAGE_REL_I386_DIR32 :
  1455. crel++;
  1456. break;
  1457. case IMAGE_REL_I386_REL32 :
  1458. if (pimage->Switch.Link.fNewRelocs) {
  1459. if (icon != rgsym[prel->SymbolTableIndex].SectionNumber) {
  1460. crel++;
  1461. }
  1462. }
  1463. break;
  1464. }
  1465. }
  1466. break;
  1467. case IMAGE_FILE_MACHINE_R3000 :
  1468. case IMAGE_FILE_MACHINE_R4000 :
  1469. case IMAGE_FILE_MACHINE_R10000 :
  1470. for (prelNext = prel; creloc; prelNext++, creloc--) {
  1471. if (prelNext->Type == IMAGE_REL_MIPS_PAIR) {
  1472. continue;
  1473. }
  1474. if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
  1475. IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
  1476. FatalPcon(pcon,
  1477. BADCOFF_BADRELOC,
  1478. SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
  1479. }
  1480. if (pimage->Switch.Link.fTCE) {
  1481. ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
  1482. }
  1483. if (pimage->Switch.Link.fFixed) {
  1484. continue;
  1485. }
  1486. switch (prelNext->Type) {
  1487. case IMAGE_REL_MIPS_REFHALF:
  1488. case IMAGE_REL_MIPS_REFWORD:
  1489. case IMAGE_REL_MIPS_JMPADDR:
  1490. crel++;
  1491. break;
  1492. case IMAGE_REL_MIPS_REFHI:
  1493. // The next relocation record must be a pair
  1494. assert((prelNext+1)->Type == IMAGE_REL_MIPS_PAIR);
  1495. crel += 2;
  1496. break;
  1497. case IMAGE_REL_MIPS_REFLO:
  1498. crel++;
  1499. break;
  1500. }
  1501. }
  1502. break;
  1503. case IMAGE_FILE_MACHINE_ALPHA :
  1504. for (prelNext = prel; creloc; prelNext++, creloc--) {
  1505. if ((prelNext->Type == IMAGE_REL_ALPHA_HINT) ||
  1506. (prelNext->Type == IMAGE_REL_ALPHA_PAIR) ||
  1507. (prelNext->Type == IMAGE_REL_ALPHA_MATCH)) {
  1508. continue;
  1509. }
  1510. if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
  1511. IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
  1512. FatalPcon(pcon,
  1513. BADCOFF_BADRELOC,
  1514. SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
  1515. }
  1516. if (pimage->Switch.Link.fTCE) {
  1517. ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
  1518. }
  1519. if (pimage->Switch.Link.fFixed) {
  1520. continue;
  1521. }
  1522. switch (prelNext->Type) {
  1523. case IMAGE_REL_ALPHA_REFLONG :
  1524. case IMAGE_REL_ALPHA_REFQUAD :
  1525. case IMAGE_REL_ALPHA_REFLO :
  1526. crel++;
  1527. break;
  1528. case IMAGE_REL_ALPHA_BRADDR :
  1529. if (icon != rgsym[prel->SymbolTableIndex].SectionNumber) {
  1530. // If this BSR is outside our CON, account for
  1531. // possible out of range handling.
  1532. pcon->AlphaBsrCount++;
  1533. // UNDONE: This is very conservative
  1534. crel += 3;
  1535. }
  1536. break;
  1537. case IMAGE_REL_ALPHA_INLINE_REFLONG :
  1538. crel += 3;
  1539. break;
  1540. case IMAGE_REL_ALPHA_REFHI :
  1541. // The next relocation record must be a pair
  1542. assert((prelNext+1)->Type == IMAGE_REL_ALPHA_PAIR);
  1543. crel += 2;
  1544. break;
  1545. }
  1546. }
  1547. break;
  1548. case IMAGE_FILE_MACHINE_POWERPC :
  1549. for (prelNext = prel; creloc; prelNext++, creloc--) {
  1550. if ((prelNext->Type & IMAGE_REL_PPC_TYPEMASK) == IMAGE_REL_PPC_PAIR) {
  1551. continue;
  1552. }
  1553. if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
  1554. IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
  1555. FatalPcon(pcon,
  1556. BADCOFF_BADRELOC,
  1557. SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
  1558. }
  1559. if (prelNext->Type == IMAGE_REL_PPC_IMGLUE) {
  1560. DWORD isym;
  1561. isym = prelNext->SymbolTableIndex;
  1562. if ((mpisymbToc[isym] & fImGlue) != 0) {
  1563. const char *szName;
  1564. szName = SzNameSymPb(rgsym[isym], StringTable);
  1565. ErrorPcon(pcon, DUPLICATEGLUE, szName);
  1566. }
  1567. mpisymbToc[isym] |= fImGlue;
  1568. mpisymdwRestoreToc[isym] = prelNext->VirtualAddress;
  1569. continue;
  1570. }
  1571. if (pimage->Switch.Link.fTCE) {
  1572. ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
  1573. }
  1574. if (prelNext->Type & IMAGE_REL_PPC_TOCDEFN) {
  1575. mpisymbToc[prelNext->SymbolTableIndex] |= fDataMarkToc;
  1576. }
  1577. switch (prelNext->Type & IMAGE_REL_PPC_TYPEMASK) {
  1578. case IMAGE_REL_PPC_ADDR64 :
  1579. case IMAGE_REL_PPC_ADDR32 :
  1580. case IMAGE_REL_PPC_ADDR16 :
  1581. case IMAGE_REL_PPC_REFLO :
  1582. if (!pimage->Switch.Link.fFixed) {
  1583. crel++;
  1584. }
  1585. break;
  1586. case IMAGE_REL_PPC_TOCREL16 :
  1587. case IMAGE_REL_PPC_TOCREL14 :
  1588. if (prelNext->Type & IMAGE_REL_PPC_TOCDEFN) {
  1589. mpisymbToc[prelNext->SymbolTableIndex] |= fDataReferenceToc;
  1590. } else {
  1591. mpisymbToc[prelNext->SymbolTableIndex] |= fReferenceToc;
  1592. }
  1593. break;
  1594. case IMAGE_REL_PPC_IFGLUE :
  1595. pmod->fIfGlue = TRUE;
  1596. break;
  1597. case IMAGE_REL_PPC_REFHI :
  1598. if (!pimage->Switch.Link.fFixed) {
  1599. crel += 2;
  1600. }
  1601. break;
  1602. }
  1603. }
  1604. break;
  1605. case IMAGE_FILE_MACHINE_M68K :
  1606. {
  1607. BOOL fSACode =
  1608. ((PsecPCON(pcon)->flags & IMAGE_SCN_CNT_CODE) &&
  1609. !(PsecPCON(pcon)->ResTypeMac == sbeCODE ||
  1610. fDLL(pimage) || PsecPCON(pcon)->ResTypeMac == sbeDLLcode));
  1611. for (prelNext = prel; creloc; prelNext++, creloc--) {
  1612. if (fSACode) {
  1613. CheckForIllegalA5Ref(prelNext->Type);
  1614. }
  1615. if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
  1616. IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
  1617. FatalPcon(pcon,
  1618. BADCOFF_BADRELOC,
  1619. SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
  1620. }
  1621. if (pimage->Switch.Link.fTCE) {
  1622. ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
  1623. }
  1624. switch (prelNext->Type) {
  1625. case IMAGE_REL_M68K_DTOU32:
  1626. case IMAGE_REL_M68K_DTOC32:
  1627. if (!fSACode) {
  1628. ProcessSTRef(prelNext->SymbolTableIndex,
  1629. PsecPCON(pcon), EXTERN_ADDTHUNK);
  1630. }
  1631. break;
  1632. case IMAGE_REL_M68K_DTOABSD32:
  1633. AddRelocInfo(&DFIXRaw, pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
  1634. break;
  1635. case IMAGE_REL_M68K_DTOABSU32:
  1636. case IMAGE_REL_M68K_DTOABSC32:
  1637. AddRelocInfo(&DFIXRaw, pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
  1638. if (!fSACode) {
  1639. ProcessSTRef(prelNext->SymbolTableIndex,
  1640. PsecPCON(pcon), EXTERN_ADDTHUNK);
  1641. }
  1642. break;
  1643. // CTOU16 is always an A5 offset, so mark this
  1644. // symbol as needing a thunk. If the symbol turns
  1645. // out to be a data symbol it will be ignored in
  1646. // the middle pass when the thunk table is made.
  1647. case IMAGE_REL_M68K_CTOU16:
  1648. case IMAGE_REL_M68K_DTOU16:
  1649. case IMAGE_REL_M68K_DTOC16:
  1650. case IMAGE_REL_M68K_CTOT16:
  1651. if (!fSACode) {
  1652. ProcessSTRef(prelNext->SymbolTableIndex,
  1653. PsecPCON(pcon), EXTERN_ADDTHUNK | EXTERN_REF16);
  1654. }
  1655. break;
  1656. case IMAGE_REL_M68K_PCODETOT24:
  1657. if (!fSACode) {
  1658. ProcessSTRef(prelNext->SymbolTableIndex,
  1659. PsecPCON(pcon), EXTERN_ADDTHUNK);
  1660. }
  1661. break;
  1662. case IMAGE_REL_M68K_CTOC16:
  1663. if (!fSACode) {
  1664. ProcessSTRef(prelNext->SymbolTableIndex,
  1665. PsecPCON(pcon), EXTERN_REF16);
  1666. }
  1667. break;
  1668. case IMAGE_REL_M68K_CTOABST32:
  1669. if (!fSACode) {
  1670. ProcessSTRef(prelNext->SymbolTableIndex,
  1671. PsecPCON(pcon), EXTERN_ADDTHUNK);
  1672. }
  1673. AddRelocInfo(&mpsna5ri[PsecPCON(pcon)->isecTMAC],
  1674. pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
  1675. break;
  1676. // REVIEW - make seg-rel (not unknown)
  1677. case IMAGE_REL_M68K_CTOABSCS32:
  1678. AddRawUnknownRelocInfo(pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon), prelNext->SymbolTableIndex);
  1679. break;
  1680. case IMAGE_REL_M68K_PCODETONATIVE32:
  1681. case IMAGE_REL_M68K_PCODETOC32:
  1682. if (!fSACode) {
  1683. ProcessSTRef(prelNext->SymbolTableIndex,
  1684. PsecPCON(pcon), 0);
  1685. }
  1686. break;
  1687. case IMAGE_REL_M68K_CTOABSU32:
  1688. case IMAGE_REL_M68K_CTOABSC32:
  1689. if (!fSACode) {
  1690. ProcessSTRef(prelNext->SymbolTableIndex,
  1691. PsecPCON(pcon), 0);
  1692. }
  1693. AddRawUnknownRelocInfo(pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon), prelNext->SymbolTableIndex);
  1694. break;
  1695. case IMAGE_REL_M68K_CTOABSD32:
  1696. AddRelocInfo(&mpsna5ri[PsecPCON(pcon)->isecTMAC],
  1697. pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
  1698. break;
  1699. case IMAGE_REL_M68K_CSECTABLEB16:
  1700. assert(!fSACode);
  1701. ProcessSTRef(prelNext->SymbolTableIndex,
  1702. PsecPCON(pcon), EXTERN_REF16 | EXTERN_CSECTABLEB);
  1703. break;
  1704. case IMAGE_REL_M68K_CSECTABLEW16:
  1705. assert(!fSACode);
  1706. ProcessSTRef(prelNext->SymbolTableIndex,
  1707. PsecPCON(pcon), EXTERN_REF16 | EXTERN_CSECTABLEW);
  1708. break;
  1709. case IMAGE_REL_M68K_CSECTABLEL16:
  1710. assert(!fSACode);
  1711. ProcessSTRef(prelNext->SymbolTableIndex,
  1712. PsecPCON(pcon), EXTERN_REF16 | EXTERN_CSECTABLEL);
  1713. break;
  1714. case IMAGE_REL_M68K_CSECTABLEBABS32:
  1715. assert(!fSACode);
  1716. ProcessSTRef(prelNext->SymbolTableIndex,
  1717. PsecPCON(pcon), EXTERN_CSECTABLEB);
  1718. break;
  1719. case IMAGE_REL_M68K_CSECTABLEWABS32:
  1720. assert(!fSACode);
  1721. ProcessSTRef(prelNext->SymbolTableIndex,
  1722. PsecPCON(pcon), EXTERN_CSECTABLEW);
  1723. break;
  1724. case IMAGE_REL_M68K_CSECTABLELABS32:
  1725. assert(!fSACode);
  1726. ProcessSTRef(prelNext->SymbolTableIndex,
  1727. PsecPCON(pcon), EXTERN_CSECTABLEL);
  1728. break;
  1729. case IMAGE_REL_M68K_DUPCON16:
  1730. ProcessSTRef(prelNext->SymbolTableIndex,
  1731. PsecPCON(pcon), EXTERN_DUPCON);
  1732. break;
  1733. case IMAGE_REL_M68K_DUPCONABS32:
  1734. AddRelocInfo(&mpsnsri[PsecPCON(pcon)->isecTMAC],
  1735. pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
  1736. ProcessSTRef(prelNext->SymbolTableIndex,
  1737. PsecPCON(pcon), EXTERN_DUPCON);
  1738. break;
  1739. }
  1740. }
  1741. break;
  1742. }
  1743. case IMAGE_FILE_MACHINE_MPPC_601 :
  1744. for (prelNext = prel; creloc > 0; prelNext++, creloc--) {
  1745. DWORD isym;
  1746. PEXTERNAL pext;
  1747. const char *szName;
  1748. BOOL fFromCreateDescrRel = FALSE;
  1749. BOOL fFromDataDescRel = FALSE;
  1750. if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
  1751. IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
  1752. FatalPcon(pcon,
  1753. BADCOFF_BADRELOC,
  1754. SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
  1755. }
  1756. if (pimage->Switch.Link.fTCE) {
  1757. ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
  1758. }
  1759. switch (prelNext->Type & 0xFF) {
  1760. case IMAGE_REL_MPPC_DATAREL :
  1761. mppc_numRelocations++;
  1762. break;
  1763. case IMAGE_REL_MPPC_DATADESCRREL :
  1764. mppc_numRelocations++;
  1765. fFromDataDescRel = TRUE;
  1766. // DataDescrRel falls through to CreateDescrRel but no further
  1767. case IMAGE_REL_MPPC_CREATEDESCRREL :
  1768. isym = prelNext->SymbolTableIndex;
  1769. pext = pmod->rgpext[isym];
  1770. if (pext != NULL) {
  1771. if (!READ_BIT(pext, sy_DESCRRELCREATED)) {
  1772. szName = SzNamePext(pext, pimage->pst);
  1773. CreateDescriptor(szName, pcon, pimage, FALSE);
  1774. SET_BIT(pext, sy_DESCRRELCREATED);
  1775. }
  1776. if (fIncrDbFile) {
  1777. // if it is subsequent iLink, then reset this bit
  1778. // so that FixUpDescriptor will update descriptor
  1779. // if the contribution had moved.
  1780. RESET_BIT(pext, sy_DESCRRELWRITTEN);
  1781. if (fFromDataDescRel) {
  1782. MppcFixIncrDotExternFlags(pext, pimage);
  1783. }
  1784. }
  1785. } else {
  1786. // Must be a static
  1787. szName = SzNameSymPb(rgsym[isym], StringTable);
  1788. pext = CreateDescriptor(szName, pcon, pimage, TRUE);
  1789. pmod->rgpext[isym] = pext;
  1790. SET_BIT(pext, sy_ISDOTEXTERN);
  1791. bv_setAndReadBit(pmod->tocBitVector, isym);
  1792. if (fIncrDbFile) {
  1793. // if it is subsequent iLink, then reset this bit
  1794. // so that FixUpDescriptor will update descriptor
  1795. // if the contribution had moved.
  1796. RESET_BIT(pext, sy_DESCRRELWRITTEN);
  1797. }
  1798. }
  1799. if (fFromDataDescRel) {
  1800. break;
  1801. }
  1802. // Fall through into TOCREL ... see the comment
  1803. // in mppc.c when the relocs are actually applied.
  1804. assert(creloc >= 1 && ((prelNext + 1)->Type & 0xFF) == IMAGE_REL_MPPC_TOCREL);
  1805. fFromCreateDescrRel = TRUE;
  1806. // Fall through
  1807. case IMAGE_REL_MPPC_TOCREL :
  1808. isym = prelNext->SymbolTableIndex;
  1809. if (bv_readBit(pmod->tocBitVector, isym)) {
  1810. pext = pmod->rgpext[isym];
  1811. assert(pext != NULL);
  1812. if (!READ_BIT(pext, sy_TOCALLOCATED)) {
  1813. pext->ibToc = (SHORT) (mppc_numTocEntries * sizeof(DWORD) - MPPC_TOC_BIAS);
  1814. mppc_numTocEntries++;
  1815. mppc_numRelocations++;
  1816. SET_BIT(pext, sy_TOCALLOCATED);
  1817. if (pimage->Switch.Link.fMap) {
  1818. SaveTocForMapFile(pext);
  1819. }
  1820. }
  1821. } else if (!bv_setAndReadBit(pmod->writeBitVector, isym)) {
  1822. pmod->rgpext[isym] = (PEXTERNAL) mppc_numTocEntries;
  1823. mppc_numTocEntries++;
  1824. mppc_numRelocations++;
  1825. }
  1826. if (fFromCreateDescrRel) {
  1827. // Eat the next reloc so we don't double-count.
  1828. prelNext++;
  1829. creloc--;
  1830. }
  1831. break;
  1832. }
  1833. }
  1834. break;
  1835. }
  1836. // Done processing sections relocations entries.
  1837. FreeRgrel(rgrel);
  1838. if (crel != 0) {
  1839. pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size += crel;
  1840. pmod->cReloc += crel;
  1841. DBEXEC(DB_SCAN_RELOCS, DBPRINT("SCAN_RELOCS: pcon=%p, %5d, %s\n",
  1842. pcon, crel, SzPCON(pcon)));
  1843. }
  1844. }
  1845. void
  1846. DiscardDebugSectionPCON(
  1847. PCON pcon,
  1848. SWITCH *pswitch
  1849. )
  1850. /*++
  1851. Routine Description:
  1852. Discard debug sections.
  1853. Arguments:
  1854. pcon - debug section contribution node in image\driver map
  1855. Return Value:
  1856. None.
  1857. --*/
  1858. {
  1859. if ((pswitch->Link.DebugInfo != Full) || !(pswitch->Link.DebugType & CvDebug)) {
  1860. if ((pcon->pgrpBack == pgrpCvSymbols) ||
  1861. (pcon->pgrpBack == pgrpCvTypes) ||
  1862. (pcon->pgrpBack == pgrpCvPTypes)) {
  1863. pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  1864. }
  1865. }
  1866. if (pswitch->Link.DebugInfo == None || !(pswitch->Link.DebugType & FpoDebug)) {
  1867. if (pcon->pgrpBack == pgrpFpoData) {
  1868. pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  1869. }
  1870. }
  1871. }
  1872. void
  1873. ProcessWeakExtern(
  1874. PST pst,
  1875. PIMAGE_SYMBOL *ppsymNext,
  1876. PIMAGE_SYMBOL psymObj,
  1877. PEXTERNAL pext,
  1878. PMOD pmod,
  1879. PBOOL pfNewSymbol,
  1880. BOOL fNewSymbol,
  1881. WORD iArcMem
  1882. )
  1883. /*++
  1884. Routine Description:
  1885. Do necessary processing for a weak external.
  1886. Arguments:
  1887. psechdr - section header
  1888. Return Value:
  1889. None.
  1890. --*/
  1891. {
  1892. char szComFileName[_MAX_PATH * 2];
  1893. PIMAGE_AUX_SYMBOL pasym;
  1894. IMAGE_SYMBOL symDef;
  1895. DWORD foDefSym;
  1896. DWORD foCur;
  1897. PEXTERNAL pextWeakDefault;
  1898. if (psymObj->NumberOfAuxSymbols != 1) {
  1899. char *szOutput = SzOutputSymbolName(SzNamePext(pext, pst), TRUE);
  1900. SzComNamePMOD(pmod, szComFileName);
  1901. Fatal(szComFileName, BADWEAKEXTERN, szOutput);
  1902. }
  1903. pasym = (PIMAGE_AUX_SYMBOL) FetchNextSymbol(ppsymNext);
  1904. // save current file offset
  1905. foCur = FileTell(FileReadHandle);
  1906. // get weak extern symbol
  1907. foDefSym = FoSymbolTablePMOD(pmod) +
  1908. (pasym->Sym.TagIndex * sizeof(IMAGE_SYMBOL));
  1909. FileSeek(FileReadHandle, foDefSym, SEEK_SET);
  1910. ReadSymbolTableEntry(FileReadHandle, &symDef);
  1911. // Ignore weak and lazy externs if we've already seen the symbol (i.e.
  1912. // got a strong reference). However, we still look at alias records
  1913. // which can override a strong reference.
  1914. if (fNewSymbol ||
  1915. !(pext->Flags & EXTERN_DEFINED) && pasym->Sym.Misc.TotalSize == 3)
  1916. {
  1917. cextWeakOrLazy++;
  1918. pext->ImageSymbol.StorageClass = IMAGE_SYM_CLASS_WEAK_EXTERNAL;
  1919. if (IsLongName(symDef)) {
  1920. pextWeakDefault =
  1921. LookupExternName(pst, LONGNAME, &StringTable[symDef.n_offset],
  1922. pfNewSymbol);
  1923. } else {
  1924. pextWeakDefault =
  1925. LookupExternName(pst, SHORTNAME, (char *) symDef.n_name, pfNewSymbol);
  1926. }
  1927. AddWeakExtToList(pext, pextWeakDefault);
  1928. // Remember archive member index. This is just for LIB which needs
  1929. // to put weak externs in the lib's directory.
  1930. pext->ArchiveMemberIndex = iArcMem;
  1931. switch (pasym->Sym.Misc.TotalSize) {
  1932. case 1: pext->Flags |= EXTERN_WEAK; break;
  1933. case 2: pext->Flags |= EXTERN_LAZY; break;
  1934. case 3: pext->Flags |= EXTERN_ALIAS; break;
  1935. }
  1936. // in the incremental case mark it as a new func if applicable
  1937. if (fIncrDbFile && fNewSymbol && ISFCN(psymObj->Type)) {
  1938. pext->Flags |= EXTERN_NEWFUNC;
  1939. }
  1940. } else {
  1941. // If the symbol exists or has already been referenced, ignore weak
  1942. // extern
  1943. if (fIncrDbFile) {
  1944. // on an ilink the syms are not new;
  1945. if (IsLongName(symDef)) {
  1946. pextWeakDefault =
  1947. LookupExternName(pst, LONGNAME, &StringTable[symDef.n_offset],
  1948. pfNewSymbol);
  1949. } else {
  1950. pextWeakDefault =
  1951. LookupExternName(pst, SHORTNAME, (char *) symDef.n_name, pfNewSymbol);
  1952. }
  1953. AddWeakExtToList(pext, pextWeakDefault);
  1954. // in the incr case mark the sym as being weak/lazy/alias
  1955. // since it is not going to be a new symbol.
  1956. switch (pasym->Sym.Misc.TotalSize) {
  1957. case 1: pext->Flags |= EXTERN_WEAK; break;
  1958. case 2: pext->Flags |= EXTERN_LAZY; break;
  1959. case 3: pext->Flags |= EXTERN_ALIAS; break;
  1960. }
  1961. }
  1962. }
  1963. // reset file offset to where we were before
  1964. FileSeek(FileReadHandle, foCur, SEEK_SET);
  1965. }
  1966. void
  1967. ProcessSectionFlags(
  1968. DWORD *pflags,
  1969. const char *szName,
  1970. PIMAGE_OPTIONAL_HEADER pImgOptHdr
  1971. )
  1972. /*++
  1973. Routine Description:
  1974. Process a COFF sections flags.
  1975. Arguments:
  1976. *pflags - a COFF section flags
  1977. szName - name of section
  1978. Return Value:
  1979. None.
  1980. --*/
  1981. {
  1982. DWORD flags;
  1983. flags = *pflags & ~(IMAGE_SCN_TYPE_NO_PAD | // ignore padding
  1984. IMAGE_SCN_LNK_COMDAT | // ignore comdat bit
  1985. IMAGE_SCN_LNK_NRELOC_OVFL | // ignore overflow bit
  1986. 0x00f00000); // ignore alignment bits
  1987. // Force the DISCARDABLE flag if the section name starts with .debug.
  1988. if (strcmp(szName, ".debug") == 0) {
  1989. flags |= IMAGE_SCN_MEM_DISCARDABLE;
  1990. }
  1991. if (fImageMappedAsFile && (flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
  1992. // Place the bss on the disk for packed images.
  1993. flags &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
  1994. flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
  1995. }
  1996. // Mark resource data on native images (device drivers) as discardable.
  1997. if ((pImgOptHdr->Subsystem == IMAGE_SUBSYSTEM_NATIVE) &&
  1998. (!strcmp(szName, ReservedSection.Resource.Name))) {
  1999. flags |= IMAGE_SCN_MEM_DISCARDABLE;
  2000. }
  2001. // If unknown contents, mark INITIALIZED DATA
  2002. if (!(flags & (IMAGE_SCN_LNK_OTHER |
  2003. IMAGE_SCN_CNT_CODE |
  2004. IMAGE_SCN_CNT_INITIALIZED_DATA |
  2005. IMAGE_SCN_CNT_UNINITIALIZED_DATA))) {
  2006. flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
  2007. }
  2008. // set anything not marked with a memory protection attribute
  2009. // - code will be marked EXECUTE READ,
  2010. // - everything else will be marked READ WRITE
  2011. if (!(flags & (IMAGE_SCN_MEM_WRITE |
  2012. IMAGE_SCN_MEM_READ |
  2013. IMAGE_SCN_MEM_EXECUTE))) {
  2014. if (flags & IMAGE_SCN_CNT_CODE) {
  2015. flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
  2016. } else {
  2017. flags |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
  2018. }
  2019. }
  2020. *pflags = flags;
  2021. }
  2022. void
  2023. ProcessSectionInModule (
  2024. PIMAGE pimage,
  2025. PMOD pmod,
  2026. SHORT isec,
  2027. IMAGE_SECTION_HEADER *pImgSecHdr,
  2028. PIMAGE_SYMBOL rgsymAll,
  2029. WORD wMachine,
  2030. PNAME_LIST pnlDirectives
  2031. )
  2032. /*++
  2033. Routine Description:
  2034. Process all the sections in a module.
  2035. Arguments:
  2036. pst - pointer to external structure
  2037. pmod - module node in driver/image map that pcon
  2038. fIncReloc - !0 if we are to include relocatins, 0 otherwise
  2039. isec - section number of contribution to process
  2040. pImgSecHdr - ptr to section header of contribution
  2041. rgsymAll - COFF symbol table for module
  2042. wMachine - machine type of object file.
  2043. pnlDirectives - list to keep directives in.
  2044. Return Value:
  2045. None.
  2046. --*/
  2047. {
  2048. const char *szName;
  2049. DWORD dwCharacteristics;
  2050. PCON pcon;
  2051. const char *szComdatName = NULL;
  2052. DWORD cbAlign;
  2053. szName = SzObjSectionName((char *) pImgSecHdr->Name, StringTable);
  2054. // Force all sections on MIPS to at least ALIGN4 (old compilers didn't
  2055. // specify an alignment making merging/incremental impossible)
  2056. if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R4000) ||
  2057. (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R10000)) {
  2058. if ((!(pImgSecHdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)) &&
  2059. (strncmp(szName, ".idata", 6) != 0) &&
  2060. (FetchContent(pImgSecHdr->Characteristics) != IMAGE_SCN_LNK_OTHER)
  2061. )
  2062. {
  2063. cbAlign = RvaAlign(1, pImgSecHdr->Characteristics);
  2064. if (cbAlign < 4) {
  2065. char szModule[_MAX_PATH*2];
  2066. SzComNamePMOD(pmod, szModule);
  2067. DBEXEC(DB_INCRCALCPTRS,
  2068. printf("Fixing legacy module with no alignment: %s %s\n", szModule, szName));
  2069. // UNDONE: Len - Why whack the NO_PAD attribute when building
  2070. // incremental?
  2071. // If you don't whack the NO_PAD then you'll get ilink padding
  2072. // that is not 0 modulo alignment and that could leave one
  2073. // xdata section unaligned following a padded section.
  2074. // see RvaAlign.
  2075. if (fINCR && !fIncrDbFile) {
  2076. pImgSecHdr->Characteristics &= 0xFF8FFFF7;
  2077. } else {
  2078. pImgSecHdr->Characteristics &= 0xFF8FFFFF;
  2079. }
  2080. pImgSecHdr->Characteristics |= IMAGE_SCN_ALIGN_4BYTES;
  2081. }
  2082. }
  2083. }
  2084. dwCharacteristics = pImgSecHdr->Characteristics;
  2085. if (fPowerMac) {
  2086. if (strcmp(szName, ".ppcshl") == 0) {
  2087. MppcSetExpFilename(SzOrigFilePMOD(pmod));
  2088. }
  2089. }
  2090. // Allocate a contribution:
  2091. pcon = PconNew(szName,
  2092. pImgSecHdr->SizeOfRawData,
  2093. dwCharacteristics,
  2094. dwCharacteristics,
  2095. pmod,
  2096. &pimage->secs,
  2097. pimage);
  2098. DiscardDebugSectionPCON(pcon, &pimage->Switch);
  2099. if (fPdb && (pcon->pgrpBack == pgrpCvPTypes)) {
  2100. AddToPLMODList(&PCTMods, pmod);
  2101. }
  2102. if (pcon->flags & IMAGE_SCN_LNK_COMDAT) {
  2103. if (!FIncludeComdat(pimage, pcon, rgsymAll, isec, &szComdatName)) {
  2104. // Don't include this comdat.
  2105. pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  2106. return;
  2107. }
  2108. }
  2109. if ((pcon->flags & IMAGE_SCN_LNK_INFO) && !pimage->fIgnoreDirectives) {
  2110. if (!strcmp(szName, ReservedSection.Directive.Name)) {
  2111. char *pchDirectives;
  2112. DWORD ich;
  2113. pchDirectives = (char *) PvAlloc((size_t) pcon->cbRawData + 1);
  2114. FileSeek(FileReadHandle, FoRawDataSrcPCON(pcon), SEEK_SET);
  2115. FileRead(FileReadHandle, pchDirectives, pcon->cbRawData);
  2116. // Convert embedded '\0's to spaces
  2117. for (ich = 0; ich < pcon->cbRawData; ich++) {
  2118. if (pchDirectives[ich] == '\0') {
  2119. pchDirectives[ich] = ' ';
  2120. }
  2121. }
  2122. // Now null terminate the string
  2123. pchDirectives[pcon->cbRawData] = '\0';
  2124. if (fIncrDbFile) {
  2125. BuildArgList(pimage, pcon, pnlDirectives, pchDirectives);
  2126. } else {
  2127. ApplyDirectives(pimage, pcon, pchDirectives);
  2128. }
  2129. FreePv(pchDirectives);
  2130. }
  2131. }
  2132. if (Tool == Librarian) {
  2133. return;
  2134. }
  2135. if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
  2136. return;
  2137. }
  2138. // Make sure the group is aligned in such a way that this CON gets
  2139. // aligned correctly.
  2140. cbAlign = RvaAlign(1, dwCharacteristics);
  2141. if (pcon->pgrpBack->cbAlign < (BYTE) cbAlign) {
  2142. pcon->pgrpBack->cbAlign = (BYTE) cbAlign;
  2143. if (!fM68K && !fPowerMac) {
  2144. if (pimage->ImgOptHdr.SectionAlignment < cbAlign) {
  2145. FatalPcon(pcon, CONALIGNTOOLARGE, isec, cbAlign);
  2146. }
  2147. }
  2148. if (fM68K && (pimage->ImgOptHdr.SectionAlignment < cbAlign)) {
  2149. pimage->ImgOptHdr.SectionAlignment = cbAlign;
  2150. }
  2151. }
  2152. if (pimage->Switch.Link.fTCE) {
  2153. InitNodPcon(pcon, szComdatName, FALSE);
  2154. if ((pcon->flags & IMAGE_SCN_LNK_COMDAT) == 0) {
  2155. // Enforce the policy that non-comdat sections (and anything they
  2156. // refer to) are not eliminated. We could eventually eliminate
  2157. // some of these but first we have to worry about .CRT initialization,
  2158. // .idata, etc.
  2159. PentNew_TCE(NULL, NULL, pcon, &pentHeadImage);
  2160. } else if (pcon->pconAssoc != NULL) {
  2161. PedgNew_TCE(0, pcon->pconAssoc, pcon);
  2162. }
  2163. }
  2164. // No padding yet at end of CON. If the next CON wants padding then we
  2165. // may add some later.
  2166. // Incr pad currently disabled for
  2167. // idata cons since it will mess up those NULL THUNKs.
  2168. // do pdata padding elsewhere LFL
  2169. // For PowerMac, .pdata exists as a section now and not yet been merged into .data as a grp
  2170. if (fINCR && !fIncrDbFile &&
  2171. (PsecPCON(pcon) != psecDebug) &&
  2172. (PsecPCON(pcon) != psecException) &&
  2173. !FIsLibPMOD(pmod) &&
  2174. strcmp(PsecPCON(pcon)->szName, ".idata")) {
  2175. DWORD cbPad;
  2176. if (pcon->flags & IMAGE_SCN_CNT_CODE) {
  2177. cbPad = (pcon->cbRawData * CODE_PAD_PERCENT) / 100;
  2178. // A one byte pad causes more problems making small
  2179. // import thunks non-continuous than it solves.
  2180. if (cbPad == 1) {
  2181. cbPad = 0;
  2182. }
  2183. } else if (PsecPCON(pcon) == psecXdata) {
  2184. cbPad = (pcon->cbRawData * XDATA_PAD_PERCENT) / 100;
  2185. } else {
  2186. cbPad = (pcon->cbRawData * DATA_PAD_PERCENT) / 100;
  2187. }
  2188. pcon->cbPad = cbPad;
  2189. pcon->cbRawData += pcon->cbPad; // cbRawData includes pad size
  2190. }
  2191. #ifdef MFILE_PAD
  2192. // Put padding for MFile if it is non incremental link
  2193. if (fPowerMac && fMfilePad && (PsecPCON(pcon) != psecDebug) &&
  2194. (PsecPCON(pcon) != psecException) && !FIsLibPCON(pcon)) {
  2195. // it can't be incremental link
  2196. assert (!fINCR);
  2197. pcon->cbPad = CalculateMFilePad(pcon->cbRawData);
  2198. pcon->cbRawData += pcon->cbPad; // cbRawData includes pad size
  2199. }
  2200. #endif
  2201. // Count number of relocations that will remain part of image
  2202. // and update the optional header. Don't count debug relocations
  2203. // since we don't generate base relocs for them.
  2204. if (PsecPCON(pcon) != psecDebug) {
  2205. CountRelocsInSection(pimage, pcon, rgsymAll, pmod, wMachine);
  2206. }
  2207. }
  2208. void
  2209. MultiplyDefinedSym(
  2210. SWITCH *pswitch,
  2211. const char *szFilename2,
  2212. const char *szSym,
  2213. const char *szFilename1
  2214. )
  2215. {
  2216. char *szOutput;
  2217. szOutput = SzOutputSymbolName(szSym, TRUE);
  2218. if ((Tool == Linker) && !(pswitch->Link.Force & ftMultiple)) {
  2219. // Error if linker and /FORCE:MULTIPLE not specified
  2220. Error(szFilename2, MULTIPLYDEFINED, szOutput, szFilename1);
  2221. } else {
  2222. // Warning for the rest
  2223. Warning(szFilename2, WARNMULTIPLYDEFINED, szOutput, szFilename1);
  2224. }
  2225. if (szSym != szOutput) {
  2226. FreePv(szOutput);
  2227. }
  2228. fMultipleDefinitions = TRUE;
  2229. }
  2230. void
  2231. ProcessAbsSymForIlink (
  2232. PIMAGE pimage,
  2233. PEXTERNAL pext,
  2234. PIMAGE_SYMBOL psymObj,
  2235. const char *szSym,
  2236. BOOL fNewSymbol,
  2237. PMOD pmod
  2238. )
  2239. {
  2240. // check in the incr case
  2241. if (fIncrDbFile &&
  2242. (ChckAbsSym(szSym, psymObj, pext, fNewSymbol) != errNone)) {
  2243. return;
  2244. }
  2245. // full-link case
  2246. RecordSymDef(&pimage->psdAbsolute, pext, pmod);
  2247. }
  2248. void
  2249. ProcessInitSymReplacingCommonSym (
  2250. PEXTERNAL pext,
  2251. const char *szSym,
  2252. PMOD pmod
  2253. )
  2254. {
  2255. // on an ilink if you get a init sym replacing a bss, give up
  2256. if (fIncrDbFile) {
  2257. // This symbol was defined as COMMON at the end
  2258. // of the previous link. Don't allow it to be
  2259. // redefined now.
  2260. #ifdef INSTRUMENT
  2261. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "COMMON replaced with non-COMMON: %s", szSym);
  2262. #endif // INSTRUMENT
  2263. errInc = errCommonSym;
  2264. return;
  2265. }
  2266. // init sym is defined in a cmdline obj => previously seen bss was in cmdline obj
  2267. if (!FIsLibPMOD(pmod)) {
  2268. RemovePrevDefn(pext);
  2269. pext->Flags |= EXTERN_RELINK;
  2270. }
  2271. // init sym defined in lib obj & bss being replaced in cmdline/lib obj
  2272. else {
  2273. RemovePrevDefn(pext);
  2274. pext->Flags |= EXTERN_NO_REFS;
  2275. RemoveAllRefsToPext(pext);
  2276. }
  2277. }
  2278. void
  2279. ProcessCommonSymForIlink (
  2280. PIMAGE pimage,
  2281. PEXTERNAL pext,
  2282. PIMAGE_SYMBOL psymObj,
  2283. const char *szSym,
  2284. BOOL fNewSymbol,
  2285. PMOD pmod
  2286. )
  2287. {
  2288. // Keep track of reference to this bss symbol
  2289. AddReferenceExt(pext, pmod);
  2290. // extern undefined
  2291. if (!(pext->Flags & EXTERN_DEFINED)) {
  2292. // On ilink bss replacing an init isn't allowed
  2293. if (fIncrDbFile && !fNewSymbol && !(pext->Flags & EXTERN_COMMON)) {
  2294. #ifdef INSTRUMENT
  2295. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "COMMON replacing init symbol: %s", szSym);
  2296. #endif // INSTRUMENT
  2297. errInc = errCommonSym;
  2298. return;
  2299. }
  2300. // first definition of COMMON
  2301. if (FIsLibPMOD(pmod)) {
  2302. RecordSymDef(&pimage->psdCommon, pext, pmod);
  2303. }
  2304. }
  2305. // extern already defined as NOT being COMMON
  2306. else if ((pext->Flags & EXTERN_DEFINED) && !(pext->Flags & EXTERN_COMMON)) {
  2307. // Alternate defn for ext available. Need to relink if defn goes away.
  2308. pext->Flags |= EXTERN_RELINK;
  2309. // if on an ilink a bss gets added to a cmdline obj & NOT COMMON was
  2310. // defined in a lib object take out refs and let lib correctness figure
  2311. // it out.
  2312. if (!FIsLibPMOD(pmod) && FIsLibPMOD(PmodPCON(pext->pcon))) {
  2313. pext->Flags |= EXTERN_NO_REFS;
  2314. RemoveAllRefsToPext(pext);
  2315. }
  2316. }
  2317. // extern already defined as COMMON
  2318. else if ((pext->Flags & EXTERN_DEFINED) && (pext->Flags & EXTERN_COMMON)) {
  2319. // Second defn found. Relink if one defn goes away
  2320. pext->Flags |= EXTERN_RELINK;
  2321. // this COMMON is bigger than previously seen COMMON
  2322. if (psymObj->Value > (pext->pcon ?
  2323. pext->pcon->cbRawData - pext->pcon->cbPad : pext->ImageSymbol.Value)) {
  2324. if (fIncrDbFile) {
  2325. // This symbol was defined as COMMON
  2326. // at the end of the previous link.
  2327. // It isn't allowed to grow.
  2328. #ifdef INSTRUMENT
  2329. LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "COMMON symbol grew: %s", szSym);
  2330. #endif // INSTRUMENT
  2331. errInc = errCommonSym;
  2332. return;
  2333. } else {
  2334. // Full Link: Take out prev defn. Alternate defn available
  2335. // If 2nd defn in lib obj remove all references since this obj wasn't pulled in
  2336. // for this defn.
  2337. RemovePrevDefn(pext);
  2338. if (FIsLibPMOD(pmod)) {
  2339. pext->Flags |= EXTERN_NO_REFS;
  2340. RemoveAllRefsToPext(pext);
  2341. RecordSymDef(&pimage->psdCommon, pext, pmod);
  2342. }
  2343. }
  2344. // this COMMON is same size as previously seen COMMON
  2345. } else if (psymObj->Value == (pext->pcon ?
  2346. pext->pcon->cbRawData - pext->pcon->cbPad : pext->ImageSymbol.Value)) {
  2347. // on ilink we need to relink if previous defn was from lib
  2348. if (fIncrDbFile && FindPmodDefiningSym(pimage->psdCommon, pext)) {
  2349. errInc = errCommonSym;
  2350. return;
  2351. }
  2352. }
  2353. }
  2354. // track references made by mod (must call this last)
  2355. AddExtToModRefList(pmod, pext);
  2356. }
  2357. void
  2358. UpdateExternalSymbol(
  2359. PEXTERNAL pext,
  2360. PCON pcon,
  2361. DWORD value,
  2362. SHORT isec,
  2363. WORD symtype,
  2364. WORD iArcMem,
  2365. PMOD pmod,
  2366. PST pst
  2367. )
  2368. /*++
  2369. Routine Description:
  2370. Update the external symbol table.
  2371. Arguments:
  2372. pst - pointer to external structure
  2373. Return Value:
  2374. None.
  2375. --*/
  2376. {
  2377. SetDefinedExt(pext, TRUE, pst);
  2378. if (pext->Flags & (EXTERN_WEAK | EXTERN_LAZY | EXTERN_ALIAS)) {
  2379. // Found a definition of it, so we can forget that it was weak etc.
  2380. pext->Flags &= ~(EXTERN_WEAK | EXTERN_LAZY | EXTERN_ALIAS);
  2381. pext->ImageSymbol.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
  2382. cextWeakOrLazy--;
  2383. }
  2384. pext->pcon = pcon;
  2385. pext->ImageSymbol.Value = value;
  2386. pext->ImageSymbol.SectionNumber = isec;
  2387. pext->ImageSymbol.Type = symtype;
  2388. pext->ArchiveMemberIndex = iArcMem;
  2389. // chain up externs defined by MOD; cannot use PmodPcon(pext->pcon) because of bss
  2390. if (fINCR) {
  2391. if (pmod->pextFirstDefined) {
  2392. pext->pextNextDefined = pmod->pextFirstDefined;
  2393. }
  2394. pmod->pextFirstDefined = pext;
  2395. }
  2396. }
  2397. void
  2398. SetIdataNullThunkPMOD(
  2399. PMOD pmod
  2400. )
  2401. /*++
  2402. Routine Description:
  2403. For each contribution in the module that an .idata NULL_THUNK symbol
  2404. was present, check if the contribution is in .idata. If so, then set
  2405. the rva to !0. In ImportSemantics(), all contributions with !0 rva's
  2406. will be put at then end of their respective DLL contributions. It is
  2407. save to use the rva field in the pcon because this happens before we
  2408. calculate pointers.
  2409. Arguments:
  2410. pmod - module node in image/driver map
  2411. Return Value:
  2412. None.
  2413. --*/
  2414. {
  2415. ENM_SRC enm_src;
  2416. InitEnmSrc(&enm_src, pmod);
  2417. while (FNextEnmSrc(&enm_src)) {
  2418. PCON pcon;
  2419. pcon = enm_src.pcon;
  2420. if ((strcmp(pcon->pgrpBack->szName, ".idata$4") == 0) ||
  2421. (strcmp(pcon->pgrpBack->szName, ".idata$5") == 0)) {
  2422. pcon->rva = !0;
  2423. }
  2424. }
  2425. EndEnmSrc(&enm_src);
  2426. }
  2427. void
  2428. ProcessSymbolsInModule(
  2429. PIMAGE pimage,
  2430. PMOD pmod,
  2431. PBOOL pfNewSymbol,
  2432. PIMAGE_SYMBOL psymAll,
  2433. WORD iArcMem,
  2434. BOOL isPowerMac
  2435. )
  2436. /*++
  2437. Routine Description:
  2438. Process all the symbols in a module.
  2439. Arguments:
  2440. pst - pointer to external structure
  2441. pmod - module node in driver map to process
  2442. *pfNewSymbol - set to !0 if new symbol is added to external symbol table
  2443. psymAll - pointer to all the symbols for a module
  2444. iArcMem - if !0, specifies archive member being processed
  2445. Return Value:
  2446. None.
  2447. --*/
  2448. {
  2449. char szComFileName[_MAX_PATH * 2];
  2450. PIMAGE_SYMBOL psymNext = psymAll;
  2451. PIMAGE_SYMBOL psymObj;
  2452. PIMAGE_AUX_SYMBOL pasym;
  2453. PEXTERNAL pext;
  2454. BOOL fUpdate;
  2455. BOOL fNewSymbol;
  2456. BOOL fNullThunk;
  2457. DWORD csymT = 0;
  2458. DWORD value;
  2459. const char *szSym;
  2460. SHORT isec;
  2461. BYTE isym;
  2462. PCON pcon;
  2463. SzComNamePMOD(pmod, szComFileName);
  2464. DBEXEC(DB_SYMPROCESS, DBPRINT("\nMODULE: %s\n", szComFileName));
  2465. fNullThunk = FALSE;
  2466. while (csymT != pmod->csymbols) {
  2467. assert(psymNext == NULL || csymT == (DWORD)(psymNext - psymAll));
  2468. psymObj = FetchNextSymbol(&psymNext);
  2469. isym = 0;
  2470. if (psymObj->StorageClass == IMAGE_SYM_CLASS_EXTERNAL ||
  2471. psymObj->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL ||
  2472. psymObj->StorageClass == IMAGE_SYM_CLASS_FAR_EXTERNAL) {
  2473. // Initially mark the symbol for no updating.
  2474. // Updating will occur later after we decide if
  2475. // the symbol defines/redefines an existing symbol.
  2476. fUpdate = FALSE;
  2477. fNewSymbol = FALSE;
  2478. // Add to external symbol table
  2479. if (IsLongName(*psymObj)) {
  2480. pext = LookupExternName(pimage->pst, LONGNAME,
  2481. &StringTable[psymObj->n_offset], &fNewSymbol);
  2482. // Flag that this module references a null thunk
  2483. fNullThunk |= (StringTable[psymObj->n_offset] == 0x7f);
  2484. } else {
  2485. pext = LookupExternName(pimage->pst, SHORTNAME,
  2486. (char *) psymObj->n_name, &fNewSymbol);
  2487. // Flag that this module references a null thunk
  2488. fNullThunk |= (psymObj->n_name[0] == 0x7f);
  2489. }
  2490. if (fPowerMac) {
  2491. // This function ProcessSymbolsInModule is called twice in
  2492. // PowerMac. Since the Symbol Table Lookup doesn't mark the
  2493. // symbol new the second time around, we make use of pext->ppcflags
  2494. // to carry over the information
  2495. if (isPowerMac) {
  2496. if (fNewSymbol) {
  2497. SET_BIT(pext, sy_NEWSYMBOL);
  2498. }
  2499. } else if (READ_BIT(pext, sy_NEWSYMBOL)) {
  2500. fNewSymbol = TRUE;
  2501. RESET_BIT(pext, sy_NEWSYMBOL);
  2502. }
  2503. }
  2504. // if MAC DLL, we ignore the symbol __Init32BitLoadseg,
  2505. // because it always referenced, but never called
  2506. if (fM68K && fDLL(pimage)) {
  2507. if (IsLongName(*psymObj)) {
  2508. if (strcmp(&StringTable[psymObj->n_offset], LargeModelName) == 0) {
  2509. pext->Flags |= EXTERN_IGNORE;
  2510. pext->ImageSymbol.Value = 0;
  2511. csymT++;
  2512. continue;
  2513. }
  2514. }
  2515. }
  2516. rgpExternObj[csymT] = pext;
  2517. if (fPowerMac && Tool == Linker) {
  2518. pmod->rgpext[csymT] = pext;
  2519. bv_setAndReadBit(pmod->tocBitVector, csymT);
  2520. }
  2521. // In the case of ilink it is possible to see an ignore'ed
  2522. // external variable again.
  2523. if (fIncrDbFile && !fNewSymbol && (pext->Flags & EXTERN_IGNORE)) {
  2524. fNewSymbol = TRUE;
  2525. pext->Offset = 0;
  2526. pext->ppextPrevUndefined = NULL;
  2527. pext->pextNextUndefined = NULL;
  2528. pext->Flags = EXTERN_DEFINED;
  2529. SetDefinedExt(pext, FALSE, pimage->pst);
  2530. if (fPowerMac) {
  2531. SET_BIT(pext, sy_NEWSYMBOL);
  2532. RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
  2533. RESET_BIT(pext, sy_DESCRRELWRITTEN);
  2534. }
  2535. }
  2536. if (!fNewSymbol &&
  2537. (pext->Flags & (EXTERN_WEAK | EXTERN_LAZY)) &&
  2538. psymObj->StorageClass != IMAGE_SYM_CLASS_WEAK_EXTERNAL)
  2539. {
  2540. // Found a non-weak version of a weak extern. The weak extern
  2541. // should go away. This doesn't happen for aliases, which
  2542. // remain unless they are explicitly defined.
  2543. pext->Flags &= ~(EXTERN_WEAK | EXTERN_LAZY);
  2544. cextWeakOrLazy--;
  2545. fWeakToRegular = TRUE; // See note in SearchLib
  2546. }
  2547. if (fNewSymbol) {
  2548. // Propagate the symbol type ... currently this is just for
  2549. // remembering whether it's a function or not (for multiply
  2550. // defined errors).
  2551. pext->ImageSymbol.Type = psymObj->Type;
  2552. if (pfNewSymbol != NULL) {
  2553. *pfNewSymbol = TRUE;
  2554. }
  2555. }
  2556. if (fM68K && (Tool != Librarian)) {
  2557. // Add appropriate thunk info to this extern
  2558. UpdateExternThunkInfo(pext, csymT);
  2559. }
  2560. szSym = SzNamePext(pext, pimage->pst);
  2561. if (isPowerMac) {
  2562. if (!(pext->Flags & EXTERN_DEFINED) &&
  2563. psymObj->Value == 0 &&
  2564. psymObj->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL)
  2565. {
  2566. csymT++;
  2567. ProcessWeakExtern(pimage->pst, &psymNext, psymObj,
  2568. pext, pmod, pfNewSymbol, fNewSymbol,
  2569. iArcMem);
  2570. isym = 1;
  2571. }
  2572. } else {
  2573. // Determine if the symbol is being defined/redefined.
  2574. isec = psymObj->SectionNumber;
  2575. if (isec > 0) {
  2576. // The symbol is being defined because it has a positive
  2577. // section number.
  2578. fUpdate = TRUE;
  2579. // get contribution symbol is defined in
  2580. pcon = PconPMOD(pmod, isec);
  2581. if ((Tool == Linker || (Tool == Librarian && pimage->Switch.Lib.DefFile))
  2582. && pcon->flags & IMAGE_SCN_LNK_INFO) {
  2583. // Symbol is being defined in a directive section (currently that means it's
  2584. // PowerMac and we're doing an -import directive on it). Ignore it here, i.e.
  2585. // leave it as an unresolved external. The processing will all be done when
  2586. // the directive is handled.
  2587. //
  2588. // In the case of the librarian we ignore it, if a DEF file is present. We will be
  2589. // parsing the directives later. However, we don't ignore it here, but
  2590. // we continue processing it when the librarian does not have a DEF file.
  2591. // This would be the case when we want to combine two import libraries into a new one.
  2592. //
  2593. // this goto is sort of like "continue" except that the loop increment is non-trivial.
  2594. goto NextIterationOfSymbolLoop;
  2595. }
  2596. // If the symbol in the external symbol table has already
  2597. // been defined, then a redefinition is allowed if the
  2598. // new symbols is replacing a COMMON symbol. In this case,
  2599. // the common definition is replaced. Otherwise, notify
  2600. // the user we have a multiply defined symbol and don't
  2601. // update the symbol.
  2602. if (pext->Flags & EXTERN_DEFINED) {
  2603. if (pext->Flags & EXTERN_COMMON) {
  2604. if (fINCR) {
  2605. ProcessInitSymReplacingCommonSym(pext,szSym,pmod);
  2606. }
  2607. pext->Flags &= ~EXTERN_COMMON;
  2608. } else {
  2609. // UNDONE: The following is temporarily broken
  2610. // UNDONE: so that Mac PCODE can get by using
  2611. // UNDONE: two external symbols from a COMDAT
  2612. // UNDONE: section
  2613. #ifdef UNDONE
  2614. if (((pext->Flags & EXTERN_COMDAT) != 0) &&
  2615. #else
  2616. if ((pext->pcon != NULL) && ((pext->pcon->flags & IMAGE_SCN_LNK_COMDAT) != 0) &&
  2617. #endif
  2618. ((pcon->flags & IMAGE_SCN_LNK_COMDAT) != 0)) {
  2619. // This symbol is a COMDAT symbol being
  2620. // redefined in a COMDAT section. Multiple
  2621. // definition errors are detected and reported
  2622. // in FIncludeComdat.
  2623. if (fINCR) {
  2624. // Keep track of COMDAT references
  2625. AddReferenceExt(pext, pmod);
  2626. AddExtToModRefList(pmod, pext);
  2627. }
  2628. } else if (fPowerMac && (szSym[0] == '.')) {
  2629. // Ignore internally created symbols for PowerMac.
  2630. // UNDONE: Why?
  2631. } else {
  2632. char szModule[_MAX_PATH * 2];
  2633. if (pext->pcon == NULL) {
  2634. // This is true for absolute symbols
  2635. strcpy(szModule, "a previous module");
  2636. } else {
  2637. SzComNamePMOD(PmodPCON(pext->pcon), szModule);
  2638. }
  2639. // on an ilink do a full link if new defn is from cmdline obj & old is from lib
  2640. if (fIncrDbFile && !FIsLibPMOD(pmod) &&
  2641. ((pext->pcon && FIsLibPMOD(PmodPCON(pext->pcon)))
  2642. || FindPmodDefiningSym(pimage->psdAbsolute, pext))) {
  2643. if (fTest) {
  2644. PostNote(NULL, MULTDEFNFOUND, szSym);
  2645. }
  2646. errInc = errMultDefFound;
  2647. return;
  2648. }
  2649. MultiplyDefinedSym(&pimage->Switch, szComFileName, szSym, szModule);
  2650. }
  2651. // Reset contribution symbol is defined in
  2652. pcon = pext->pcon;
  2653. fUpdate = FALSE;
  2654. }
  2655. }
  2656. // Assign the value, which will be the local virtual
  2657. // address of the section plus the value of the symbol.
  2658. value = psymObj->Value;
  2659. if (fIncrDbFile) {
  2660. // On an ilink change from bss to init results in full-link
  2661. if (pext->Flags & EXTERN_COMMON) {
  2662. errInc = errCommonSym;
  2663. return;
  2664. }
  2665. // On an ilink, don't update if the pcon is being thrown out. This may happen
  2666. // if a definition in an obj occurs before the defn that was picked before (our
  2667. // policy for COMDATs is to select it from the same obj as before. Needs to be
  2668. // reviewed.)
  2669. if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
  2670. fUpdate = FALSE;
  2671. }
  2672. // On an incremental build need to check for new funcs, data etc.
  2673. else if (!FIsLibPCON(pcon) &&
  2674. (ChckExtSym(szSym, psymObj, pext, fNewSymbol) != errNone)) {
  2675. return;
  2676. }
  2677. }
  2678. } else {
  2679. // The symbol doesn't have a section defining it, but
  2680. // it might be COMMON or an ABSOLUTE. Common data is
  2681. // defined by having a zero section number, but a
  2682. // non-zero value.
  2683. pcon = NULL; // we don't have a CON yet
  2684. if (isec == 0) {
  2685. if (psymObj->Value) {
  2686. // The symbol defines COMMON.
  2687. if (fINCR) {
  2688. ProcessCommonSymForIlink (pimage, pext, psymObj, szSym, fNewSymbol, pmod);
  2689. if (errInc != errNone) {
  2690. return;
  2691. }
  2692. }
  2693. if (!(pext->Flags & EXTERN_DEFINED) ||
  2694. pext->Flags & EXTERN_COMMON)
  2695. {
  2696. if (!(pext->Flags & EXTERN_COMMON)) {
  2697. // First occurrence of common data ...
  2698. // remember which module referenced it (we
  2699. // will emit it with that module when
  2700. // generating CV publics).
  2701. AddToLext(&pmod->plextCommon, pext);
  2702. pext->Flags |= EXTERN_COMMON;
  2703. }
  2704. if (fM68K) {
  2705. if (!(pext->Flags & EXTERN_DEFINED)) {
  2706. // Remember if definition is FAR_EXTERNAL or just EXTERNAL
  2707. pext->ImageSymbol.StorageClass = psymObj->StorageClass;
  2708. } else if (pext->ImageSymbol.StorageClass != psymObj->StorageClass) {
  2709. // Near/Far mismatch
  2710. Warning(szComFileName, MACCOMMON, szSym);
  2711. // Force symbol near
  2712. pext->ImageSymbol.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
  2713. }
  2714. }
  2715. if (psymObj->Value > (pext->pcon ?
  2716. pext->pcon->cbRawData - pext->pcon->cbPad : pext->ImageSymbol.Value)) {
  2717. value = psymObj->Value;
  2718. fUpdate = TRUE;
  2719. }
  2720. }
  2721. } else {
  2722. // This is a simple EXTERN reference
  2723. // add extern to list which if they have mult defns could alter link behavior
  2724. if (fIncrDbFile && (pext->Flags & EXTERN_DEFINED)) {
  2725. AddExtToMultDefList(pext, pimage);
  2726. }
  2727. AddReferenceExt(pext, pmod); // adds MOD to reference list of EXTERN
  2728. if (fINCR) {
  2729. AddExtToModRefList(pmod, pext); // adds EXTERN to reference list of MOD
  2730. }
  2731. if (!(pext->Flags & EXTERN_DEFINED)) {
  2732. if (fIncrDbFile && fNewSymbol) {
  2733. // mark the extern as new function
  2734. if (ISFCN(psymObj->Type)) {
  2735. pext->Flags |= EXTERN_NEWFUNC;
  2736. // reference to new data item
  2737. } else {
  2738. pext->Flags |= EXTERN_NEWDATA;
  2739. }
  2740. }
  2741. if (psymObj->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
  2742. csymT++;
  2743. ProcessWeakExtern(pimage->pst, &psymNext, psymObj,
  2744. pext, pmod, pfNewSymbol, fNewSymbol,
  2745. iArcMem);
  2746. if (fIncrDbFile && (errInc != errNone)) {
  2747. return;
  2748. }
  2749. isym = 1;
  2750. }
  2751. }
  2752. }
  2753. } else if (isec == IMAGE_SYM_ABSOLUTE) {
  2754. // ABSOLUTE. Value is absolute, thus no virtual
  2755. // address needs to be assigned, just the value itself.
  2756. value = psymObj->Value;
  2757. fUpdate = TRUE;
  2758. // If the symbol in the external symbol table is already
  2759. // defined and the absolute values don't match,
  2760. // notify the user we have a multiply defined symbol
  2761. // but don't update the symbol, otherwise update
  2762. // the symbol.
  2763. if ((pext->Flags & EXTERN_DEFINED) &&
  2764. (value != pext->ImageSymbol.Value)) {
  2765. char szModule[_MAX_PATH * 2];
  2766. if (pext->pcon) {
  2767. SzComNamePMOD(PmodPCON(pext->pcon), szModule);
  2768. } else {
  2769. strcpy(szModule, "a previous module");
  2770. }
  2771. MultiplyDefinedSym(&pimage->Switch, szComFileName, szSym, szModule);
  2772. fUpdate = FALSE;
  2773. }
  2774. if (fINCR) {
  2775. ProcessAbsSymForIlink(pimage, pext, psymObj, szSym, fNewSymbol, pmod);
  2776. if (errInc != errNone) {
  2777. return;
  2778. }
  2779. }
  2780. }
  2781. }
  2782. if (fUpdate) {
  2783. UpdateExternalSymbol(pext, pcon, value, isec, psymObj->Type,
  2784. iArcMem, pmod, pimage->pst);
  2785. }
  2786. }
  2787. if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) &&
  2788. (Tool == Linker)) {
  2789. // Record the external symbol.
  2790. if (!bv_setAndReadBit(pmod->tocBitVector, csymT)) {
  2791. pmod->rgpext[csymT] = pext;
  2792. }
  2793. if (mpisymbToc[csymT] & (fReferenceToc |
  2794. fDataReferenceToc |
  2795. fDataMarkToc)) {
  2796. ProcessTocSymbol(pimage, pmod, pext, csymT, mpisymbToc[csymT]);
  2797. }
  2798. if ((mpisymbToc[csymT] & fImGlue) != 0) {
  2799. if (READ_BIT(pext, fImGlue)) {
  2800. Error(szComFileName, DUPLICATEGLUE, szSym);
  2801. }
  2802. pext->dwRestoreToc = mpisymdwRestoreToc[csymT];
  2803. }
  2804. SET_BIT(pext, mpisymbToc[csymT]);
  2805. }
  2806. } else if (Tool == Linker) {
  2807. if (fM68K && (psymObj->SectionNumber > 0)) {
  2808. UpdateLocalThunkInfo(pimage, PconPMOD(pmod, psymObj->SectionNumber), psymObj, csymT);
  2809. }
  2810. if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
  2811. if (mpisymbToc[csymT] & (fReferenceToc |
  2812. fDataReferenceToc |
  2813. fDataMarkToc)) {
  2814. ProcessTocSymbol(pimage, pmod, NULL, csymT, mpisymbToc[csymT]);
  2815. }
  2816. }
  2817. }
  2818. NextIterationOfSymbolLoop:
  2819. csymT++;
  2820. if (!isPowerMac) {
  2821. // Accumulate estimated count of symbols to be emitted to the COFF debug symbol table
  2822. if (IsDebugSymbol(psymObj->StorageClass, &pimage->Switch) ) {
  2823. csymDebugEst += 1 + psymObj->NumberOfAuxSymbols;
  2824. }
  2825. }
  2826. // Skip any auxiliary symbol table entries.
  2827. // isym is initialized to 0 and set to one when ProcessWeakExtern is called
  2828. for (; isym < psymObj->NumberOfAuxSymbols; isym++) {
  2829. pasym = (PIMAGE_AUX_SYMBOL) FetchNextSymbol(&psymNext);
  2830. csymT++;
  2831. }
  2832. }
  2833. if ((Tool == Linker) && fNullThunk) {
  2834. // This module contains a NULL thunk
  2835. SetIdataNullThunkPMOD(pmod);
  2836. }
  2837. }
  2838. void
  2839. BuildExternalSymbolTable (
  2840. PIMAGE pimage,
  2841. PBOOL pfNewSymbol,
  2842. PMOD pmod,
  2843. WORD iArcMem,
  2844. WORD wMachine
  2845. )
  2846. /*++
  2847. Routine Description:
  2848. Reads thru an object, building the external symbols table,
  2849. and optionally counts number of relocations that will end up in image.
  2850. Arguments:
  2851. pst - pointer to external structure
  2852. pfNewSymbol - set to !0 if new symbol, otherwise 0
  2853. pmod - module to process
  2854. fIncReloc - if !0, count relocations
  2855. iArcMem - if !0, specifies number of archive file being processed
  2856. wMachine - machine type of object file.
  2857. Return Value:
  2858. None.
  2859. --*/
  2860. {
  2861. IMAGE_SECTION_HEADER *rgImgSecHdr;
  2862. PIMAGE_SYMBOL rgsymAll = NULL;
  2863. DWORD cbST;
  2864. NAME_LIST nlDirectives;
  2865. DWORD icon;
  2866. // Read in image section headers
  2867. ReadImageSecHdrInfoPMOD(pmod, &rgImgSecHdr);
  2868. if (fM68K && (Tool != Librarian)) {
  2869. // Allocate table that keeps track of references to sym tab
  2870. InitSTRefTab(pmod->csymbols);
  2871. }
  2872. rgsymAll = ReadSymbolTable(FoSymbolTablePMOD(pmod),
  2873. pmod->csymbols,
  2874. FALSE);
  2875. // Read and store object string table.
  2876. StringTable = ReadStringTable(SzFilePMOD(pmod),
  2877. FoSymbolTablePMOD(pmod) +
  2878. (pmod->csymbols * sizeof(IMAGE_SYMBOL)),
  2879. &cbST);
  2880. totalStringTableSize += cbST;
  2881. rgpExternObj = (PEXTERNAL *) PvAllocZ(pmod->csymbols * sizeof(PEXTERNAL));
  2882. if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
  2883. mpisymbToc = (BYTE *) PvAllocZ(pmod->csymbols);
  2884. mpisymdwRestoreToc = (DWORD *) PvAlloc(pmod->csymbols * sizeof(DWORD));
  2885. }
  2886. if (fPowerMac && !(pmod->flags & IMAGE_FILE_MPPC_DLL)) {
  2887. // Process symbols in module before sections
  2888. // This is done to set TocBitVector and to process
  2889. // weak externs before the sections are processed
  2890. // Got to redo this some day - ShankarV
  2891. ProcessSymbolsInModule(
  2892. pimage,
  2893. pmod,
  2894. pfNewSymbol,
  2895. rgsymAll,
  2896. iArcMem, TRUE);
  2897. }
  2898. // process all sections in module
  2899. nlDirectives.First = nlDirectives.Last = 0;
  2900. nlDirectives.Count = 0;
  2901. for (icon = 0; icon < pmod->ccon; icon++) {
  2902. ProcessSectionInModule(pimage,
  2903. pmod,
  2904. (SHORT) (icon + 1),
  2905. &rgImgSecHdr[icon],
  2906. rgsymAll,
  2907. wMachine,
  2908. &nlDirectives);
  2909. }
  2910. if (fIncrDbFile) {
  2911. // Make sure directives haven't changed,
  2912. // REVIEW: we could ret rt away.
  2913. FVerifyDirectivesPMOD(pimage, pmod, &nlDirectives);
  2914. }
  2915. // Process all symbols in module
  2916. ProcessSymbolsInModule(pimage,
  2917. pmod,
  2918. pfNewSymbol,
  2919. rgsymAll,
  2920. iArcMem,
  2921. FALSE);
  2922. if (pimage->Switch.Link.fTCE) {
  2923. MakeEdgePextFromISym(pmod);
  2924. }
  2925. if (fM68K && (Tool != Librarian)) {
  2926. CleanupUnknownObjriRaw(pimage->pst,rgsymAll,StringTable,pmod);
  2927. CleanupSTRefTab();
  2928. }
  2929. // done processing sections and symbols, free tables
  2930. if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
  2931. FreePv(mpisymdwRestoreToc);
  2932. FreePv(mpisymbToc);
  2933. }
  2934. FreePv(rgImgSecHdr);
  2935. FreeStringTable(StringTable);
  2936. FreeSymbolTable(rgsymAll);
  2937. FreePv(rgpExternObj);
  2938. StringTable = NULL;
  2939. if (rgComdatIsyms) {
  2940. FreePv(rgComdatIsyms);
  2941. rgComdatIsyms = NULL;
  2942. }
  2943. if (fIncrDbFile) {
  2944. FreeArgumentList(&nlDirectives);
  2945. }
  2946. }
  2947. COMDAT_ISYMS *
  2948. BuildIsecToIsymMapping (
  2949. PCON pcon,
  2950. PIMAGE_SYMBOL psymAll
  2951. )
  2952. {
  2953. PMOD pmod = PmodPCON(pcon);
  2954. COMDAT_ISYMS *rgcomdatisyms = (COMDAT_ISYMS *) PvAlloc(pmod->ccon * sizeof(COMDAT_ISYMS));
  2955. // initialize
  2956. DWORD i;
  2957. for (i = 0; i < pmod->ccon; i++) {
  2958. rgcomdatisyms[i].isymSec = (DWORD) -1;
  2959. rgcomdatisyms[i].isymComdat = (DWORD) -1;
  2960. }
  2961. // Walk the symbol table and place the first two symbols' isym
  2962. // associated with a section into the map
  2963. PIMAGE_SYMBOL psym = psymAll;
  2964. DWORD isym;
  2965. for (isym = 0; isym < pmod->csymbols; isym++, psym++) {
  2966. SHORT isec = psym->SectionNumber;
  2967. if (isec <= 0) {
  2968. // Skip the uninteresting symbols
  2969. isym += psym->NumberOfAuxSymbols;
  2970. psym += psym->NumberOfAuxSymbols;
  2971. continue;
  2972. }
  2973. assert((DWORD) isec <= pmod->ccon);
  2974. if (rgcomdatisyms[isec-1].isymSec == -1) {
  2975. rgcomdatisyms[isec-1].isymSec = isym;
  2976. } else if (rgcomdatisyms[isec-1].isymComdat == -1) {
  2977. rgcomdatisyms[isec-1].isymComdat = isym;
  2978. }
  2979. // Skip over the auxiliary symbols
  2980. isym += psym->NumberOfAuxSymbols;
  2981. psym += psym->NumberOfAuxSymbols;
  2982. }
  2983. return rgcomdatisyms;
  2984. }
  2985. void
  2986. RemoveAssociativeComdats (
  2987. PCON pcon
  2988. )
  2989. // marks any comdats that are 'associated' with PCON as IMAGE_SCN_LNK_REMOVE.
  2990. // note: all associated pcons come from the same obj
  2991. {
  2992. ENM_SRC enm_src;
  2993. InitEnmSrc(&enm_src, PmodPCON(pcon));
  2994. while (FNextEnmSrc(&enm_src)) {
  2995. if ((enm_src.pcon->selComdat == IMAGE_COMDAT_SELECT_ASSOCIATIVE) &&
  2996. (enm_src.pcon->pconAssoc == pcon)) {
  2997. enm_src.pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  2998. }
  2999. }
  3000. EndEnmSrc(&enm_src);
  3001. }
  3002. BOOL
  3003. FIncludeComdat (
  3004. PIMAGE pimage,
  3005. PCON pcon,
  3006. PIMAGE_SYMBOL psymAll,
  3007. SHORT isecComdat,
  3008. const char **pszComdatName
  3009. )
  3010. /*++
  3011. Routine Description:
  3012. Decide whether to include a comdat in an image.
  3013. Arguments:
  3014. Return Value:
  3015. !0 if we are to include the comdat section, 0 otherwise.
  3016. --*/
  3017. {
  3018. static PMOD pmodCur = NULL;
  3019. PIMAGE_AUX_SYMBOL pasym;
  3020. PIMAGE_SYMBOL psym;
  3021. PEXTERNAL pext;
  3022. BOOL fNewSymbol = FALSE;
  3023. DWORD chksumComdat;
  3024. const char *szName;
  3025. BYTE selComdat;
  3026. PST pst;
  3027. assert(pimage);
  3028. assert(pimage->pst);
  3029. assert(pcon);
  3030. assert(psymAll);
  3031. pst = pimage->pst;
  3032. // build the isec to isym mapping
  3033. if (pmodCur != PmodPCON(pcon)) {
  3034. pmodCur = PmodPCON(pcon);
  3035. rgComdatIsyms = BuildIsecToIsymMapping(pcon, psymAll);
  3036. }
  3037. // setup section symbol
  3038. if (rgComdatIsyms[isecComdat-1].isymSec == -1) {
  3039. FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
  3040. }
  3041. psym = psymAll + rgComdatIsyms[isecComdat-1].isymSec;
  3042. if (psym->StorageClass != IMAGE_SYM_CLASS_STATIC) {
  3043. FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
  3044. }
  3045. if (psym->NumberOfAuxSymbols == 0) {
  3046. FatalPcon(pcon, NOAUXSYMFORCOMDAT, isecComdat);
  3047. }
  3048. pasym = (PIMAGE_AUX_SYMBOL) psym + 1;
  3049. selComdat = pasym->Section.Selection;
  3050. chksumComdat = pasym->Section.CheckSum;
  3051. if (selComdat == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
  3052. // REVIEW -- this algorithm (& assert) assumes that an
  3053. // associative comdat always follows the section it is
  3054. // associated with ... I don't know if that's really
  3055. // true.
  3056. assert(pasym->Section.Number < isecComdat);
  3057. // Include this comdat if the other one got included
  3058. // (i.e. has non-zero size).
  3059. pcon->selComdat = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
  3060. pcon->pconAssoc = RgconPMOD(pmodCur) + pasym->Section.Number - 1;
  3061. if (pcon->pconAssoc->flags & IMAGE_SCN_LNK_REMOVE) {
  3062. return(FALSE);
  3063. }
  3064. return(TRUE);
  3065. }
  3066. // Setup COMDAT symbol
  3067. if (rgComdatIsyms[isecComdat-1].isymComdat == -1) {
  3068. FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
  3069. }
  3070. psym = psymAll + rgComdatIsyms[isecComdat-1].isymComdat;
  3071. // Second symbol has to be STATIC or EXTERNAL
  3072. if ((psym->StorageClass != IMAGE_SYM_CLASS_STATIC) &&
  3073. (psym->StorageClass != IMAGE_SYM_CLASS_EXTERNAL) &&
  3074. (psym->StorageClass != IMAGE_SYM_CLASS_FAR_EXTERNAL)) {
  3075. FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
  3076. }
  3077. if (!psym->N.Name.Short) {
  3078. szName = &StringTable[psym->N.Name.Long];
  3079. } else {
  3080. szName = SzNameSymPst(*psym, pst);
  3081. }
  3082. *pszComdatName = szName;
  3083. if (psym->StorageClass == IMAGE_SYM_CLASS_STATIC) {
  3084. return(TRUE);
  3085. }
  3086. if (IsLongName(*psym)) {
  3087. pext = LookupExternName(pst, LONGNAME, (char *) szName,
  3088. &fNewSymbol);
  3089. } else {
  3090. pext = LookupExternName(pst, SHORTNAME, (char *) psym->n_name,
  3091. &fNewSymbol);
  3092. }
  3093. if (fPowerMac && READ_BIT(pext, sy_NEWSYMBOL)) {
  3094. fNewSymbol = TRUE;
  3095. RESET_BIT(pext, sy_NEWSYMBOL);
  3096. }
  3097. if (fIncrDbFile) {
  3098. // A COMDAT that vanished, reappears - mark it as new.
  3099. if (pext->Flags & EXTERN_IGNORE) {
  3100. fNewSymbol = TRUE;
  3101. pext->Offset = 0;
  3102. pext->ppextPrevUndefined = NULL;
  3103. pext->pextNextUndefined = NULL;
  3104. pext->Flags = EXTERN_DEFINED;
  3105. SetDefinedExt(pext, FALSE, pimage->pst);
  3106. if (fPowerMac) {
  3107. RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
  3108. RESET_BIT(pext, sy_DESCRRELWRITTEN);
  3109. }
  3110. }
  3111. // previously existing function/data. Need to look
  3112. // pext flags since a ref to comdat may occur before defn.
  3113. if (!fNewSymbol &&
  3114. ((pext->Flags & EXTERN_NEWDATA) == 0) &&
  3115. ((pext->Flags & EXTERN_NEWFUNC) == 0)) {
  3116. if (pext->Flags & EXTERN_DEFINED) {
  3117. // Already defined
  3118. if (selComdat == pext->pcon->selComdat) {
  3119. // Attribs match
  3120. if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
  3121. selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
  3122. chksumComdat != pext->pcon->chksumComdat) {
  3123. errInc = errComdat;
  3124. }
  3125. return(FALSE);
  3126. }
  3127. // Attribs don't match
  3128. if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
  3129. pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
  3130. // Pick largest may not match
  3131. errInc = errComdat;
  3132. return(FALSE);
  3133. }
  3134. } else {
  3135. // Currently undefined
  3136. if (pext->Flags & EXTERN_COMDAT) {
  3137. // Previously a comdat
  3138. if (selComdat == pext->pcon->selComdat) {
  3139. if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
  3140. selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
  3141. chksumComdat != pext->pcon->chksumComdat) {
  3142. errInc = errComdat;
  3143. return(FALSE);
  3144. }
  3145. pcon->chksumComdat = chksumComdat;
  3146. pcon->selComdat = selComdat;
  3147. return(TRUE);
  3148. }
  3149. if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
  3150. pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
  3151. // Pick largest may not match
  3152. errInc = errComdat;
  3153. return(FALSE);
  3154. }
  3155. }
  3156. }
  3157. }
  3158. // if a new function, mark it now since it will not
  3159. // appear as a new func when we process symbols.
  3160. if (fNewSymbol && ISFCN(psym->Type) && !FIsLibPCON(pcon)) {
  3161. pext->Flags |= EXTERN_NEWFUNC;
  3162. }
  3163. }
  3164. if ((pext->Flags & EXTERN_COMDAT) != 0) {
  3165. char szComFileName[_MAX_PATH * 2];
  3166. char szComFileNameExt[_MAX_PATH * 2];
  3167. if ((pext->Flags & EXTERN_DEFINED) == 0) {
  3168. // We may have an invalid object module. An example
  3169. // is when an object module defines two COMDATs with
  3170. // the same name because of the compiler's -H option
  3171. // being used to truncate away the uniqueness.
  3172. FatalPcon(pcon, BADCOFF_DUPCOMDAT, szName);
  3173. }
  3174. assert(pext->pcon != NULL);
  3175. assert(pext->pcon->flags & IMAGE_SCN_LNK_COMDAT);
  3176. if (selComdat != pext->pcon->selComdat) {
  3177. // types may not match in the case of IMAGE_COMDAT_SELECT_LARGEST
  3178. if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
  3179. pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
  3180. SzComNamePMOD(pmodCur, szComFileName);
  3181. SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
  3182. MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
  3183. return(FALSE);
  3184. }
  3185. }
  3186. switch (pext->pcon->selComdat) {
  3187. case IMAGE_COMDAT_SELECT_NODUPLICATES :
  3188. SzComNamePMOD(pmodCur, szComFileName);
  3189. SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
  3190. MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
  3191. break;
  3192. case IMAGE_COMDAT_SELECT_ANY :
  3193. if (selComdat == IMAGE_COMDAT_SELECT_LARGEST) {
  3194. // select this comdat instead of the previously selected one
  3195. // UNDONE: tce is affected by this.
  3196. // special ilink handling
  3197. if (fINCR) {
  3198. if (fIncrDbFile) { // on ilink give up
  3199. errInc = errComdat;
  3200. return(FALSE);
  3201. } else { // on full build remove it from defn list but keep all the refs
  3202. RemoveExtFromDefList(PmodPCON(pext->pcon), pext);
  3203. }
  3204. }
  3205. pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  3206. RemoveAssociativeComdats(pext->pcon);
  3207. SetDefinedExt(pext, FALSE, pst);
  3208. goto SelectComdat;
  3209. }
  3210. break;
  3211. case IMAGE_COMDAT_SELECT_SAME_SIZE :
  3212. case IMAGE_COMDAT_SELECT_EXACT_MATCH :
  3213. if (chksumComdat != pext->pcon->chksumComdat) {
  3214. SzComNamePMOD(pmodCur, szComFileName);
  3215. SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
  3216. MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
  3217. }
  3218. break;
  3219. case IMAGE_COMDAT_SELECT_ASSOCIATIVE :
  3220. break;
  3221. case IMAGE_COMDAT_SELECT_LARGEST :
  3222. if ((pcon->cbRawData - pcon->cbPad) >
  3223. (pext->pcon->cbRawData - pext->pcon->cbPad)) {
  3224. // select this comdat instead of the previously selected one
  3225. // UNDONE: tce is affected by this
  3226. // special ilink handling
  3227. if (fINCR) {
  3228. if (fIncrDbFile) { // on ilink give up
  3229. errInc = errComdat;
  3230. return(FALSE);
  3231. } else { // on full build remove it from defn list but keep all the refs
  3232. RemoveExtFromDefList(PmodPCON(pext->pcon), pext);
  3233. }
  3234. }
  3235. pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  3236. RemoveAssociativeComdats(pext->pcon);
  3237. SetDefinedExt(pext, FALSE, pst);
  3238. goto SelectComdat;
  3239. }
  3240. break;
  3241. default:
  3242. FatalPcon(pcon, INVALIDCOMDATSEL, isecComdat);
  3243. }
  3244. return(FALSE);
  3245. } else if (pext->Flags & EXTERN_COMMON) {
  3246. // In FORTRAN it is possible to get a COMMON in one obj
  3247. // and a COMDAT in another for the same data. In this case,
  3248. // the COMDAT should be selected.
  3249. assert(pext->Flags & EXTERN_DEFINED);
  3250. // init sym is defined in a cmdline obj => previously seen sym
  3251. if (fINCR) {
  3252. ProcessInitSymReplacingCommonSym(pext,
  3253. SzNamePext(pext, pimage->pst),
  3254. pmodCur);
  3255. }
  3256. pext->Flags &= ~EXTERN_COMMON;
  3257. SetDefinedExt(pext, FALSE, pst);
  3258. } else if ((pext->Flags & EXTERN_DEFINED) != 0) {
  3259. // The symbol is already defined as neither a COMDAT nor
  3260. // COMMON. Don't select this COMDAT. A multiply defined
  3261. // warning will be issued by ProcessSymbolsInModule.
  3262. return(FALSE);
  3263. }
  3264. SelectComdat:
  3265. pcon->chksumComdat = chksumComdat;
  3266. pcon->selComdat = selComdat;
  3267. pext->Flags |= EXTERN_COMDAT;
  3268. // remove the new data flag on ilink
  3269. if (fINCR && (pext->Flags & EXTERN_NEWDATA)) {
  3270. pext->Flags &= ~(EXTERN_NEWDATA);
  3271. }
  3272. return(TRUE);
  3273. }
  3274. #if 0
  3275. BOOL
  3276. FIncludeComdat (
  3277. PIMAGE pimage,
  3278. PCON pcon,
  3279. PIMAGE_SYMBOL psymAll,
  3280. SHORT isecComdat,
  3281. const char **pszComdatName
  3282. )
  3283. /*++
  3284. Routine Description:
  3285. Decide whether to include a comdat in an image.
  3286. Arguments:
  3287. Return Value:
  3288. !0 if we are to include the comdat section, 0 otherwise.
  3289. --*/
  3290. {
  3291. static PMOD pmodCur = NULL;
  3292. static PIMAGE_SYMBOL psymNext;
  3293. static DWORD csym;
  3294. PIMAGE_AUX_SYMBOL pasym;
  3295. PIMAGE_SYMBOL psym;
  3296. PEXTERNAL pext;
  3297. BOOL fNewSymbol = FALSE;
  3298. BOOL fSecSymSeen = FALSE;
  3299. DWORD isymLast = 0;
  3300. DWORD chksumComdat;
  3301. const char *szName;
  3302. BYTE selComdat;
  3303. PST pst;
  3304. assert(pimage);
  3305. assert(pimage->pst);
  3306. assert(pcon);
  3307. assert(psymAll);
  3308. pst = pimage->pst;
  3309. // compiler guarantees that the comdat section symbols appear in
  3310. // order and the symbols defined in these sections come after
  3311. // the section symbols. make one pass over the symbol table (not quite)
  3312. // for each module to process comdat symbols. Caveat: all symbols of
  3313. // an obj must be in memory which is true now. If this should change
  3314. // uncomment the FileSeek() call below and make changes as outlined
  3315. // in the comments below.
  3316. if (pmodCur != PmodPCON(pcon)) {
  3317. pmodCur = PmodPCON(pcon);
  3318. csym = 0;
  3319. psymNext = psymAll;
  3320. }
  3321. while (csym < pmodCur->csymbols) {
  3322. psym = psymNext++;
  3323. ++csym;
  3324. if (psym->SectionNumber != isecComdat) {
  3325. // Skip any auxiliary symbol table entries.
  3326. psymNext += psym->NumberOfAuxSymbols;
  3327. csym += psym->NumberOfAuxSymbols;
  3328. continue;
  3329. }
  3330. if (!fSecSymSeen) {
  3331. assert(IMAGE_SYM_CLASS_STATIC == psym->StorageClass);
  3332. fSecSymSeen = TRUE;
  3333. if (psym->NumberOfAuxSymbols) {
  3334. pasym = (PIMAGE_AUX_SYMBOL) psymNext;
  3335. selComdat = pasym->Section.Selection;
  3336. chksumComdat = pasym->Section.CheckSum;
  3337. psymNext += psym->NumberOfAuxSymbols;
  3338. csym += psym->NumberOfAuxSymbols;
  3339. isymLast = csym;
  3340. if (selComdat == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
  3341. // REVIEW -- this algorithm (& assert) assumes that an
  3342. // associative comdat always follows the section it is
  3343. // associated with ... I don't know if that's really
  3344. // true.
  3345. assert(pasym->Section.Number < isecComdat);
  3346. // Include this comdat if the other one got included
  3347. // (i.e. has non-zero size).
  3348. pcon->selComdat = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
  3349. pcon->pconAssoc =
  3350. RgconPMOD(pmodCur) + pasym->Section.Number - 1;
  3351. if (pcon->pconAssoc->flags & IMAGE_SCN_LNK_REMOVE) {
  3352. return(FALSE);
  3353. }
  3354. return(TRUE);
  3355. }
  3356. continue;
  3357. }
  3358. FatalPcon(pcon, NOAUXSYMFORCOMDAT, isecComdat);
  3359. }
  3360. // need to reset symbol index to where we left off.
  3361. psymNext = psymAll+isymLast;
  3362. csym = isymLast;
  3363. // second symbol has to be STATIC or EXTERNAL
  3364. assert(IMAGE_SYM_CLASS_STATIC == psym->StorageClass ||
  3365. IMAGE_SYM_CLASS_EXTERNAL == psym->StorageClass ||
  3366. IMAGE_SYM_CLASS_FAR_EXTERNAL == psym->StorageClass);
  3367. if (!psym->N.Name.Short) {
  3368. szName = &StringTable[psym->N.Name.Long];
  3369. } else {
  3370. szName = SzNameSymPst(*psym, pst);
  3371. }
  3372. *pszComdatName = szName;
  3373. if (psym->StorageClass == IMAGE_SYM_CLASS_STATIC) {
  3374. return(TRUE);
  3375. }
  3376. if (IsLongName(*psym)) {
  3377. pext = LookupExternName(pst, LONGNAME, (char *) szName,
  3378. &fNewSymbol);
  3379. } else {
  3380. pext = LookupExternName(pst, SHORTNAME, (char *) psym->n_name,
  3381. &fNewSymbol);
  3382. }
  3383. if (fPowerMac && READ_BIT(pext, sy_NEWSYMBOL)) {
  3384. fNewSymbol = TRUE;
  3385. RESET_BIT(pext, sy_NEWSYMBOL);
  3386. }
  3387. // ilink handling of COMDATs
  3388. if (fIncrDbFile) {
  3389. // A COMDAT that vanished, reappears - mark it as new.
  3390. if (pext->Flags & EXTERN_IGNORE) {
  3391. fNewSymbol = TRUE;
  3392. pext->Offset = 0;
  3393. pext->ppextPrevUndefined = NULL;
  3394. pext->pextNextUndefined = NULL;
  3395. pext->Flags = EXTERN_DEFINED;
  3396. SetDefinedExt(pext, FALSE, pimage->pst);
  3397. if (fPowerMac) {
  3398. RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
  3399. RESET_BIT(pext, sy_DESCRRELWRITTEN);
  3400. }
  3401. }
  3402. // previously existing function/data. Need to look
  3403. // pext flags since a ref to comdat may occur before defn.
  3404. if (!fNewSymbol &&
  3405. ((pext->Flags & EXTERN_NEWDATA) == 0) &&
  3406. ((pext->Flags & EXTERN_NEWFUNC) == 0) ) {
  3407. if (pext->Flags & EXTERN_DEFINED) {
  3408. // Already defined
  3409. if (selComdat == pext->pcon->selComdat) {
  3410. // Attribs match
  3411. if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
  3412. selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
  3413. chksumComdat != pext->pcon->chksumComdat) {
  3414. errInc = errComdat;
  3415. }
  3416. return(FALSE);
  3417. }
  3418. // Attribs don't match
  3419. errInc = errComdat;
  3420. return(FALSE);
  3421. } else if (pext->Flags & EXTERN_COMDAT) {
  3422. // Previously a comdat
  3423. if (selComdat == pext->pcon->selComdat) {
  3424. if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
  3425. selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
  3426. chksumComdat != pext->pcon->chksumComdat) {
  3427. errInc = errComdat;
  3428. return(FALSE);
  3429. }
  3430. pcon->chksumComdat = chksumComdat;
  3431. pcon->selComdat = selComdat;
  3432. return(TRUE);
  3433. }
  3434. errInc = errComdat;
  3435. return(FALSE);
  3436. }
  3437. }
  3438. // if a new function, mark it now since it will not
  3439. // appear as a new func when we process symbols.
  3440. if (fNewSymbol && ISFCN(psym->Type) && !FIsLibPCON(pcon)) {
  3441. pext->Flags |= EXTERN_NEWFUNC;
  3442. }
  3443. }
  3444. if ((pext->Flags & EXTERN_COMDAT) != 0) {
  3445. char szComFileName[_MAX_PATH * 2];
  3446. char szComFileNameExt[_MAX_PATH * 2];
  3447. if ((pext->Flags & EXTERN_DEFINED) == 0) {
  3448. // We may have an invalid object module. An example
  3449. // is when an object module defines two COMDATs with
  3450. // the same name because of the compiler's -H option
  3451. // being used to truncate away the uniqueness.
  3452. FatalPcon(pcon, BADCOFF_DUPCOMDAT, szName);
  3453. }
  3454. assert(pext->pcon != NULL);
  3455. assert(pext->pcon->flags & IMAGE_SCN_LNK_COMDAT);
  3456. if (selComdat != pext->pcon->selComdat) {
  3457. // types may not match in the case of IMAGE_COMDAT_SELECT_LARGEST
  3458. if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
  3459. pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
  3460. SzComNamePMOD(pmodCur, szComFileName);
  3461. SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
  3462. MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
  3463. return(FALSE);
  3464. }
  3465. }
  3466. switch (pext->pcon->selComdat) {
  3467. case IMAGE_COMDAT_SELECT_NODUPLICATES :
  3468. SzComNamePMOD(pmodCur, szComFileName);
  3469. SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
  3470. MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
  3471. break;
  3472. case IMAGE_COMDAT_SELECT_ANY :
  3473. if (selComdat == IMAGE_COMDAT_SELECT_LARGEST) {
  3474. // select this comdat instead of the previously selected one
  3475. // UNDONE: tce is affected by this.
  3476. pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  3477. RemoveAssociativeComdats(pext->pcon);
  3478. SetDefinedExt(pext, FALSE, pst);
  3479. goto SelectComdat;
  3480. }
  3481. break;
  3482. case IMAGE_COMDAT_SELECT_SAME_SIZE :
  3483. case IMAGE_COMDAT_SELECT_EXACT_MATCH :
  3484. if (chksumComdat != pext->pcon->chksumComdat) {
  3485. SzComNamePMOD(pmodCur, szComFileName);
  3486. SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
  3487. MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
  3488. }
  3489. break;
  3490. case IMAGE_COMDAT_SELECT_ASSOCIATIVE :
  3491. break;
  3492. case IMAGE_COMDAT_SELECT_LARGEST :
  3493. if ((pcon->cbRawData - pcon->cbPad) >
  3494. (pext->pcon->cbRawData - pext->pcon->cbPad)) {
  3495. // select this comdat instead of the previously selected one
  3496. // UNDONE: tce is affected by this
  3497. pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
  3498. RemoveAssociativeComdats(pext->pcon);
  3499. SetDefinedExt(pext, FALSE, pst);
  3500. goto SelectComdat;
  3501. }
  3502. break;
  3503. default:
  3504. FatalPcon(pcon, INVALIDCOMDATSEL, isecComdat);
  3505. }
  3506. return(FALSE);
  3507. } else if (pext->Flags & EXTERN_COMMON) {
  3508. // In FORTRAN it is possible to get a COMMON in one obj
  3509. // and a COMDAT in another for the same data. In this case,
  3510. // the COMDAT should be selected.
  3511. assert(pext->Flags & EXTERN_DEFINED);
  3512. pext->Flags &= ~EXTERN_COMMON;
  3513. SetDefinedExt(pext, FALSE, pst);
  3514. } else if ((pext->Flags & EXTERN_DEFINED) != 0) {
  3515. // The symbol is already defined as neither a COMDAT nor
  3516. // COMMON. Don't select this COMDAT. A multiply defined
  3517. // warning will be issued by ProcessSymbolsInModule.
  3518. return(FALSE);
  3519. }
  3520. SelectComdat:
  3521. pcon->chksumComdat = chksumComdat;
  3522. pcon->selComdat = selComdat;
  3523. pext->Flags |= EXTERN_COMDAT;
  3524. // remove the new data flag on ilink
  3525. if (fINCR && (pext->Flags & EXTERN_NEWDATA)) {
  3526. pext->Flags &= ~(EXTERN_NEWDATA);
  3527. }
  3528. return(TRUE);
  3529. }
  3530. FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
  3531. return(FALSE);
  3532. }
  3533. #endif // 0
  3534. DWORD
  3535. AppendLongName (
  3536. PST pst,
  3537. const char *Name
  3538. )
  3539. /*++
  3540. Routine Description:
  3541. Appends the name to string table.
  3542. NOTE: This function currently used by ilink but we should
  3543. be able to use it for non-ilink, non-coff builds.
  3544. Arguments:
  3545. pst - external symbol table.
  3546. Name - Pointer to symbol name.
  3547. Return Value:
  3548. A pointer to the symbol name in the long string table.
  3549. --*/
  3550. {
  3551. DWORD Offset;
  3552. PBLK pblk = &pst->blkStringTable;
  3553. if (pblk->pb == NULL) {
  3554. GrowBlk(pblk, 16L*_1K);
  3555. // Reserve space for String Table Length
  3556. pblk->cb += sizeof(DWORD);
  3557. }
  3558. Offset = pblk->cb;
  3559. // append long name
  3560. IbAppendBlk(pblk, Name, strlen(Name)+1);
  3561. // return offset
  3562. return(Offset);
  3563. }
  3564. DWORD
  3565. LookupLongName (
  3566. PST pst,
  3567. const char *Name
  3568. )
  3569. /*++
  3570. Routine Description:
  3571. Looks up a symbol name in the long string table. If not found, adds
  3572. the symbol name to the long string table.
  3573. Arguments:
  3574. pst - external symbol table.
  3575. Name - Pointer to symbol name.
  3576. Return Value:
  3577. A pointer to the symbol name in the long string table.
  3578. --*/
  3579. {
  3580. INT i;
  3581. PLONG_STRING_LIST ptrString;
  3582. PLONG_STRING_LIST *ptrLastString;
  3583. PBLK pblk;
  3584. // we should never be here on an ilink
  3585. assert(!fIncrDbFile);
  3586. ptrString = pst->plslFirstLongName;
  3587. pblk = &pst->blkStringTable;
  3588. // Adds "Name" to String Table if not found.
  3589. while (ptrString) {
  3590. if (!(i = strcmp(Name, (char *)(&pblk->pb[ptrString->Offset])))) {
  3591. return(ptrString->Offset);
  3592. }
  3593. if (i < 0) {
  3594. ptrLastString = &ptrString->Left;
  3595. ptrString = ptrString->Left;
  3596. } else {
  3597. ptrLastString = &ptrString->Right;
  3598. ptrString = ptrString->Right;
  3599. }
  3600. }
  3601. ptrString = (PLONG_STRING_LIST) ALLOC_PERM(sizeof(LONG_STRING_LIST));
  3602. if (pst->plslFirstLongName == NULL) {
  3603. pst->plslFirstLongName = ptrString;
  3604. } else {
  3605. *ptrLastString = ptrString;
  3606. }
  3607. if (pblk->pb == NULL) {
  3608. GrowBlk(pblk, 16L*_1K);
  3609. // Reserve space for String Table Length
  3610. pblk->cb += sizeof(DWORD);
  3611. }
  3612. ptrString->Offset = pblk->cb;
  3613. IbAppendBlk(pblk, Name, strlen(Name)+1);
  3614. ptrString->Left = ptrString->Right = NULL;
  3615. return(ptrString->Offset);
  3616. }
  3617. INT __cdecl
  3618. Compare (
  3619. void const *String1,
  3620. void const *String2
  3621. )
  3622. /*++
  3623. Routine Description:
  3624. Compares two strings.
  3625. Arguments:
  3626. String1 - A pointer to a string.
  3627. String2 - A pointer to a string.
  3628. Return Value:
  3629. Same as strcmp().
  3630. --*/
  3631. {
  3632. return (strcmp(*(char **) String1, *(char **) String2));
  3633. }
  3634. void
  3635. ReadImageSecHdrInfoPMOD (
  3636. PMOD pmod,
  3637. IMAGE_SECTION_HEADER **prgImgSecHdr
  3638. )
  3639. /*++
  3640. Routine Description:
  3641. Reads in the section headers and saves info.
  3642. Arguments:
  3643. pmod - ptr to a mod
  3644. prgImgSecHdr - if not NULL on return will have ptr to array of section headers
  3645. Return Value:
  3646. None.
  3647. --*/
  3648. {
  3649. IMAGE_SECTION_HEADER *rgImgSecHdr;
  3650. DWORD cbImgSecHdrs;
  3651. DWORD icon;
  3652. DWORD Seek = sizeof(IMAGE_FILE_HEADER) + pmod->cbOptHdr;
  3653. FileSeek(FileReadHandle, FoMemberPMOD(pmod) + Seek, SEEK_SET);
  3654. cbImgSecHdrs = pmod->ccon * sizeof(IMAGE_SECTION_HEADER);
  3655. rgImgSecHdr = (IMAGE_SECTION_HEADER *) PvAlloc(cbImgSecHdrs);
  3656. FileRead(FileReadHandle, rgImgSecHdr, cbImgSecHdrs);
  3657. if (pmod->rgci == NULL) {
  3658. pmod->rgci = (CONINFO *) PvAlloc(pmod->ccon * sizeof(CONINFO));
  3659. }
  3660. assert(pmod->rgci);
  3661. for (icon = 0; icon < pmod->ccon; icon++) {
  3662. pmod->rgci[icon].cReloc = rgImgSecHdr[icon].NumberOfRelocations;
  3663. pmod->rgci[icon].cLinenum = rgImgSecHdr[icon].NumberOfLinenumbers;
  3664. pmod->rgci[icon].foRelocSrc = rgImgSecHdr[icon].PointerToRelocations;
  3665. pmod->rgci[icon].foLinenumSrc = rgImgSecHdr[icon].PointerToLinenumbers;
  3666. pmod->rgci[icon].foRawDataSrc = rgImgSecHdr[icon].PointerToRawData;
  3667. pmod->rgci[icon].rvaSrc = rgImgSecHdr[icon].VirtualAddress;
  3668. }
  3669. if (prgImgSecHdr) {
  3670. *prgImgSecHdr = rgImgSecHdr;
  3671. } else {
  3672. FreePv(rgImgSecHdr);
  3673. }
  3674. }
  3675. char *
  3676. ReadStringTable (
  3677. const char *szFile,
  3678. LONG fo,
  3679. DWORD *pcb
  3680. )
  3681. /*++
  3682. Routine Description:
  3683. Reads the long string table from FileReadHandle.
  3684. Arguments:
  3685. szFile - file to read string table from
  3686. fo - offset to read symbol table from
  3687. *pcb - size of the string table read
  3688. Return Value:
  3689. A pointer to the long string table in memory.
  3690. --*/
  3691. {
  3692. char *pST;
  3693. DWORD cbFile;
  3694. assert(!fStringTableInUse);
  3695. fStringTableInUse = TRUE;
  3696. if (fo == 0) {
  3697. return NULL; // no stringtable
  3698. }
  3699. fMappedStrings = FALSE;
  3700. pST = (char *) PbMappedRegion(FileReadHandle, fo, sizeof(DWORD));
  3701. if (pST != NULL) {
  3702. *pcb = *(DWORD UNALIGNED *) pST;
  3703. if (*pcb == 0) {
  3704. return(NULL);
  3705. }
  3706. if (*pcb == sizeof(DWORD)) {
  3707. *pcb = 0;
  3708. return(NULL);
  3709. }
  3710. pST = (char *) PbMappedRegion(FileReadHandle, fo, *pcb);
  3711. if (pST != NULL) {
  3712. if (pST[*pcb - 1] == '\0') {
  3713. // Only use mapped string table if properly terminated
  3714. fMappedStrings = TRUE;
  3715. return(pST);
  3716. }
  3717. }
  3718. }
  3719. cbFile = FileLength(FileReadHandle);
  3720. if (fo + sizeof(DWORD) > cbFile ||
  3721. (FileSeek(FileReadHandle, fo, SEEK_SET),
  3722. FileRead(FileReadHandle, pcb, sizeof(DWORD)),
  3723. fo + *pcb > cbFile)) {
  3724. // Invalid stringtable pointer.
  3725. Warning(szFile, BADCOFF_STRINGTABLE);
  3726. *pcb = 0;
  3727. return NULL;
  3728. }
  3729. if (*pcb == 0) {
  3730. return(NULL);
  3731. }
  3732. if (*pcb == sizeof(DWORD)) {
  3733. *pcb = 0;
  3734. return(NULL);
  3735. }
  3736. // Allocate string table plus an extra NULL byte to lessen our
  3737. // chances of running off the end of the string table if an object
  3738. // is corrupt.
  3739. GrowBlk(&blkStringTable, *pcb + 1);
  3740. pST = (char *) blkStringTable.pb;
  3741. FileSeek(FileReadHandle, fo, SEEK_SET);
  3742. FileRead(FileReadHandle, pST, *pcb);
  3743. if (*(pST + *pcb - 1)) {
  3744. Warning(szFile, NOSTRINGTABLEEND);
  3745. }
  3746. return(pST);
  3747. }
  3748. void
  3749. FreeStringTable(
  3750. char *pchStringTable
  3751. )
  3752. {
  3753. assert(fStringTableInUse);
  3754. fStringTableInUse = FALSE;
  3755. assert(fMappedStrings || pchStringTable == NULL || pchStringTable == (char *) blkStringTable.pb);
  3756. }
  3757. void
  3758. WriteStringTable (
  3759. INT FileHandle,
  3760. PST pst
  3761. )
  3762. /*++
  3763. Routine Description:
  3764. Writes the long string table to FileWriteHandle.
  3765. Arguments:
  3766. pst - symbol table
  3767. Return Value:
  3768. None.
  3769. --*/
  3770. {
  3771. DWORD li;
  3772. PBLK pblk = &pst->blkStringTable;
  3773. InternalError.Phase = "WriteStringTable";
  3774. if (pblk->pb) {
  3775. li = pblk->cb;
  3776. *(DWORD *) &pblk->pb[0] = li;
  3777. FileWrite(FileHandle, pblk->pb, li);
  3778. } else {
  3779. // No long string names, write a zero.
  3780. li = 0L;
  3781. FileWrite(FileHandle, &li, sizeof(DWORD));
  3782. }
  3783. }
  3784. PIMAGE_RELOCATION
  3785. ReadRgrelPCON(
  3786. PCON pcon,
  3787. DWORD *pcreloc
  3788. )
  3789. {
  3790. DWORD creloc;
  3791. DWORD cbRelocs;
  3792. PIMAGE_RELOCATION rgrel;
  3793. assert(!fRelocsInUse);
  3794. fRelocsInUse = TRUE;
  3795. creloc = CRelocSrcPCON(pcon);
  3796. if (pcon->flags & IMAGE_SCN_LNK_NRELOC_OVFL) {
  3797. if (creloc == 0xFFFF) {
  3798. IMAGE_RELOCATION relFirst;
  3799. PIMAGE_RELOCATION prelFirst;
  3800. // When creloc == 0xFFFF, the reloc count is stored in the first relocation
  3801. prelFirst = (PIMAGE_RELOCATION) PbMappedRegion(FileReadHandle,
  3802. FoRelocSrcPCON(pcon),
  3803. sizeof(IMAGE_RELOCATION));
  3804. if (prelFirst == NULL) {
  3805. FileSeek(FileReadHandle, FoRelocSrcPCON(pcon), SEEK_SET);
  3806. FileRead(FileReadHandle, (void *) &relFirst, sizeof(IMAGE_RELOCATION));
  3807. prelFirst = &relFirst;
  3808. }
  3809. creloc = prelFirst->VirtualAddress;
  3810. #ifndef TESTOVFL
  3811. if (creloc < 0xFFFF) {
  3812. FatalPcon(pcon, BADCOFF_RELOCCOUNT, creloc);
  3813. }
  3814. #endif
  3815. } else {
  3816. FatalPcon(pcon, BADCOFF_RELOCCOUNT, creloc);
  3817. }
  3818. }
  3819. *pcreloc = creloc;
  3820. cbRelocs = creloc * sizeof(IMAGE_RELOCATION);
  3821. rgrel = (PIMAGE_RELOCATION) PbMappedRegion(FileReadHandle,
  3822. FoRelocSrcPCON(pcon),
  3823. cbRelocs);
  3824. fMappedRelocs = (rgrel != NULL);
  3825. if (fMappedRelocs) {
  3826. return(rgrel);
  3827. }
  3828. GrowBlk(&blkRelocs, cbRelocs);
  3829. rgrel = (PIMAGE_RELOCATION) blkRelocs.pb;
  3830. FileSeek(FileReadHandle, FoRelocSrcPCON(pcon), SEEK_SET);
  3831. FileRead(FileReadHandle, (void *) rgrel, cbRelocs);
  3832. return(rgrel);
  3833. }
  3834. void
  3835. FreeRgrel(
  3836. PIMAGE_RELOCATION rgrel
  3837. )
  3838. {
  3839. assert(fRelocsInUse);
  3840. fRelocsInUse = FALSE;
  3841. assert(fMappedRelocs || rgrel == NULL || rgrel == (PIMAGE_RELOCATION) blkRelocs.pb);
  3842. }
  3843. PIMAGE_SYMBOL
  3844. ReadSymbolTable (
  3845. DWORD fo,
  3846. DWORD NumberOfSymbols,
  3847. BOOL fAllowWrite
  3848. )
  3849. /*++
  3850. Routine Description:
  3851. Reads the symbol table from FileReadHandle.
  3852. Arguments:
  3853. fo - A file pointer to the symbol table on disk.
  3854. NumberOfSymbols - Number of symbol table entries.
  3855. Return Value:
  3856. A pointer to the symbol table in memory.
  3857. If zero, then indicates entire symbol table won't fit in memory.
  3858. --*/
  3859. {
  3860. DWORD cb;
  3861. PIMAGE_SYMBOL rgsym;
  3862. assert(!fSymbolTableInUse);
  3863. fSymbolTableInUse = TRUE;
  3864. cb = NumberOfSymbols * sizeof(IMAGE_SYMBOL);
  3865. // Don't use mapping because ProcessSymbolsInModule writes to symbol
  3866. if (!fAllowWrite) {
  3867. rgsym = (PIMAGE_SYMBOL) PbMappedRegion(FileReadHandle,
  3868. fo,
  3869. cb);
  3870. } else {
  3871. rgsym = NULL;
  3872. }
  3873. fMappedSyms = (rgsym != NULL);
  3874. if (fMappedSyms) {
  3875. return(rgsym);
  3876. }
  3877. GrowBlk(&blkSymbolTable, cb);
  3878. rgsym = (PIMAGE_SYMBOL) blkSymbolTable.pb;
  3879. FileSeek(FileReadHandle, fo, SEEK_SET);
  3880. FileRead(FileReadHandle, (void *) rgsym, cb);
  3881. return(rgsym);
  3882. }
  3883. void
  3884. FreeSymbolTable(
  3885. PIMAGE_SYMBOL rgsym
  3886. )
  3887. {
  3888. assert(fSymbolTableInUse);
  3889. fSymbolTableInUse = FALSE;
  3890. assert(fMappedSyms || rgsym == NULL || rgsym == (PIMAGE_SYMBOL) blkSymbolTable.pb);
  3891. }
  3892. PIMAGE_SYMBOL
  3893. FetchNextSymbol (
  3894. PIMAGE_SYMBOL *PtrSymbolTable
  3895. )
  3896. /*++
  3897. Routine Description:
  3898. Returns a pointer to the next symbol table entry.
  3899. Arguments:
  3900. PtrSymbolTable - A pointer to the last symbol table entry.
  3901. If zero, then indicates the next symbol table entry
  3902. must be read from disk, else its already in memory.
  3903. Return Value:
  3904. A pointer to the next symbol table entry in memory.
  3905. --*/
  3906. {
  3907. static IMAGE_SYMBOL symbol;
  3908. if (*PtrSymbolTable) {
  3909. return((*PtrSymbolTable)++);
  3910. }
  3911. ReadSymbolTableEntry(FileReadHandle, &symbol);
  3912. return(&symbol);
  3913. }
  3914. void
  3915. ReadFileHeader (
  3916. INT Handle,
  3917. PIMAGE_FILE_HEADER FileHeader
  3918. )
  3919. /*++
  3920. Routine Description:
  3921. Reads a file header.
  3922. Arguments:
  3923. Handle - File handle to read from.
  3924. FileHeader - Pointer to location to write file header to.
  3925. Return Value:
  3926. None.
  3927. --*/
  3928. {
  3929. FileRead(Handle, FileHeader, sizeof(IMAGE_FILE_HEADER));
  3930. }
  3931. void
  3932. WriteFileHeader (
  3933. INT Handle,
  3934. PIMAGE_FILE_HEADER FileHeader
  3935. )
  3936. /*++
  3937. Routine Description:
  3938. Writes a file header.
  3939. Arguments:
  3940. Handle - File handle to write to.
  3941. FileHeader - Pointer to location to read file header from.
  3942. Return Value:
  3943. None.
  3944. --*/
  3945. {
  3946. // Force flags for little endian target
  3947. FileHeader->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
  3948. FileWrite(Handle, FileHeader, sizeof(IMAGE_FILE_HEADER));
  3949. }
  3950. void
  3951. ReadOptionalHeader (
  3952. INT Handle,
  3953. PIMAGE_OPTIONAL_HEADER OptionalHeader,
  3954. WORD Size
  3955. )
  3956. /*++
  3957. Routine Description:
  3958. Reads an optional header.
  3959. Arguments:
  3960. Handle - File handle to read from.
  3961. OptionalHeader - Pointer to location to write optional header to.
  3962. Size - Length in bytes of optional header.
  3963. Return Value:
  3964. None.
  3965. --*/
  3966. {
  3967. if (Size) {
  3968. Size = (WORD) __min(Size, sizeof(IMAGE_OPTIONAL_HEADER));
  3969. FileRead(Handle, OptionalHeader, Size);
  3970. }
  3971. }
  3972. void
  3973. WriteOptionalHeader (
  3974. INT Handle,
  3975. PIMAGE_OPTIONAL_HEADER OptionalHeader,
  3976. WORD Size
  3977. )
  3978. /*++
  3979. Routine Description:
  3980. Writes an optional header.
  3981. Arguments:
  3982. Handle - File handle to read from.
  3983. OptionalHeader - Pointer to location to read optional header from.
  3984. Size - Length in bytes of optional header.
  3985. Return Value:
  3986. None.
  3987. --*/
  3988. {
  3989. if (Size) {
  3990. FileWrite(Handle, OptionalHeader, Size);
  3991. }
  3992. }
  3993. void
  3994. ReadSymbolTableEntry (
  3995. INT Handle,
  3996. PIMAGE_SYMBOL SymbolEntry
  3997. )
  3998. /*++
  3999. Routine Description:
  4000. Reads a symbol table entry.
  4001. Arguments:
  4002. Handle - File handle to read from.
  4003. SymbolEntry - Pointer to location to write symbol entry to.
  4004. Return Value:
  4005. None.
  4006. --*/
  4007. {
  4008. FileRead(Handle, (void *) SymbolEntry, sizeof(IMAGE_SYMBOL));
  4009. }
  4010. // WriteSectionHeader: writes a COFF section header to object or image file.
  4011. //
  4012. void
  4013. WriteSectionHeader (
  4014. INT Handle,
  4015. PIMAGE_SECTION_HEADER SectionHeader
  4016. )
  4017. {
  4018. FileWrite(Handle, SectionHeader, sizeof(IMAGE_SECTION_HEADER));
  4019. }
  4020. void
  4021. WriteSymbolTableEntry (
  4022. INT Handle,
  4023. PIMAGE_SYMBOL SymbolEntry
  4024. )
  4025. /*++
  4026. Routine Description:
  4027. Writes a symbol entry.
  4028. Arguments:
  4029. Handle - File handle to write to.
  4030. SymbolEntry - Pointer to location to read symbol entry from.
  4031. Return Value:
  4032. None.
  4033. --*/
  4034. {
  4035. BOOL fPCODE = FALSE;
  4036. if ((fM68K || fPowerMac) && FPcodeSym(*SymbolEntry)) {
  4037. fPCODE = TRUE;
  4038. SymbolEntry->Type &= ~IMAGE_SYM_TYPE_PCODE;
  4039. }
  4040. FileWrite(Handle, (void *) SymbolEntry, sizeof(IMAGE_SYMBOL));
  4041. if ((fM68K || fPowerMac) && fPCODE) {
  4042. SymbolEntry->Type |= IMAGE_SYM_TYPE_PCODE;
  4043. }
  4044. }
  4045. void
  4046. WriteAuxSymbolTableEntry (
  4047. INT Handle,
  4048. PIMAGE_AUX_SYMBOL AuxSymbolEntry
  4049. )
  4050. /*++
  4051. Routine Description:
  4052. Writes an auxiliary symbol entry.
  4053. Arguments:
  4054. Handle - File handle to write to.
  4055. AuxSymbolEntry - Pointer to location to read auxiliary symbol entry from.
  4056. Return Value:
  4057. None.
  4058. --*/
  4059. {
  4060. FileWrite(Handle, (void *) AuxSymbolEntry, sizeof(IMAGE_AUX_SYMBOL));
  4061. }
  4062. void
  4063. ReadRelocations (
  4064. INT Handle,
  4065. PIMAGE_RELOCATION RelocTable,
  4066. DWORD NumRelocs
  4067. )
  4068. /*++
  4069. Routine Description:
  4070. Reads relocations.
  4071. Arguments:
  4072. Handle - File handle to read from.
  4073. RelocTable - Pointer to location to write relocations to.
  4074. NumRelocs - Number of relocations to read.
  4075. Return Value:
  4076. None.
  4077. --*/
  4078. {
  4079. FileRead(Handle, (void *) RelocTable, NumRelocs*sizeof(IMAGE_RELOCATION));
  4080. }
  4081. void
  4082. WriteRelocations (
  4083. INT Handle,
  4084. PIMAGE_RELOCATION RelocTable,
  4085. DWORD NumRelocs
  4086. )
  4087. /*++
  4088. Routine Description:
  4089. Write relocations.
  4090. Arguments:
  4091. Handle - File handle to write to.
  4092. RelocTable - Pointer to location to read relocations from.
  4093. NumRelocs - Number of relocations to write.
  4094. Return Value:
  4095. None.
  4096. --*/
  4097. {
  4098. FileWrite(Handle, (PVOID)RelocTable, NumRelocs*sizeof(IMAGE_RELOCATION));
  4099. }
  4100. INT __cdecl
  4101. FpoDataCompare (
  4102. void const *Fpo1,
  4103. void const *Fpo2
  4104. )
  4105. /*++
  4106. Routine Description:
  4107. Compares two fpo data structures
  4108. Arguments:
  4109. Fpo1 - A pointer to a Fpo Data Structure.
  4110. Fpo2 - A pointer to a Fpo Data Structure.
  4111. Return Value:
  4112. Same as strcmp().
  4113. --*/
  4114. {
  4115. return (((PFPO_DATA) Fpo1)->ulOffStart -
  4116. ((PFPO_DATA) Fpo2)->ulOffStart);
  4117. }
  4118. char *
  4119. SzModifyFilename(
  4120. const char *szIn,
  4121. const char *szNewExt
  4122. )
  4123. // Mallocs a version of the old filename with the new extension.
  4124. {
  4125. char szDrive[_MAX_DRIVE];
  4126. char szDir[_MAX_DIR];
  4127. char szFname[_MAX_FNAME];
  4128. char szExt[_MAX_EXT];
  4129. char szOut[_MAX_PATH];
  4130. _splitpath(szIn, szDrive, szDir, szFname, szExt);
  4131. _makepath(szOut, szDrive, szDir, szFname, szNewExt);
  4132. return SzDup(szOut);
  4133. }
  4134. void
  4135. SaveFixupForMapFile(
  4136. DWORD rva
  4137. )
  4138. {
  4139. if (plrvaFixupsForMapFile == NULL ||
  4140. crvaFixupsForMapFile >= crvaInLrva) {
  4141. LRVA *plrvaNew = (LRVA *) PvAlloc(sizeof(LRVA));
  4142. plrvaNew->plrvaNext = plrvaFixupsForMapFile;
  4143. plrvaFixupsForMapFile = plrvaNew;
  4144. crvaFixupsForMapFile = 0;
  4145. }
  4146. plrvaFixupsForMapFile->rgrva[crvaFixupsForMapFile++] = rva;
  4147. }
  4148. void
  4149. PrintBanner(VOID)
  4150. {
  4151. const char *szThing;
  4152. switch (Tool) {
  4153. case Editor: szThing = "COFF Binary File Editor"; break;
  4154. #if defined(_M_IX86) || defined(_M_MRX000)
  4155. case Linker: szThing = "32-Bit Incremental Linker"; break;
  4156. #else
  4157. case Linker: szThing = "32-Bit Executable Linker"; break;
  4158. #endif
  4159. case Librarian: szThing = "32-Bit Library Manager"; break;
  4160. case Dumper: szThing = "COFF Binary File Dumper"; break;
  4161. default: szThing = ToolGenericName; break;
  4162. }
  4163. printf("Microsoft (R) %s Version " VERSION_STR
  4164. "\n"
  4165. "Copyright (C) Microsoft Corp 1992-1996. All rights reserved.\n"
  4166. "\n",
  4167. szThing);
  4168. if (blkResponseFileEcho.pb != NULL) {
  4169. if (blkResponseFileEcho.pb[blkResponseFileEcho.cb - 1] != '\n') {
  4170. IbAppendBlk(&blkResponseFileEcho, "\n", 1);
  4171. }
  4172. IbAppendBlk(&blkResponseFileEcho, "", 1); // null-terminate
  4173. printf("%s", blkResponseFileEcho.pb);
  4174. FreeBlk(&blkResponseFileEcho);
  4175. }
  4176. fflush(stdout);
  4177. fNeedBanner = FALSE;
  4178. }
  4179. const char *
  4180. SzObjSectionName(
  4181. const char *szsName,
  4182. const char *rgchObjStringTable
  4183. )
  4184. // Returns a section name as read from an object, properly mapping names
  4185. // beginning with "/" to longnames.
  4186. //
  4187. // Uses a static buffer for the returned zero-terminated name (i.e. don't
  4188. // use it twice at the same time ...)
  4189. {
  4190. static char szSectionNameBuf[IMAGE_SIZEOF_SHORT_NAME + 1];
  4191. unsigned long ichName;
  4192. strncpy(szSectionNameBuf, szsName, IMAGE_SIZEOF_SHORT_NAME);
  4193. if (szSectionNameBuf[0] != '/') {
  4194. return szSectionNameBuf;
  4195. }
  4196. if (sscanf(&szSectionNameBuf[1], "%7lu", &ichName) == 1) {
  4197. return &rgchObjStringTable[ichName];
  4198. }
  4199. return szSectionNameBuf;
  4200. }
  4201. DWORD
  4202. RvaAlign(
  4203. DWORD rvaIn,
  4204. DWORD flags
  4205. )
  4206. // Aligns an RVA according to the alignment specified in the given flags.
  4207. //
  4208. {
  4209. DWORD mskAlign;
  4210. if (flags & IMAGE_SCN_TYPE_NO_PAD) {
  4211. return rvaIn; // no align
  4212. }
  4213. switch (flags & 0x00700000) {
  4214. default: assert(FALSE); // this can't happen
  4215. case IMAGE_SCN_ALIGN_1BYTES:
  4216. return rvaIn;
  4217. case IMAGE_SCN_ALIGN_2BYTES: mskAlign = 1; break;
  4218. case IMAGE_SCN_ALIGN_4BYTES: mskAlign = 3; break;
  4219. case IMAGE_SCN_ALIGN_8BYTES: mskAlign = 7; break;
  4220. case IMAGE_SCN_ALIGN_16BYTES: mskAlign = 15; break;
  4221. case IMAGE_SCN_ALIGN_32BYTES: mskAlign = 31; break;
  4222. case IMAGE_SCN_ALIGN_64BYTES: mskAlign = 63; break;
  4223. // If no explicit alignment is specified (because this is an old object or a
  4224. // section that was created by the linker), default a to machine-dependent value
  4225. case 0:
  4226. if (fM68K) {
  4227. mskAlign = 3;
  4228. break;
  4229. } else {
  4230. mskAlign = 15;
  4231. break;
  4232. }
  4233. }
  4234. if ((rvaIn & mskAlign) == 0) {
  4235. return rvaIn;
  4236. }
  4237. return (rvaIn & ~mskAlign) + mskAlign + 1;
  4238. }
  4239. void
  4240. AddToLext(
  4241. LEXT **pplext,
  4242. PEXTERNAL pext
  4243. )
  4244. {
  4245. LEXT *plextNew = (LEXT *) PvAlloc(sizeof(LEXT));
  4246. plextNew->pext = pext;
  4247. plextNew->plextNext = *pplext;
  4248. *pplext = plextNew;
  4249. }
  4250. LEXT *
  4251. PlextFind (
  4252. LEXT *plextFirst,
  4253. PEXTERNAL pext
  4254. )
  4255. {
  4256. LEXT *plext = plextFirst;
  4257. while (plext) {
  4258. if (plext->pext == pext) {
  4259. return plext;
  4260. }
  4261. plext = plext->plextNext;
  4262. }
  4263. return NULL;
  4264. }
  4265. BOOL
  4266. FValidFileHdr (
  4267. const char *szFilename,
  4268. PIMAGE_FILE_HEADER pImgFileHdr
  4269. )
  4270. /*++
  4271. Routine Description:
  4272. Validates an object or image.
  4273. Arguments:
  4274. Argument - argument.
  4275. Return Value:
  4276. 0 invalid file header
  4277. !0 valid file header
  4278. --*/
  4279. {
  4280. // Check to see if it has a valid machine type
  4281. switch (pImgFileHdr->Machine) {
  4282. case IMAGE_FILE_MACHINE_UNKNOWN :
  4283. case IMAGE_FILE_MACHINE_I386 :
  4284. case IMAGE_FILE_MACHINE_R3000 :
  4285. case IMAGE_FILE_MACHINE_R4000 :
  4286. case IMAGE_FILE_MACHINE_R10000 :
  4287. case IMAGE_FILE_MACHINE_ALPHA :
  4288. case IMAGE_FILE_MACHINE_POWERPC :
  4289. case 0x0290 : // UNDONE : IMAGE_FILE_MACHINE_PARISC
  4290. case IMAGE_FILE_MACHINE_M68K :
  4291. case IMAGE_FILE_MACHINE_MPPC_601 :
  4292. break;
  4293. default:
  4294. Warning(szFilename, NOTCOFF);
  4295. return(FALSE);
  4296. }
  4297. return(TRUE);
  4298. }
  4299. // CheckDupFilename: checks for an output file having the same name as an
  4300. // input file.
  4301. void
  4302. CheckDupFilename(
  4303. const char *szOutFilename,
  4304. PARGUMENT_LIST parg
  4305. )
  4306. {
  4307. char szFullOutPath[_MAX_PATH];
  4308. if (_fullpath(szFullOutPath, szOutFilename, _MAX_PATH - 1) == NULL) {
  4309. Fatal(NULL, CANTOPENFILE, szOutFilename);
  4310. }
  4311. while (parg != NULL) {
  4312. char szPargPath[_MAX_PATH];
  4313. if (_fullpath(szPargPath, parg->OriginalName, _MAX_PATH - 1) == NULL) {
  4314. Fatal(NULL, CANTOPENFILE, parg->OriginalName);
  4315. }
  4316. if (_tcsicmp(szFullOutPath, szPargPath) == 0) {
  4317. OutFilename = NULL; // don't clobber output file
  4318. Fatal(NULL, DUP_OUT_FILE, szFullOutPath);
  4319. }
  4320. parg = parg->Next;
  4321. }
  4322. }
  4323. typedef PIMAGE_NT_HEADERS (WINAPI *PFNCSMF)(PVOID, DWORD, DWORD *, DWORD *);
  4324. typedef PIMAGE_NT_HEADERS (WINAPI *PFNMFACS)(LPSTR, DWORD *, DWORD *);
  4325. void
  4326. ChecksumImage(
  4327. PIMAGE pimage
  4328. )
  4329. {
  4330. HINSTANCE hImagehlp;
  4331. DWORD cbImageFile;
  4332. BYTE *pbMap;
  4333. DWORD dwSumHeader;
  4334. DWORD dwChecksum;
  4335. hImagehlp = LoadLibrary("IMAGEHLP.DLL");
  4336. if (hImagehlp == NULL) {
  4337. Warning(NULL, DLLLOADWARN, "IMAGEHLP.DLL");
  4338. return;
  4339. }
  4340. cbImageFile = FileLength(FileWriteHandle);
  4341. pbMap = PbMappedRegion(FileWriteHandle, 0, cbImageFile);
  4342. if (pbMap == NULL) {
  4343. PFNMFACS pfnMapAndCheckSum;
  4344. pfnMapAndCheckSum = (PFNMFACS) GetProcAddress(hImagehlp, "MapFileAndCheckSumA");
  4345. if (pfnMapAndCheckSum == NULL) {
  4346. Warning(NULL, FCNNOTFOUNDWARN, "MapFileAndCheckSumA", "IMAGEHLP.DLL");
  4347. return;
  4348. }
  4349. FileClose(FileWriteHandle, TRUE);
  4350. if ((*pfnMapAndCheckSum)(OutFilename, &dwSumHeader, &dwChecksum)) {
  4351. Warning(NULL, UNABLETOCHECKSUM);
  4352. }
  4353. FileWriteHandle = FileOpen(OutFilename, O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
  4354. pimage->ImgOptHdr.CheckSum = dwChecksum;
  4355. pimage->WriteHeader(pimage, FileWriteHandle);
  4356. } else {
  4357. PFNCSMF pfnCheckSumMappedFile;
  4358. PIMAGE_NT_HEADERS pHdr;
  4359. pfnCheckSumMappedFile = (PFNCSMF) GetProcAddress(hImagehlp, "CheckSumMappedFile");
  4360. if (pfnCheckSumMappedFile == NULL) {
  4361. Warning(NULL, FCNNOTFOUNDWARN, "CheckSumMappedFile", "IMAGEHLP.DLL");
  4362. return;
  4363. }
  4364. pHdr = (*pfnCheckSumMappedFile)(pbMap, cbImageFile, &dwSumHeader, &dwChecksum);
  4365. if (pHdr == NULL) {
  4366. Warning(NULL, UNABLETOCHECKSUM);
  4367. return;
  4368. }
  4369. pHdr->OptionalHeader.CheckSum = dwChecksum;
  4370. }
  4371. FreeLibrary(hImagehlp);
  4372. }
  4373. //================================================================
  4374. // PsymAlternateStaticPcodeSym -
  4375. // given a pointer to a static pcode symbol foo,
  4376. // this function returns a pointer to __nep_foo. __nep_foo will
  4377. // preced foo by either
  4378. // one symbol (the file was *NOT* compiled /Gy), or
  4379. // three symbols (the file was compiled /Gy.
  4380. // In the second case, the two symbols in between the native and
  4381. // pcode symbol are the section sym and its aux sym.
  4382. // So the algorithm is to look back two symbols and check if that
  4383. // symbol has one aux symbol. If so, the file was compiled /Gy
  4384. // and __nep_foo is three symbols back. Otherwise, __nep_foo is
  4385. // one symbol back.
  4386. //================================================================
  4387. PIMAGE_SYMBOL
  4388. PsymAlternateStaticPcodeSym(
  4389. PIMAGE pimage,
  4390. PCON pcon,
  4391. BOOL fPass1,
  4392. PIMAGE_SYMBOL psym,
  4393. BOOL fPcodeRef
  4394. )
  4395. {
  4396. const char *szPrefix = fPcodeRef ? szPCODEFHPREFIX : szPCODENATIVEPREFIX;
  4397. size_t cchPrefix = strlen(szPrefix);
  4398. PIMAGE_SYMBOL pStaticPcodeSym;
  4399. WORD isym;
  4400. // make sure this is in fact a pcode symbol
  4401. assert(FPcodeSym(*psym));
  4402. // Search backward for a symbol with the appropriate name and prefix. Try
  4403. // a maximum of two symbols; ignore section symbols. The compiler is
  4404. // required to generate Pcode entry points this way.
  4405. pStaticPcodeSym = psym - 1;
  4406. for (isym = 0; isym < 2; isym++) {
  4407. if ((pStaticPcodeSym-1)->NumberOfAuxSymbols == 1 &&
  4408. (pStaticPcodeSym-1)->StorageClass == IMAGE_SYM_CLASS_STATIC)
  4409. {
  4410. pStaticPcodeSym -= 2;
  4411. }
  4412. if (pStaticPcodeSym->StorageClass != IMAGE_SYM_CLASS_STATIC ||
  4413. pStaticPcodeSym->NumberOfAuxSymbols != 0)
  4414. {
  4415. FatalPcon(pcon, MACBADPCODEEP);
  4416. }
  4417. const char *szSym;
  4418. if (fPass1) {
  4419. szSym = SzNameSymPb(*pStaticPcodeSym, StringTable);
  4420. } else {
  4421. szSym = SzNameFixupSym(pimage, pStaticPcodeSym);
  4422. }
  4423. if (strncmp(szSym, szPrefix, cchPrefix) == 0) {
  4424. // Found it
  4425. return(pStaticPcodeSym);
  4426. }
  4427. pStaticPcodeSym--;
  4428. }
  4429. // Didn't find the Pcode variant ... this isn't supposed to happen.
  4430. FatalPcon(pcon, MACBADPCODEEP);
  4431. return(NULL);
  4432. }
  4433. // keep a list of weak externs
  4434. void
  4435. AddWeakExtToList (
  4436. IN PEXTERNAL pext,
  4437. IN PEXTERNAL pextWeakDefault
  4438. )
  4439. {
  4440. WEAK_EXTERN_LIST *pwel = pwelHead;
  4441. while (pwel) {
  4442. if (pwel->pext == pext) {
  4443. pwel->pextWeakDefault = pextWeakDefault;
  4444. return;
  4445. }
  4446. pwel = pwel->pwelNext;
  4447. }
  4448. pwel = (WEAK_EXTERN_LIST *)PvAlloc(sizeof(WEAK_EXTERN_LIST));
  4449. pwel->pext = pext;
  4450. pwel->pextWeakDefault = pextWeakDefault;
  4451. // attach it to list
  4452. pwel->pwelNext = pwelHead;
  4453. pwelHead = pwel;
  4454. }
  4455. // return the extern associated with the weak extern
  4456. PEXTERNAL
  4457. PextWeakDefaultFind (
  4458. IN PEXTERNAL pext
  4459. )
  4460. {
  4461. WEAK_EXTERN_LIST *pwel = pwelHead;
  4462. while (pwel) {
  4463. if (pwel->pext == pext) {
  4464. return pwel->pextWeakDefault;
  4465. }
  4466. pwel = pwel->pwelNext;
  4467. }
  4468. return NULL;
  4469. }
  4470. void
  4471. FreeWeakExtList (
  4472. IN VOID
  4473. )
  4474. {
  4475. WEAK_EXTERN_LIST *pwelNext;
  4476. while (pwelHead) {
  4477. pwelNext = pwelHead->pwelNext;
  4478. FreePv(pwelHead);
  4479. pwelHead = pwelNext;
  4480. }
  4481. pwelHead = NULL;
  4482. }