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.

2614 lines
79 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: lnkmain.cpp
  7. *
  8. * File Comments:
  9. *
  10. * Main entrypoint to the COFF Linker.
  11. *
  12. ***********************************************************************/
  13. #include "link.h"
  14. extern PIMAGE pimageDeflib;
  15. BOOL fIncrSwitchUsed; // User specified the incremental switch
  16. BOOL fIncrSwitchValue; // User specified value
  17. BOOL fExportDirective; // export directives were seen
  18. BOOL fDbgImpLib = FALSE; // build a dbg implib
  19. static DEBUG_TYPE dtUser; // User-specified debugtype
  20. static int savArgc; // saved argc
  21. static char **savArgv; // saved argv
  22. DWORD cbHdrSize;
  23. BOOL
  24. FScanSwitches(const char *szOption)
  25. {
  26. WORD i;
  27. PARGUMENT_LIST argument;
  28. for (i = 0, argument = SwitchArguments.First;
  29. i < SwitchArguments.Count;
  30. i++, argument = argument->Next) {
  31. if (_stricmp(szOption, argument->OriginalName) == 0) {
  32. return TRUE;
  33. }
  34. }
  35. return FALSE;
  36. }
  37. void
  38. LinkerUsage(void)
  39. {
  40. if (fNeedBanner) {
  41. PrintBanner();
  42. }
  43. // UNDONE: Options for unreleased products are supressed for the
  44. // UNDONE: NT build. This is so an external release of the linker
  45. // UNDONE: for NT 3.5 will not document unreleased products. No
  46. // UNDONE: functionality is disabled in the NT version.
  47. puts("usage: LINK [options] [files] [@commandfile]\n"
  48. "\n"
  49. " options:\n"
  50. "\n"
  51. " /ALIGN:#\n"
  52. " /BASE:{address|@filename,key}\n"
  53. " /COMMENT:comment\n"
  54. " /DEBUG\n"
  55. " /DEBUGTYPE:{CV|COFF|BOTH}\n"
  56. " /DEF:filename\n"
  57. " /DEFAULTLIB:library\n"
  58. " /DLL\n"
  59. " /DLLCHAR:X86THUNK\n"
  60. " /DRIVER[:UPONLY]\n"
  61. " /ENTRY:symbol\n"
  62. " /EXETYPE:DYNAMIC\n"
  63. " /EXPORT:symbol\n"
  64. " /FIXED\n"
  65. " /FORCE[:{MULTIPLE|UNRESOLVED}]\n"
  66. " /GPSIZE:#\n"
  67. " /HEAP:reserve[,commit]\n"
  68. " /IMPORT:[symbol][,][LIB=container][,WEAK=1]\n" // PowerMac
  69. " /IMPORT:[CURRENTVER=#][,][OLDCODEVER=#][,][OLDAPIVER=#]\n" // PowerMac
  70. " /IMPLIB:filename\n"
  71. " /INCLUDE:symbol\n"
  72. " /INCREMENTAL:{YES|NO}\n"
  73. " /MAC:{BUNDLE|NOBUNDLE|TYPE=xxxx|CREATOR=xxxx|INIT=symbol|TERM=symbol}\n"
  74. #ifdef MFILE_PAD
  75. " /MAC:{MFILEPAD|NOMFILEPAD}\n"
  76. #endif
  77. " /MACDATA:filename\n"
  78. " /MACHINE:{IX86|MIPS|ALPHA|PPC|M68K|MPPC}\n"
  79. " /MACRES:filename\n"
  80. " /MAP[:filename]\n"
  81. " /MERGE:from=to\n"
  82. " /NODEFAULTLIB[:library]\n"
  83. " /NOENTRY\n"
  84. " /NOLOGO\n"
  85. " /OPT:{REF|NOREF}\n"
  86. " /ORDER:@filename\n"
  87. " /OUT:filename\n"
  88. " /PDB:{filename|NONE}\n"
  89. " /PROFILE\n"
  90. " /RELEASE\n"
  91. " /SECTION:name,[E][R][W][S][D][K][L][P][X]\n"
  92. " /SHARED\n" // PowerMac
  93. " /STACK:reserve[,commit]\n"
  94. " /STUB:filename\n"
  95. " /SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|POSIX}[,#[.##]]\n"
  96. " /SWAPRUN:{NET|CD}\n"
  97. " /VERBOSE[:LIB]\n"
  98. " /VERSION:#[.#]\n"
  99. " /VXD\n"
  100. " /WARN[:warninglevel]\n"
  101. " /WS:AGGRESSIVE");
  102. exit(USAGE);
  103. }
  104. BOOL
  105. FIncrementalLinkSupported(PIMAGE pimage)
  106. /*++
  107. Routine Description:
  108. Validates that ilink is supported for the machine type.
  109. If machine type is not already known, checks all command
  110. line argument files for a machine type stamp. If no files
  111. indicate machine type, then go ahead and try an ilink, but if
  112. it later turns out we can't do ilink on this machine, Error.
  113. Arguments:
  114. pimage - Pointer to the image.
  115. Return Value:
  116. FALSE - Ilink not supported for machine..
  117. TRUE - Ilink supported for machine (or still unknown).
  118. --*/
  119. {
  120. DWORD i;
  121. PARGUMENT_LIST argument;
  122. switch (pimage->ImgFileHdr.Machine) {
  123. case IMAGE_FILE_MACHINE_UNKNOWN :
  124. break;
  125. case IMAGE_FILE_MACHINE_ALPHA :
  126. case IMAGE_FILE_MACHINE_I386 :
  127. case IMAGE_FILE_MACHINE_R4000:
  128. case IMAGE_FILE_MACHINE_R10000:
  129. cbExternal = offsetof(EXTERNAL, psecRef);
  130. case IMAGE_FILE_MACHINE_MPPC_601:
  131. return(TRUE);
  132. default :
  133. return(FALSE);
  134. }
  135. // Check all command line files for object files with machine type
  136. for (i = 0, argument = FilenameArguments.First;
  137. i < FilenameArguments.Count;
  138. i++, argument = argument->Next) {
  139. INT fhObj;
  140. IMAGE_FILE_HEADER ImageFileHdr;
  141. fhObj = FileOpen(argument->OriginalName, O_RDONLY | O_BINARY, 0);
  142. if (IsArchiveFile(argument->OriginalName, fhObj)) {
  143. FileClose(fhObj, FALSE);
  144. continue;
  145. }
  146. // Could be an obj file, read header
  147. FileSeek(fhObj, 0, SEEK_SET);
  148. ReadFileHeader(fhObj, &ImageFileHdr);
  149. FileClose(fhObj, FALSE);
  150. switch (ImageFileHdr.Machine) {
  151. case IMAGE_FILE_MACHINE_UNKNOWN :
  152. // Keep looking
  153. break;
  154. case IMAGE_FILE_MACHINE_ALPHA :
  155. case IMAGE_FILE_MACHINE_I386:
  156. case IMAGE_FILE_MACHINE_R4000:
  157. case IMAGE_FILE_MACHINE_R10000:
  158. cbExternal = offsetof(EXTERNAL, psecRef);
  159. case IMAGE_FILE_MACHINE_MPPC_601:
  160. // Incremental link supported
  161. return(TRUE);
  162. default:
  163. // Incremental link not supported
  164. return(FALSE);
  165. }
  166. }
  167. // still don't know whether machine is supported.
  168. // try to ilink and error out later if not
  169. return(TRUE);
  170. }
  171. void
  172. ProcessLinkerSwitches (
  173. PIMAGE pimage,
  174. PCON pcon,
  175. const char *szFilename
  176. )
  177. /*++
  178. Routine Description:
  179. Process all linker switches.
  180. Arguments:
  181. pimage - image
  182. pcon - Non-NULL if switch is from a directive
  183. szFilename - name of file in the case of switch is from directive
  184. Return Value:
  185. None.
  186. --*/
  187. {
  188. #define ImageFileHdr (pimage->ImgFileHdr)
  189. #define ImageOptionalHdr (pimage->ImgOptHdr)
  190. #define Switch (pimage->Switch)
  191. #define SwitchInfo (pimage->SwitchInfo)
  192. BOOL IsDirective;
  193. DWORD i;
  194. INT good_scan;
  195. INT next;
  196. DWORD major;
  197. DWORD minor;
  198. char fileKey[_MAX_PATH];
  199. char *name;
  200. char *token;
  201. char *p;
  202. PARGUMENT_LIST argument;
  203. FILE *file_read_stream;
  204. char *szReproOption;
  205. PST pst = pimage->pst;
  206. BOOL fAmountSet = FALSE;
  207. IsDirective = (pcon != NULL);
  208. for (i = 0, argument = SwitchArguments.First;
  209. i < SwitchArguments.Count;
  210. i++, argument = argument->Next,
  211. (!IsDirective && (szReproDir != NULL)
  212. ? fprintf(pfileReproResponse, "/%s\n", szReproOption)
  213. : 0), FreePv(szReproOption)) {
  214. WORD iarpv;
  215. DWORD dwVal;
  216. char *szVal;
  217. char szFname[_MAX_FNAME + _MAX_EXT];
  218. char szExt[_MAX_EXT];
  219. argument->parp = ParpParseSz(argument->OriginalName);
  220. iarpv = 0; // we will gen warning if all val's not consumed
  221. // The default is to copy the option verbatim to the repro directory,
  222. // but the option-handling code may change this if the option contains
  223. // a filename.
  224. szReproOption = SzDup(argument->OriginalName);
  225. if (!strcmp(argument->OriginalName, "?")) {
  226. LinkerUsage();
  227. assert(FALSE); // doesn't return
  228. }
  229. if (!_stricmp(argument->OriginalName, "batch")) {
  230. goto ProcessedArg; // quietly ignore -batch
  231. }
  232. if (!_stricmp(argument->parp->szArg, "comment")) {
  233. if (!FGotVal(argument->parp, iarpv)) {
  234. goto MissingVal;
  235. }
  236. szVal = argument->parp->rgarpv[iarpv++].szVal;
  237. IbAppendBlk(&blkComment, szVal, strlen(szVal) + 1);
  238. SetOpt(SwitchInfo, OP_COMMENT);
  239. goto ProcessedArg;
  240. }
  241. if (!_stricmp(argument->parp->szArg, "exetype")) {
  242. if (!FGotVal(argument->parp, iarpv)) {
  243. goto MissingVal;
  244. }
  245. for (; iarpv < argument->parp->carpv; iarpv++) {
  246. szVal = argument->parp->rgarpv[iarpv].szVal;
  247. if (!_stricmp(szVal, "dynamic")) {
  248. pimage->fDynamicVxd = TRUE;
  249. } else if (!_stricmp(szVal, "dev386")) {
  250. // UNDONE: This is obsolete
  251. } else {
  252. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  253. }
  254. }
  255. goto ProcessedArg;
  256. }
  257. // UNDONE: temp param for handling VxD header size problem
  258. if (!_stricmp(argument->parp->szArg, "hdrsize")) {
  259. if (!FGotVal(argument->parp, iarpv)) {
  260. goto MissingVal;
  261. }
  262. if (!FNumParp(argument->parp, iarpv++, &dwVal)) {
  263. goto BadNum;
  264. }
  265. cbHdrSize = dwVal;
  266. goto ProcessedArg;
  267. }
  268. if (!_stricmp(argument->parp->szArg, "mac")) {
  269. if (!FGotVal(argument->parp, iarpv)) {
  270. goto MissingVal;
  271. }
  272. for (; iarpv < argument->parp->carpv; iarpv++) {
  273. char *szKey = argument->parp->rgarpv[iarpv].szKeyword;
  274. szVal = argument->parp->rgarpv[iarpv].szVal;
  275. if (szKey != NULL && !_stricmp(szKey, "type")) {
  276. Switch.Link.szMacType = szVal;
  277. } else if (szKey != NULL && !_stricmp(szKey, "creator")) {
  278. Switch.Link.szMacCreator = szVal;
  279. } else if (szKey != NULL && !_stricmp(szKey, "init")) {
  280. MppcSetInitRoutine(pimage, szVal);
  281. SetOpt(SwitchInfo, OP_MACINIT);
  282. if (IsDirective) {
  283. SetOpt(SwitchInfo, OP_MACINITLIB);
  284. }
  285. } else if (szKey != NULL && !_stricmp(szKey, "term")) {
  286. MppcSetTermRoutine(pimage, szVal);
  287. SetOpt(SwitchInfo, OP_MACTERM);
  288. if (IsDirective) {
  289. SetOpt(SwitchInfo, OP_MACTERMLIB);
  290. }
  291. } else if (!_stricmp(szVal, "bundle")) {
  292. Switch.Link.fMacBundle = TRUE;
  293. } else if (!_stricmp(szVal, "nobundle")) {
  294. Switch.Link.fMacBundle = FALSE;
  295. #ifdef MFILE_PAD
  296. } else if (!_stricmp(szVal, "mfilepad")) {
  297. fMfilePad = TRUE;
  298. SetOpt(SwitchInfo, OP_MFILEPAD);
  299. } else if (!_stricmp(szVal, "nomfilepad")) {
  300. fMfilePad = FALSE;
  301. SetOpt(SwitchInfo, OP_MFILEPAD);
  302. #endif
  303. } else {
  304. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  305. }
  306. }
  307. goto ProcessedArg;
  308. }
  309. if (!_stricmp(argument->parp->szArg, "macres")) {
  310. if (argument->OriginalName[7] == '\0') {
  311. goto MissingVal;
  312. }
  313. // TODO: Use GetMacResourcePointer instead of FArgumentInList - ShankarV
  314. if (!FArgumentInList(argument->OriginalName+7, &MacResourceList)) {
  315. AddArgumentToList(&MacResourceList, argument->OriginalName+7,
  316. "resntBinaryResource");
  317. SetOpt(SwitchInfo, OP_MACRES);
  318. }
  319. argument->parp->carpv = ++iarpv; // only one arg
  320. goto ProcessedArg;
  321. }
  322. if (!_stricmp(argument->parp->szArg, "macdata")) {
  323. if (argument->OriginalName[8] == '\0') {
  324. goto MissingVal;
  325. }
  326. UseMacBinaryRes(argument->OriginalName+8, resntDataFork, -1);
  327. argument->parp->carpv = ++iarpv; // assume only one arg
  328. goto ProcessedArg;
  329. }
  330. if (!_stricmp(argument->parp->szArg, "name")) {
  331. if (!IsDirective || pimage->imaget != imagetVXD) {
  332. Warning(szFilename, WARN_UNKNOWN_SWITCH, argument->OriginalName);
  333. continue;
  334. }
  335. if (!FGotVal(argument->parp, iarpv)) {
  336. goto MissingVal;
  337. }
  338. iarpv++;
  339. szModuleName = argument->parp->rgarpv[0].szVal;
  340. goto ProcessedArg;
  341. }
  342. if (!_stricmp(argument->OriginalName, "nopack")) {
  343. Switch.Link.fNoPack = TRUE;
  344. goto ProcessedArg;
  345. }
  346. #ifdef ILINKLOG
  347. if (!_stricmp(argument->OriginalName, "noilinklog")) {
  348. fIlinkLog = FALSE;
  349. goto ProcessedArg;
  350. }
  351. #endif // ILINKLOG
  352. if (!_stricmp(argument->OriginalName, "xoff")) {
  353. fExceptionsOff = TRUE;
  354. goto ProcessedArg;
  355. }
  356. if (!_stricmp(argument->OriginalName, "nologo")) {
  357. fNeedBanner = FALSE;
  358. goto ProcessedArg;
  359. }
  360. if (!_stricmp(argument->OriginalName, "profile")) {
  361. Switch.Link.fProfile = TRUE;
  362. goto ProcessedArg;
  363. }
  364. if (!_stricmp(argument->OriginalName, "test")) {
  365. fTest = TRUE;
  366. goto ProcessedArg;
  367. }
  368. if (!_stricmp(argument->OriginalName, "fullbuild")) {
  369. Switch.Link.fNotifyFullBuild = FALSE;
  370. goto ProcessedArg;
  371. }
  372. if (!_stricmp(argument->parp->szArg, "export")) {
  373. if (argument->OriginalName[6] != ':') {
  374. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  375. }
  376. if (Tool == Librarian) {
  377. assert(IsDirective);
  378. ParseExportDirective(argument->OriginalName+7, pimageDeflib,
  379. TRUE, szFilename);
  380. } else if (Tool == Linker) {
  381. if (!IsDirective || pimage->imaget == imagetVXD) {
  382. AddArgumentToList(&ExportSwitches, argument->OriginalName+7, NULL);
  383. } else {
  384. fExportDirective = TRUE;
  385. }
  386. }
  387. goto ProcessedAllVals;
  388. }
  389. if (!_strnicmp(argument->OriginalName, "defaultlib:", 11 )) {
  390. if (argument->OriginalName[11] == '\0') {
  391. goto MissingVal;
  392. }
  393. if (Switch.Link.fNoDefaultLibs) {
  394. // Skip all values
  395. iarpv = argument->parp->carpv;
  396. } else {
  397. MakeDefaultLib(&argument->OriginalName[11], &pimage->libs);
  398. argument->parp->carpv = ++iarpv; // assume only one arg
  399. }
  400. goto ProcessedArg;
  401. }
  402. if (!_stricmp(argument->parp->szArg, "disallowlib")) {
  403. if (argument->OriginalName[12] == '\0') {
  404. goto MissingVal;
  405. }
  406. if (Switch.Link.fNoDefaultLibs) {
  407. // Skip all values
  408. iarpv = argument->parp->carpv;
  409. } else {
  410. ExcludeLib(&argument->OriginalName[12],
  411. &pimage->libs,
  412. pcon ? PmodPCON(pcon) : NULL);
  413. argument->parp->carpv = ++iarpv; // assume only one arg
  414. }
  415. goto ProcessedArg;
  416. }
  417. if (!_stricmp(argument->parp->szArg, "opt")) {
  418. if (!FGotVal(argument->parp, iarpv)) {
  419. goto MissingVal;
  420. }
  421. for (; iarpv < argument->parp->carpv; iarpv++) {
  422. szVal = argument->parp->rgarpv[iarpv].szVal;
  423. if (_stricmp(szVal, "ref") == 0) {
  424. Switch.Link.fTCE = TRUE;
  425. fExplicitOptRef = TRUE;
  426. } else if (_stricmp(szVal, "noref") == 0) {
  427. Switch.Link.fTCE = FALSE;
  428. fExplicitOptRef = TRUE;
  429. } else {
  430. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  431. }
  432. }
  433. goto ProcessedArg;
  434. }
  435. next = 0;
  436. if (!_stricmp(argument->parp->szArg, "nodefaultlib") ||
  437. !_stricmp(argument->parp->szArg, "nod"))
  438. {
  439. if (Switch.Link.fNoDefaultLibs) {
  440. argument->parp->carpv = ++iarpv; // assume only one arg
  441. goto ProcessedArg; // redundant
  442. }
  443. next = !_stricmp(argument->parp->szArg, "nodefaultlib") ? 12 : 3;
  444. if (argument->OriginalName[next] == ':' &&
  445. argument->OriginalName[next+1] != '\0') {
  446. // Lib name given ...
  447. NoDefaultLib(&argument->OriginalName[next+1], &pimage->libs);
  448. argument->parp->carpv = ++iarpv; // assume only one arg
  449. } else {
  450. // -defaultlib with no argument
  451. Switch.Link.fNoDefaultLibs = TRUE;
  452. NoDefaultLib(NULL, &pimage->libs);
  453. }
  454. goto ProcessedArg;
  455. }
  456. if (!_stricmp(argument->parp->szArg, "out")) {
  457. if (argument->OriginalName[3] != ':' ||
  458. argument->OriginalName[4] == '\0') {
  459. goto MissingVal;
  460. }
  461. argument->parp->carpv = ++iarpv; // only one arg
  462. // If the user used the out switch, then ignore
  463. // any directive that sets the filename.
  464. if (Switch.Link.Out && IsDirective) {
  465. _splitpath(OutFilename, NULL, NULL, szFname, szExt);
  466. strcat(szFname, szExt);
  467. // Warn if directive doesn't match with output filename
  468. // For PowerMac the names can differ (internal name vs filename)
  469. if (_tcsicmp(szFname, argument->OriginalName+4) &&
  470. ImageFileHdr.Machine != IMAGE_FILE_MACHINE_MPPC_601) {
  471. Warning(szFilename, OUTDRCTVDIFF,
  472. argument->OriginalName+4, OutFilename);
  473. }
  474. goto ProcessedArg;
  475. }
  476. OutFilename = argument->OriginalName+4;
  477. Switch.Link.Out = TRUE;
  478. if (szReproDir != NULL) {
  479. _splitpath(OutFilename, NULL, NULL, szFname, szExt);
  480. FreePv(szReproOption);
  481. szReproOption = (char *)
  482. PvAlloc(strlen("out:\".\\%s%s\"")+strlen(szFname)+strlen(szExt));
  483. sprintf(szReproOption, "out:\".\\%s%s\"", szFname, szExt);
  484. }
  485. goto ProcessedArg;
  486. }
  487. if (!_stricmp(argument->parp->szArg, "release")) {
  488. Switch.Link.fChecksum = TRUE;
  489. goto ProcessedArg;
  490. }
  491. if (!_stricmp(argument->parp->szArg, "base")) {
  492. if (!FGotVal(argument->parp, iarpv)) {
  493. goto MissingVal;
  494. }
  495. // If the user used the base switch, then ignore
  496. // any directive that sets the base.
  497. if (Switch.Link.Base && IsDirective) {
  498. goto ProcessedAllVals;
  499. }
  500. if (argument->parp->rgarpv[0].szVal[0] == '@') {
  501. // Base file. First value is @filename ... expect a second
  502. // value which is the key.
  503. char *szBaseFile;
  504. if (!FGotVal(argument->parp, 1)) {
  505. goto MissingVal;
  506. }
  507. // Base values are in a command file, so open it.
  508. szBaseFile = SzSearchEnv("LIB",
  509. argument->parp->rgarpv[0].szVal+1,
  510. ".txt");
  511. if (szReproDir != NULL) {
  512. CopyFileToReproDir(szBaseFile, FALSE);
  513. _splitpath(szBaseFile, NULL, NULL, szFname, szExt);
  514. FreePv(szReproOption);
  515. szReproOption = (char *)
  516. PvAlloc(strlen("base:@\".\\%s%s,%s\"")+strlen(szFname)+
  517. strlen(szExt)+strlen(argument->parp->rgarpv[1].szVal));
  518. sprintf(szReproOption, "base:@\".\\%s%s,%s\"", szFname, szExt,
  519. argument->parp->rgarpv[1].szVal);
  520. }
  521. if (!(file_read_stream = fopen(szBaseFile, "rt"))) {
  522. Fatal(szFilename, CANTOPENFILE, szBaseFile);
  523. }
  524. // Read each key from command file until we find a match.
  525. // fgets() fetches next argument from command file.
  526. good_scan = 0;
  527. while (!good_scan && fgets(fileKey, _MAX_PATH,
  528. file_read_stream)) {
  529. fileKey[strlen(fileKey)-1] = '\0'; // Replace \n with \0.
  530. if ((p = strchr(fileKey, ';')) != NULL) {
  531. *p = '\0';
  532. }
  533. token = strtok(fileKey, Delimiters);
  534. while (token) {
  535. if (_stricmp(token, argument->parp->rgarpv[1].szVal)) {
  536. break;
  537. }
  538. token = strtok(NULL, Delimiters);
  539. if (token && (good_scan = sscanf(token, "%li", &dwVal)) == 1) {
  540. ImageOptionalHdr.ImageBase = dwVal;
  541. token = strtok(NULL, Delimiters);
  542. if (!token || sscanf(token, "%li", &VerifyImageSize) != 1) {
  543. Fatal(szBaseFile, BADBASE, token);
  544. }
  545. break;
  546. } else {
  547. Fatal(szBaseFile, BADBASE, token);
  548. }
  549. }
  550. }
  551. fclose(file_read_stream);
  552. if (!good_scan) {
  553. Fatal(szBaseFile, KEYNOTFOUND,
  554. argument->parp->rgarpv[1].szVal);
  555. }
  556. FreePv(szBaseFile);
  557. Switch.Link.Base = TRUE;
  558. iarpv = 2; // we processed 2 values
  559. goto ProcessedArg;
  560. }
  561. switch (argument->parp->carpv) {
  562. case 1:
  563. // BASED
  564. if (!FNumParp(argument->parp, iarpv,
  565. &ImageOptionalHdr.ImageBase)) {
  566. goto BadNum;
  567. }
  568. iarpv++;
  569. break;
  570. case 2:
  571. // BASE, SIZE
  572. //
  573. // Supported just to provide compatibility with the
  574. // syntax of the base file.
  575. if (!FNumParp(argument->parp, iarpv,
  576. &ImageOptionalHdr.ImageBase)) {
  577. goto BadNum;
  578. }
  579. iarpv++;
  580. if (!FNumParp(argument->parp, iarpv,
  581. &VerifyImageSize)) {
  582. goto BadNum;
  583. }
  584. iarpv++;
  585. break;
  586. default:
  587. Fatal(szFilename, BADBASE, argument->OriginalName+5);
  588. }
  589. Switch.Link.Base = TRUE;
  590. goto ProcessedArg;
  591. }
  592. if (!_stricmp(argument->OriginalName, "Brepro")) {
  593. fReproducible = TRUE;
  594. goto ProcessedArg;
  595. }
  596. if (!_stricmp(argument->parp->szArg, "pdb")) {
  597. if (argument->OriginalName[4] == '\0') {
  598. goto MissingVal;
  599. }
  600. szVal = argument->OriginalName+4;
  601. if (!_stricmp(szVal, "none")) {
  602. fPdb = FALSE;
  603. } else {
  604. PdbFilename = argument->OriginalName+4;
  605. if (szReproDir != NULL) {
  606. // NOTE: The actual file is copied in DeterminePDBFilename()
  607. _splitpath(PdbFilename, NULL, NULL, szFname, szExt);
  608. if ((szFname[0] != '\0') && (szExt[0] != '\0')) {
  609. FreePv(szReproOption);
  610. szReproOption = (char *)
  611. PvAlloc(strlen(szFname)+strlen(szExt)+strlen("pdb:\".\\%s%s\""));
  612. sprintf(szReproOption, "pdb:\".\\%s%s\"", szFname, szExt);
  613. }
  614. }
  615. }
  616. argument->parp->carpv = ++iarpv; // only one arg
  617. goto ProcessedArg;
  618. }
  619. next = 0;
  620. if (!_stricmp(argument->parp->szArg, "debug")) {
  621. for (; iarpv < argument->parp->carpv; iarpv++) {
  622. szVal = argument->parp->rgarpv[iarpv].szVal;
  623. if (!_stricmp(szVal, "mapped")) {
  624. IncludeDebugSection = TRUE;
  625. } else if (!_stricmp(szVal, "notmapped")) {
  626. IncludeDebugSection = FALSE;
  627. } else if (!_stricmp(szVal, "full")) {
  628. Switch.Link.DebugInfo = Full;
  629. fAmountSet = TRUE;
  630. } else if (!_stricmp(szVal, "partial")) {
  631. Switch.Link.DebugInfo = Partial;
  632. fAmountSet = TRUE;
  633. } else if (!_stricmp(szVal, "minimal")) {
  634. Switch.Link.DebugInfo = Minimal;
  635. fAmountSet = TRUE;
  636. } else if (!_stricmp(szVal, "none")) {
  637. Switch.Link.DebugInfo = None;
  638. fAmountSet = TRUE;
  639. } else {
  640. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  641. }
  642. }
  643. if (!fAmountSet) {
  644. // Just -debug, or -debug:notmapped etc. Default to "full".
  645. Switch.Link.DebugInfo = Full;
  646. }
  647. fAmountSet = FALSE; // allow for -debug:none followed by -debug
  648. goto ProcessedArg;
  649. }
  650. if (!_stricmp(argument->parp->szArg, "merge")) {
  651. char *pchEqu = _tcschr(argument->OriginalName + 6, '=');
  652. if ((pchEqu == NULL) ||
  653. (pchEqu == (argument->OriginalName + 6)) ||
  654. (pchEqu[1] == '\0')) {
  655. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  656. }
  657. *pchEqu++ = '\0';
  658. if (!FValidSecName(argument->OriginalName + 6)) {
  659. char *szSecName = SzDup(argument->OriginalName + 6);
  660. *--pchEqu = '=';
  661. Fatal(szFilename, INVALIDSECNAME, szSecName, argument->OriginalName);
  662. }
  663. if (!FValidSecName(pchEqu)) {
  664. *--pchEqu = '=';
  665. Fatal(szFilename, INVALIDSECNAME, ++pchEqu, argument->OriginalName);
  666. }
  667. AddArgumentToList(&MergeSwitches,
  668. argument->OriginalName + 6,
  669. pchEqu);
  670. goto ProcessedAllVals;
  671. }
  672. if (!_stricmp(argument->parp->szArg, "debugtype")) {
  673. if (!FGotVal(argument->parp, iarpv)) {
  674. goto MissingVal;
  675. }
  676. for (; iarpv < argument->parp->carpv; iarpv++) {
  677. szVal = argument->parp->rgarpv[iarpv].szVal;
  678. if (!_stricmp(szVal, "coff")) {
  679. dtUser = (DEBUG_TYPE) (dtUser | CoffDebug);
  680. } else if (!_stricmp(szVal, "cv")) {
  681. dtUser = (DEBUG_TYPE) (dtUser | CvDebug);
  682. } else if (!_stricmp(szVal, "both")) {
  683. dtUser = (DEBUG_TYPE) (dtUser | CoffDebug | CvDebug);
  684. } else if (!_stricmp(szVal, "fpo")) {
  685. dtUser = (DEBUG_TYPE) (dtUser | FpoDebug);
  686. } else if (!_stricmp(szVal, "fixup")) {
  687. dtUser = (DEBUG_TYPE) (dtUser | FixupDebug);
  688. } else if (!_stricmp(szVal, "map")) {
  689. // Force mapfile generation
  690. Switch.Link.fMap = TRUE;
  691. Switch.Link.fMapLines = TRUE;
  692. SetOpt(SwitchInfo, OP_MAP);
  693. } else {
  694. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  695. }
  696. }
  697. goto ProcessedArg;
  698. }
  699. if (!_stricmp(argument->parp->szArg, "entry")) {
  700. if (!FGotVal(argument->parp, iarpv)) {
  701. goto MissingVal;
  702. }
  703. EntryPointName = SzDup(argument->parp->rgarpv[0].szVal);
  704. SwitchInfo.szEntry = EntryPointName;
  705. iarpv++;
  706. SetOpt(SwitchInfo, OP_ENTRY);
  707. goto ProcessedArg;
  708. }
  709. if (!_stricmp(argument->parp->szArg, "force")) {
  710. // can add other values for the /FORCE option in future
  711. for (; iarpv < argument->parp->carpv; iarpv++) {
  712. szVal = argument->parp->rgarpv[iarpv].szVal;
  713. if (!_stricmp(szVal, "multiple")) {
  714. Switch.Link.Force = (FORCE_TYPE) (Switch.Link.Force | ftMultiple);
  715. } else if (!_stricmp(szVal, "unresolved")) {
  716. Switch.Link.Force = (FORCE_TYPE) (Switch.Link.Force | ftUnresolved);
  717. } else {
  718. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  719. }
  720. }
  721. if (Switch.Link.Force == ftNone) {
  722. // /FORCE was specfied without any values
  723. Switch.Link.Force = (FORCE_TYPE) (Switch.Link.Force | ftUnresolved | ftMultiple);
  724. }
  725. goto ProcessedArg;
  726. }
  727. if (!_stricmp(argument->OriginalName, "fixed")) {
  728. ImageFileHdr.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
  729. Switch.Link.fFixed = TRUE;
  730. goto ProcessedArg;
  731. }
  732. if (!_strnicmp(argument->OriginalName, "map", 3)) {
  733. Switch.Link.fMap = TRUE;
  734. if (argument->OriginalName[3] != '\0') {
  735. // require valid arg and set szInfoFilename
  736. if ((*(argument->OriginalName+3) == ':') &&
  737. (*(argument->OriginalName+4))) {
  738. szInfoFilename = argument->OriginalName+4;
  739. if (szReproDir != NULL) {
  740. _splitpath(szInfoFilename, NULL, NULL, szFname, szExt);
  741. FreePv(szReproOption);
  742. szReproOption = (char *)
  743. PvAlloc(strlen("map:\".\\%s%s\"")+strlen(szFname)+strlen(szExt));
  744. sprintf(szReproOption, "map:\".\\%s%s\"", szFname, szExt);
  745. }
  746. } else {
  747. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  748. }
  749. }
  750. SetOpt(SwitchInfo, OP_MAP);
  751. goto ProcessedAllVals;
  752. }
  753. #ifndef IMAGE_DLLCHARACTERISTICS_X86_THUNK
  754. #define IMAGE_DLLCHARACTERISTICS_X86_THUNK 0x0001 // Image is a Wx86 Thunk DLL
  755. #endif
  756. if (!_stricmp(argument->parp->szArg, "dllchar")) {
  757. if (!FGotVal(argument->parp, iarpv)) {
  758. goto MissingVal;
  759. }
  760. for (; iarpv < argument->parp->carpv; iarpv++) {
  761. szVal = argument->parp->rgarpv[iarpv].szVal;
  762. if (!_stricmp(szVal, "x86thunk")) {
  763. ImageOptionalHdr.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_X86_THUNK;
  764. } else {
  765. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  766. }
  767. }
  768. goto ProcessedAllVals;
  769. }
  770. if (!_strnicmp(argument->OriginalName, "dll", 3)) {
  771. ImageFileHdr.Characteristics |= IMAGE_FILE_DLL;
  772. fPowerMacBuildShared = TRUE;
  773. if (argument->OriginalName[3] == ':') {
  774. if (!_stricmp(argument->OriginalName+4, "system")) {
  775. ImageFileHdr.Characteristics |= IMAGE_FILE_SYSTEM;
  776. } else {
  777. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  778. }
  779. goto ProcessedAllVals;
  780. }
  781. if (argument->OriginalName[3] != '\0') {
  782. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  783. }
  784. goto ProcessedAllVals;
  785. }
  786. if (!_stricmp(argument->parp->szArg, "incremental")) {
  787. if (!FGotVal(argument->parp, iarpv)) {
  788. goto MissingVal;
  789. }
  790. for (; iarpv < argument->parp->carpv; iarpv++) {
  791. szVal = argument->parp->rgarpv[iarpv].szVal;
  792. if (_stricmp(szVal, "yes") == 0) {
  793. fIncrSwitchValue = TRUE;
  794. } else if (_stricmp(szVal, "no") == 0) {
  795. fIncrSwitchValue = FALSE;
  796. } else {
  797. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  798. }
  799. }
  800. fIncrSwitchUsed = TRUE;
  801. goto ProcessedArg;
  802. }
  803. if (!_stricmp(argument->OriginalName, "noentry")) {
  804. Switch.Link.fNoEntry = TRUE;
  805. goto ProcessedArg;
  806. }
  807. if (!_strnicmp(argument->OriginalName, "implib:", 7)) {
  808. ImplibFilename = &argument->OriginalName[7];
  809. goto ProcessedAllVals;
  810. }
  811. if (!_strnicmp(argument->OriginalName, "def:", 4)) {
  812. if (argument->OriginalName[4] != '\0') {
  813. DefFilename = &argument->OriginalName[4];
  814. if (szReproDir != NULL) {
  815. CopyFileToReproDir(DefFilename, FALSE);
  816. _splitpath(DefFilename, NULL, NULL, szFname, szExt);
  817. FreePv(szReproOption);
  818. szReproOption = (char *)
  819. PvAlloc(strlen("def:\".\\%s%s\"")+strlen(szFname)+strlen(szExt));
  820. sprintf(szReproOption, "def:\".\\%s%s\"", szFname, szExt);
  821. }
  822. }
  823. goto ProcessedAllVals;
  824. }
  825. if (!_strnicmp(argument->OriginalName, "include:", 8)) {
  826. PEXTERNAL pextInclude;
  827. PLEXT plext;
  828. SetOpt(SwitchInfo, OP_INCLUDE);
  829. name = argument->OriginalName+8;
  830. pextInclude = LookupExternSz(pst, name, NULL);
  831. // ilink: don't save directives (list not reqd. since TCE not done for ilink)
  832. if (!(fINCR && IsDirective)) {
  833. plext = (PLEXT) PvAlloc(sizeof(LEXT));
  834. plext->pext = pextInclude;
  835. plext->plextNext = SwitchInfo.plextIncludes;
  836. SwitchInfo.plextIncludes = plext;
  837. }
  838. // remember pmod that had the directive (used if pchsym isn't dfned)
  839. if (IsDirective) {
  840. assert(pcon);
  841. AddReferenceExt(pextInclude, PmodPCON(pcon));
  842. // ilink: keep the pext in the list of pexts referred to by this mod
  843. if (fINCR) {
  844. AddExtToModRefList(PmodPCON(pcon), pextInclude);
  845. }
  846. }
  847. goto ProcessedAllVals;
  848. }
  849. if (!_strnicmp(argument->OriginalName, "version:", 8)) {
  850. if (!_strnicmp(argument->OriginalName+8, "liborder=before,", 16)) {
  851. char *pchT;
  852. pchT = argument->OriginalName+24;
  853. for (;;) {
  854. char *pchComma;
  855. if ((pchComma = strchr(pchT, ',')) != NULL) {
  856. *pchComma = '\0';
  857. }
  858. if (PlibFind(pchT, pimage->libs.plibHead, TRUE)) {
  859. Warning(szFilename, BAD_LIBORDER, szFilename, pchT);
  860. }
  861. if (pchComma == NULL) {
  862. break;
  863. }
  864. *pchComma = ',';
  865. pchT = pchComma + 1;
  866. }
  867. goto ProcessedAllVals;
  868. }
  869. minor = 0;
  870. if ((p = strchr(argument->OriginalName+8, '.')) != NULL) {
  871. if ((sscanf(++p, "%li", &minor) != 1) || minor > 0xffff) {
  872. Warning(szFilename, INVALIDVERSIONSTAMP, argument->OriginalName+8);
  873. goto ProcessedAllVals;
  874. }
  875. SetOpt(SwitchInfo, OP_MINIMGVER);
  876. }
  877. if ((sscanf(argument->OriginalName+8, "%li", &major) != 1) || major > 0xffff) {
  878. Warning(szFilename, INVALIDVERSIONSTAMP, argument->OriginalName+8);
  879. goto ProcessedAllVals;
  880. }
  881. SetOpt(SwitchInfo, OP_MAJIMGVER);
  882. ImageOptionalHdr.MajorImageVersion = (WORD)major;
  883. ImageOptionalHdr.MinorImageVersion = (WORD)minor;
  884. goto ProcessedAllVals;
  885. }
  886. if (!_strnicmp(argument->OriginalName, "osversion:", 10)) {
  887. minor = 0;
  888. if ((p = strchr(argument->OriginalName+10, '.')) != NULL) {
  889. if ((sscanf(++p, "%li", &minor) != 1) || minor > 0xffff) {
  890. Warning(szFilename, INVALIDVERSIONSTAMP, argument->OriginalName+10);
  891. goto ProcessedAllVals;
  892. }
  893. SetOpt(SwitchInfo, OP_MINOSVER);
  894. }
  895. if ((sscanf(argument->OriginalName+10, "%li", &major) != 1) || major > 0xffff) {
  896. Warning(szFilename, INVALIDVERSIONSTAMP, argument->OriginalName+10);
  897. goto ProcessedAllVals;
  898. }
  899. SetOpt(SwitchInfo, OP_MAJOSVER);
  900. ImageOptionalHdr.MajorOperatingSystemVersion = (WORD) major;
  901. ImageOptionalHdr.MinorOperatingSystemVersion = (WORD) minor;
  902. goto ProcessedAllVals;
  903. }
  904. next = 0;
  905. if (!_strnicmp(argument->OriginalName, "subsystem:", 10)) {
  906. next = 10;
  907. if (!_strnicmp(argument->OriginalName+10, "native", 6)) {
  908. next += 6;
  909. ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_NATIVE;
  910. Switch.Link.fChecksum = TRUE; // Always checksum native images.
  911. } else if (!_strnicmp(argument->OriginalName+10, "windows", 7)) {
  912. next += 7;
  913. ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
  914. } else if (!_strnicmp(argument->OriginalName+10, "console", 7)) {
  915. next += 7;
  916. ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
  917. } else if (!_strnicmp(argument->OriginalName+10, "posix", 5)) {
  918. next += 5;
  919. ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_POSIX_CUI;
  920. } else if (!_strnicmp(argument->OriginalName+10, "mmosa", 5)) {
  921. next += 5;
  922. ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_MMOSA;
  923. } else if (argument->OriginalName[next] != ',') {
  924. Warning(szFilename, UNKNOWNSUBSYSTEM, argument->OriginalName+10);
  925. }
  926. SetOpt(SwitchInfo, OP_SUBSYSTEM);
  927. if (argument->OriginalName[next] == ',') {
  928. ++next;
  929. major = minor = 0;
  930. if ((p = strchr(argument->OriginalName+next, '.')) != NULL) {
  931. if ((sscanf(++p, "%li", &minor) != 1) || minor > 0xffff) {
  932. Warning(szFilename, INVALIDVERSIONSTAMP, argument->OriginalName+next);
  933. goto ProcessedAllVals;
  934. }
  935. }
  936. if ((sscanf(argument->OriginalName+next, "%li", &major) != 1) || major > 0xffff) {
  937. Warning(szFilename, INVALIDVERSIONSTAMP, argument->OriginalName+next);
  938. goto ProcessedAllVals;
  939. }
  940. if (((ImageOptionalHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
  941. (ImageOptionalHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) ||
  942. (ImageOptionalHdr.Subsystem == IMAGE_SUBSYSTEM_MMOSA)) &&
  943. ((major < 3) || ((major == 3) && (minor < 10)))) {
  944. Warning(szFilename, INVALIDVERSIONSTAMP, argument->OriginalName+next);
  945. goto ProcessedAllVals;
  946. }
  947. SetOpt(SwitchInfo, OP_SUBSYSVER);
  948. ImageOptionalHdr.MajorSubsystemVersion = (WORD)major;
  949. ImageOptionalHdr.MinorSubsystemVersion = (WORD)minor;
  950. }
  951. goto ProcessedAllVals;
  952. }
  953. if (!_stricmp(argument->parp->szArg, "stack")) {
  954. if (!FGotVal(argument->parp, iarpv)) {
  955. goto MissingVal;
  956. }
  957. // If the user used the stack switch, then ignore
  958. // any directive that sets the stack.
  959. if (Switch.Link.Stack && IsDirective) {
  960. iarpv = 2; // ignore 2 or fewer args
  961. goto ProcessedArg;
  962. }
  963. if (argument->parp->rgarpv[iarpv].szVal[0] != '\0' &&
  964. !FNumParp(argument->parp, iarpv,
  965. &ImageOptionalHdr.SizeOfStackReserve))
  966. {
  967. goto BadNum;
  968. }
  969. iarpv++;
  970. if (argument->parp->carpv >= 2 &&
  971. argument->parp->rgarpv[iarpv].szVal[0] != '\0' &&
  972. !FNumParp(argument->parp, iarpv,
  973. &ImageOptionalHdr.SizeOfStackCommit))
  974. {
  975. goto BadNum;
  976. }
  977. iarpv++;
  978. Switch.Link.Stack = TRUE;
  979. ImageOptionalHdr.SizeOfStackCommit =
  980. Align(sizeof(DWORD), ImageOptionalHdr.SizeOfStackCommit);
  981. ImageOptionalHdr.SizeOfStackReserve =
  982. Align(sizeof(DWORD), ImageOptionalHdr.SizeOfStackReserve);
  983. goto ProcessedArg;
  984. }
  985. if (!_stricmp(argument->parp->szArg, "heap")) {
  986. if (!FGotVal(argument->parp, iarpv)) {
  987. goto MissingVal;
  988. }
  989. // If the user used the heap switch, then ignore
  990. // any directive that sets the heap size.
  991. if (Switch.Link.Heap && IsDirective) {
  992. iarpv = 2; // ignore 2 or fewer args
  993. goto ProcessedArg;
  994. }
  995. if (argument->parp->rgarpv[iarpv].szVal[0] != '\0' &&
  996. !FNumParp(argument->parp, iarpv,
  997. &ImageOptionalHdr.SizeOfHeapReserve))
  998. {
  999. goto BadNum;
  1000. }
  1001. iarpv++;
  1002. if (argument->parp->carpv >= 2 &&
  1003. argument->parp->rgarpv[iarpv].szVal[1] != '\0' &&
  1004. !FNumParp(argument->parp, iarpv,
  1005. &ImageOptionalHdr.SizeOfHeapCommit))
  1006. {
  1007. goto BadNum;
  1008. }
  1009. iarpv++;
  1010. Switch.Link.Heap = TRUE;
  1011. ImageOptionalHdr.SizeOfHeapCommit =
  1012. Align(sizeof(DWORD), ImageOptionalHdr.SizeOfHeapCommit);
  1013. ImageOptionalHdr.SizeOfHeapReserve =
  1014. Align(sizeof(DWORD), ImageOptionalHdr.SizeOfHeapReserve);
  1015. if (ImageOptionalHdr.SizeOfHeapReserve <
  1016. ImageOptionalHdr.SizeOfHeapCommit)
  1017. {
  1018. // Reserve less than commit -- this causes NT to fail to load
  1019. // it, and it often happens when people use .def files left
  1020. // over from the 16-bit world, so we increase "reserve" to be
  1021. // the same as "commit".
  1022. ImageOptionalHdr.SizeOfHeapReserve =
  1023. ImageOptionalHdr.SizeOfHeapCommit;
  1024. }
  1025. goto ProcessedArg;
  1026. }
  1027. if (!_stricmp(argument->parp->szArg, "machine")) {
  1028. if (!FGotVal(argument->parp, iarpv)) {
  1029. goto MissingVal;
  1030. }
  1031. szVal = argument->parp->rgarpv[iarpv++].szVal;
  1032. if (!_stricmp(szVal, "I386") || !_stricmp(szVal, "IX86") || !_stricmp(szVal, "X86")) {
  1033. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_I386;
  1034. goto ProcessedArg;
  1035. }
  1036. if (!_stricmp(szVal, "MIPS")) {
  1037. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_R4000;
  1038. goto ProcessedArg;
  1039. }
  1040. if (!_stricmp(szVal, "MIPSR10")) {
  1041. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_R10000;
  1042. Switch.Link.fPadMipsCode = FALSE;
  1043. goto ProcessedArg;
  1044. }
  1045. if (!_stricmp(szVal, "ALPHA") || !_stricmp(szVal, "ALPHA_AXP")) {
  1046. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_ALPHA;
  1047. goto ProcessedArg;
  1048. }
  1049. if (!_stricmp(szVal, "PPC")) {
  1050. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_POWERPC;
  1051. goto ProcessedArg;
  1052. }
  1053. if (!_stricmp(szVal, "M68K")) {
  1054. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_M68K;
  1055. goto ProcessedArg;
  1056. }
  1057. if (!_stricmp(szVal, "MPPC")) {
  1058. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_MPPC_601;
  1059. fPowerMac = TRUE;
  1060. goto ProcessedArg;
  1061. }
  1062. Warning(szFilename, UNKNOWNRESPONSE, argument->OriginalName+8, "IX86, MIPS, ALPHA, PPC, M68K, or MPPC");
  1063. goto ProcessedArg;
  1064. }
  1065. if (!_stricmp(argument->parp->szArg, "align")) {
  1066. if (!FGotVal(argument->parp, iarpv)) {
  1067. goto MissingVal;
  1068. }
  1069. if (!FNumParp(argument->parp, iarpv++, &dwVal)) {
  1070. goto BadNum;
  1071. }
  1072. if (!dwVal || (dwVal & (dwVal - 1))) {
  1073. // Section alignment is not a power of 2
  1074. Warning(szFilename, BAD_ALIGN, dwVal);
  1075. goto ProcessedArg;
  1076. }
  1077. SetOpt(SwitchInfo, OP_ALIGN);
  1078. ImageOptionalHdr.SectionAlignment = dwVal;
  1079. goto ProcessedArg;
  1080. }
  1081. if (!_strnicmp(argument->OriginalName, "gpsize", 6)) {
  1082. if (!FGotVal(argument->parp, iarpv)) {
  1083. goto MissingVal;
  1084. }
  1085. if (!FNumParp(argument->parp, iarpv++, &dwVal)) {
  1086. goto BadNum;
  1087. }
  1088. SetOpt(SwitchInfo, OP_GPSIZE);
  1089. Switch.Link.GpSize = dwVal;
  1090. goto ProcessedArg;
  1091. }
  1092. if (!_strnicmp(argument->OriginalName, "section:", 8)) {
  1093. if (argument->OriginalName[8] == '\0') {
  1094. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1095. }
  1096. if (!IsDirective) {
  1097. SetOpt(SwitchInfo, OP_SECTION);
  1098. }
  1099. char *pb = _tcschr(argument->OriginalName+8, ',');
  1100. if (pb) {
  1101. size_t cch = pb - (argument->OriginalName+8);
  1102. char *szSecName = (char *) PvAlloc(cch + 1);
  1103. _tcsncpy(szSecName, argument->OriginalName+8, cch);
  1104. szSecName[cch] = '\0';
  1105. if (!FValidSecName(szSecName)) {
  1106. Fatal(szFilename, INVALIDSECNAME, szSecName, argument->OriginalName);
  1107. }
  1108. FreePv(szSecName);
  1109. }
  1110. AddArgument(&SectionNames, argument->OriginalName+8);
  1111. goto ProcessedAllVals;
  1112. }
  1113. if (!_strnicmp(argument->OriginalName, "verbose", 7)) {
  1114. // no arguments
  1115. if (!FGotVal(argument->parp, iarpv)) {
  1116. if (argument->OriginalName[7] != '\0') {
  1117. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1118. }
  1119. Verbose = TRUE;
  1120. fVerboseLib = TRUE;
  1121. goto ProcessedArg;
  1122. }
  1123. for (; iarpv < argument->parp->carpv; iarpv++) {
  1124. szVal = argument->parp->rgarpv[iarpv].szVal;
  1125. if (_stricmp(szVal, "lib") == 0) {
  1126. fVerboseLib = TRUE;
  1127. } else {
  1128. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1129. }
  1130. }
  1131. goto ProcessedArg;
  1132. }
  1133. if (!_stricmp(argument->OriginalName, "rom")) {
  1134. Switch.Link.fROM = TRUE;
  1135. Switch.Link.fPE = FALSE;
  1136. goto ProcessedArg;
  1137. }
  1138. if (!_strnicmp(argument->OriginalName, "stub:", 5)) {
  1139. if (argument->OriginalName[5] != '\0') {
  1140. FILE *StubFile;
  1141. LONG AlignedSize;
  1142. DWORD FileSize;
  1143. if (!(StubFile = fopen(argument->OriginalName+5, "rb"))) {
  1144. // Stub file not found using the specified path.
  1145. // If the path didn't specify a directory, try using the
  1146. // directory where the linker itself is.
  1147. char szDrive[_MAX_DRIVE];
  1148. char szDir[_MAX_DIR];
  1149. char szStubPath[_MAX_PATH];
  1150. _splitpath(argument->OriginalName+5,
  1151. szDrive, szDir, szFname, szExt);
  1152. if (szDrive[0] == '\0' && szDir[0] == '\0') {
  1153. _splitpath(_pgmptr, szDrive, szDir, NULL, NULL);
  1154. _makepath(szStubPath, szDrive, szDir, szFname, szExt);
  1155. StubFile = fopen(szStubPath, "rb");
  1156. }
  1157. }
  1158. if (StubFile == NULL) {
  1159. Fatal(szFilename, CANTOPENFILE, argument->OriginalName+5);
  1160. }
  1161. {
  1162. BYTE *pbDosHeader;
  1163. if ((FileSize = _filelength(_fileno(StubFile))) < 0) {
  1164. Fatal(szFilename, CANTREADFILE, argument->OriginalName+5);
  1165. }
  1166. // make sure the file is at least as large as a DOS header
  1167. if (FileSize < 0x40) {
  1168. Fatal(szFilename, BADSTUBFILE, argument->OriginalName+5);
  1169. }
  1170. if (pimage->imaget != imagetVXD) {
  1171. // Align the end to an 8 byte boundary
  1172. AlignedSize = Align(8, FileSize);
  1173. } else {
  1174. // 128-byte boundaries seem common for VxD stubs
  1175. AlignedSize = Align(0x80, FileSize);
  1176. }
  1177. pbDosHeader = (BYTE *) PvAlloc((size_t) AlignedSize + 4);
  1178. if (fread( pbDosHeader, 1, (size_t)FileSize, StubFile ) != FileSize) {
  1179. Fatal(szFilename, CANTREADFILE, argument->OriginalName+5);
  1180. }
  1181. fclose(StubFile);
  1182. // check for the MZ signature
  1183. if ((pbDosHeader[0] != 'M') || (pbDosHeader[1] != 'Z')) {
  1184. Fatal(szFilename, BADSTUBFILE, argument->OriginalName+5);
  1185. }
  1186. if (((PIMAGE_DOS_HEADER)pbDosHeader)->e_lfarlc < 0x40) {
  1187. // Ideally we would convert these to full headers
  1188. // but it's too late and I don't have the algorithm
  1189. // for doing it.
  1190. Warning(argument->OriginalName + 5, PARTIAL_DOS_HDR);
  1191. }
  1192. if (pimage->imaget != imagetVXD) {
  1193. // slam the PE00 at the end
  1194. pbDosHeader[AlignedSize] = 'P';
  1195. pbDosHeader[AlignedSize+1] = 'E';
  1196. pbDosHeader[AlignedSize+2] = '\0';
  1197. pbDosHeader[AlignedSize+3] = '\0';
  1198. }
  1199. // adjust the offset
  1200. *((LONG *)&pbDosHeader[0x3c]) = AlignedSize;
  1201. // set the global
  1202. pimage->pbDosHeader = pbDosHeader;
  1203. if (pimage->imaget != imagetVXD) {
  1204. pimage->cbDosHeader = AlignedSize + 4;
  1205. } else {
  1206. pimage->cbDosHeader = AlignedSize;
  1207. }
  1208. }
  1209. } else {
  1210. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1211. }
  1212. SetOpt(SwitchInfo, OP_STUB);
  1213. goto ProcessedAllVals;
  1214. }
  1215. if (!_strnicmp(argument->OriginalName, "order:@", 7)) {
  1216. Switch.Link.fOrder = TRUE;
  1217. OrderFilename = argument->OriginalName+7;
  1218. OrderInit();
  1219. if (szReproDir != NULL) {
  1220. CopyFileToReproDir(OrderFilename, FALSE);
  1221. _splitpath(OrderFilename, NULL, NULL, szFname, szExt);
  1222. FreePv(szReproOption);
  1223. szReproOption = (char *)
  1224. PvAlloc(strlen("order:@\".\\%s%s\"")+strlen(szFname)+strlen(szExt));
  1225. sprintf(szReproOption, "order:@\".\\%s%s\"", szFname, szExt);
  1226. }
  1227. goto ProcessedAllVals;
  1228. }
  1229. if (!_stricmp(argument->parp->szArg, "vxd")) {
  1230. if (IsDirective && (pimage->imaget != imagetVXD)) {
  1231. // UNDONE: Temporary error ... see comment in LinkerMain about /VXD
  1232. Fatal(szFilename, VXD_NEEDED);
  1233. }
  1234. // VXD implies MACHINE:IX86
  1235. ImageFileHdr.Machine = IMAGE_FILE_MACHINE_I386;
  1236. goto ProcessedArg;
  1237. }
  1238. if (!_strnicmp(argument->OriginalName, "ignore:", 7)) {
  1239. char *pMinus;
  1240. int range, last;
  1241. token = strtok(argument->OriginalName+7, ",");
  1242. while (token) {
  1243. if ((pMinus = strchr(token,'-')) != NULL) {
  1244. *pMinus = '\0';
  1245. last = atoi(pMinus+1);
  1246. for (range = atoi(token); range <= last; range++) {
  1247. DisableWarning(range);
  1248. }
  1249. }
  1250. else {
  1251. DisableWarning(atoi(token));
  1252. }
  1253. token = strtok(NULL,",");
  1254. }
  1255. goto ProcessedAllVals;
  1256. }
  1257. if (!_strnicmp(argument->OriginalName, "warn", 4)) {
  1258. char chWarn;
  1259. if (argument->OriginalName[4] == '\0') {
  1260. // no arg implies 2 (default is 1)
  1261. WarningLevel = 2;
  1262. goto ProcessedAllVals;
  1263. }
  1264. if ((argument->OriginalName[4] != ':') ||
  1265. ((chWarn = argument->OriginalName[5]) < '0') ||
  1266. (chWarn > '3') ||
  1267. (argument->OriginalName[6] != '\0')) {
  1268. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1269. }
  1270. WarningLevel = (WORD) (chWarn - '0');
  1271. goto ProcessedAllVals;
  1272. }
  1273. if (!_stricmp(argument->OriginalName, "verstamp")) {
  1274. // Undocumented switch used by the NT build
  1275. IbAppendBlk(&blkComment, szVersion, strlen(szVersion) + 1);
  1276. goto ProcessedAllVals;
  1277. }
  1278. if (!_stricmp(argument->OriginalName, "miscrdata")) {
  1279. // Undocumented switch used by the NT build
  1280. Switch.Link.fMiscInRData = TRUE;
  1281. goto ProcessedAllVals;
  1282. }
  1283. if (!_stricmp(argument->OriginalName, "optidata")) {
  1284. Switch.Link.fOptIdata = TRUE;
  1285. goto ProcessedAllVals;
  1286. }
  1287. if (!_strnicmp(argument->OriginalName, "driver", 6)) {
  1288. Switch.Link.fDriver = TRUE;
  1289. if (argument->OriginalName[6] != '\0') {
  1290. if (!_strnicmp(&argument->OriginalName[6], ":uponly", 7)) {
  1291. ImageFileHdr.Characteristics |= IMAGE_FILE_UP_SYSTEM_ONLY;
  1292. } else {
  1293. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1294. }
  1295. }
  1296. goto ProcessedAllVals;
  1297. }
  1298. if (!_stricmp(argument->OriginalName, "nopagecode")) {
  1299. Switch.Link.fNoPagedCode = TRUE;
  1300. Switch.Link.fPadMipsCode = FALSE;
  1301. goto ProcessedAllVals;
  1302. }
  1303. if (!_stricmp(argument->OriginalName, "nor4kworkarounds")) {
  1304. Switch.Link.fPadMipsCode = FALSE;
  1305. goto ProcessedAllVals;
  1306. }
  1307. if (!_strnicmp(argument->OriginalName, "swaprun:", 8)) {
  1308. if (argument->OriginalName[8] != '\0') {
  1309. if (!_strnicmp(&argument->OriginalName[8], "net", 3)) {
  1310. ImageFileHdr.Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP;
  1311. } else {
  1312. if (!_strnicmp(&argument->OriginalName[8], "cd", 2)) {
  1313. ImageFileHdr.Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;
  1314. } else {
  1315. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1316. }
  1317. }
  1318. } else {
  1319. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1320. }
  1321. goto ProcessedAllVals;
  1322. }
  1323. if (!_strnicmp(argument->OriginalName, "ws:", 3)) {
  1324. if (argument->OriginalName[3] != '\0') {
  1325. if (!_strnicmp(&argument->OriginalName[3], "aggressive", 10)) {
  1326. ImageFileHdr.Characteristics |= IMAGE_FILE_AGGRESIVE_WS_TRIM;
  1327. } else {
  1328. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1329. }
  1330. } else {
  1331. Fatal(szFilename, SWITCHSYNTAX, argument->OriginalName);
  1332. }
  1333. goto ProcessedAllVals;
  1334. }
  1335. // PowerMac
  1336. if (!_stricmp(argument->OriginalName, "shared")) {
  1337. fPowerMacBuildShared = TRUE;
  1338. goto ProcessedAllVals;
  1339. }
  1340. // Implementation for WEAK and regular import for PowerMac
  1341. if (!_stricmp(argument->parp->szArg, "import")) {
  1342. BOOL fWeakImport = FALSE;
  1343. BOOL fCustomGlue = FALSE;
  1344. char *szFuncName = NULL;
  1345. char *szContainerName = NULL;
  1346. char *szLocalCurrentVer = NULL;
  1347. char *szLocalOldCodeVer = NULL;
  1348. char *szLocalOldAPIVer = NULL;
  1349. if (!FGotVal(argument->parp, iarpv)) {
  1350. goto MissingVal;
  1351. }
  1352. for (; iarpv < argument->parp->carpv; iarpv++) {
  1353. char *szKey = argument->parp->rgarpv[iarpv].szKeyword;
  1354. szVal = argument->parp->rgarpv[iarpv].szVal;
  1355. if (szKey != NULL && !_stricmp(szKey, "lib")) {
  1356. if (!szContainerName) {
  1357. szContainerName = szVal;
  1358. continue;
  1359. } else {
  1360. // lib= has been mentioned twice
  1361. Fatal(szFilename, SWITCHSYNTAX, argument->parp->szArg);
  1362. }
  1363. } else if (szKey != NULL && !_stricmp(szKey, "weak")) {
  1364. fWeakImport = (!strcmp(szVal, "1")) ? TRUE : FALSE;
  1365. continue;
  1366. } else if (szKey != NULL && !_stricmp(szKey, "glue")) {
  1367. fCustomGlue = (!strcmp(szVal, "1")) ? TRUE : FALSE;
  1368. continue;
  1369. } else if (szKey != NULL && !_stricmp(szKey, "CURRENTVER")) {
  1370. if (_strspnp(szVal, "0123456789")) {
  1371. // Not appropriate number
  1372. Fatal(szFilename, SWITCHSYNTAX, argument->parp->szArg);
  1373. } else {
  1374. szLocalCurrentVer = szVal;
  1375. continue;
  1376. }
  1377. } else if (szKey != NULL && !_stricmp(szKey, "OLDCODEVER")) {
  1378. if (_strspnp(szVal, "0123456789")) {
  1379. // Not appropriate number
  1380. Fatal(szFilename, SWITCHSYNTAX, argument->parp->szArg);
  1381. } else {
  1382. szLocalOldCodeVer = szVal;
  1383. continue;
  1384. }
  1385. } else if (szKey != NULL && !_stricmp(szKey, "OLDAPIVER")) {
  1386. if (_strspnp(szVal, "0123456789")) {
  1387. // Not appropriate number
  1388. Fatal(szFilename, SWITCHSYNTAX, argument->parp->szArg);
  1389. } else {
  1390. szLocalOldAPIVer = szVal;
  1391. continue;
  1392. }
  1393. } else if (!szFuncName) {
  1394. szFuncName = szVal;
  1395. continue;
  1396. } else {
  1397. // At least two function names have been specified
  1398. Fatal(szFilename, SWITCHSYNTAX, argument->parp->szArg);
  1399. }
  1400. }
  1401. if (szLocalCurrentVer || szLocalOldCodeVer || szLocalOldAPIVer) {
  1402. AddVersionList(szContainerName, szLocalCurrentVer,
  1403. szLocalOldCodeVer, szLocalOldAPIVer);
  1404. }
  1405. if (fWeakImport) {
  1406. assert (fCustomGlue == FALSE);
  1407. if (szFuncName) {
  1408. // Add to Function list
  1409. AddArgument(&WeakImportsFunctionList, szFuncName);
  1410. } else if (szContainerName) {
  1411. // Add to Container list
  1412. AddArgument(&WeakImportsContainerList, szContainerName);
  1413. } else {
  1414. // Only WEAK attribute has been specified without function or container name
  1415. Fatal(szFilename, SWITCHSYNTAX, argument->parp->szArg);
  1416. }
  1417. }
  1418. if (szFuncName && (szContainerName || fCustomGlue)) {
  1419. char *szTempFuncName = (char *) PvAlloc(strlen(szFuncName) + 2);
  1420. if (*szFuncName != '?') {
  1421. // It is not a C++ function, but a C function
  1422. // So decorate it with an '_'
  1423. strcpy(szTempFuncName, "_");
  1424. strcat(szTempFuncName, szFuncName);
  1425. } else {
  1426. strcpy(szTempFuncName, szFuncName);
  1427. }
  1428. if (pcon) {
  1429. if (!AddCmdLineImport(szTempFuncName, szContainerName, pcon, pimage)) {
  1430. Warning(szFilename, MACIMPORTSYMBOLNOTFOUND, szFuncName);
  1431. }
  1432. } else {
  1433. // Add to Command Line Imports list
  1434. AddArgumentToList(&MppcImportList, szTempFuncName, szContainerName);
  1435. }
  1436. }
  1437. if (!szLocalCurrentVer && !szLocalOldCodeVer && !szLocalOldAPIVer && !fWeakImport &&
  1438. !(szFuncName && (szContainerName || fCustomGlue))) {
  1439. // Neither weak attribute nor (both function and container names) have been specified
  1440. // the version #s have not been specified either
  1441. Fatal(szFilename, SWITCHSYNTAX, argument->parp->szArg);
  1442. }
  1443. goto ProcessedAllVals;
  1444. }
  1445. if (!_stricmp(argument->OriginalName, "dbgimplib")) {
  1446. fDbgImpLib = TRUE;
  1447. goto ProcessedArg;
  1448. }
  1449. if (!_stricmp(argument->OriginalName, "newglue")) {
  1450. Switch.Link.fNewGlue = TRUE;
  1451. goto ProcessedArg;
  1452. }
  1453. if (!_stricmp(argument->OriginalName, "newrelocs")) {
  1454. Switch.Link.fNewRelocs = TRUE;
  1455. goto ProcessedArg;
  1456. }
  1457. #ifdef NT_BUILD
  1458. if (!_stricmp(argument->OriginalName, "calltree")) {
  1459. Switch.Link.fCallTree = TRUE;
  1460. // Force fixup debug
  1461. dtUser = (DEBUG_TYPE) (dtUser | FixupDebug);
  1462. goto ProcessedAllVals;
  1463. }
  1464. #endif
  1465. Warning(szFilename, WARN_UNKNOWN_SWITCH, argument->OriginalName);
  1466. continue;
  1467. MissingVal:
  1468. Fatal(szFilename, MISSING_SWITCH_VALUE, argument->OriginalName);
  1469. continue;
  1470. BadNum:
  1471. Fatal(szFilename, BAD_NUMBER, argument->OriginalName);
  1472. continue;
  1473. ProcessedArg:
  1474. if (argument->parp->carpv > iarpv) {
  1475. // There were extra values which were not processed by the
  1476. // option-specific handler, so give a warning.
  1477. Warning(szFilename, EXTRA_SWITCH_VALUE, argument->OriginalName);
  1478. }
  1479. ProcessedAllVals:; // ignores extra ... mainly used for handlers which
  1480. // haven't been updated to new scheme yet.
  1481. }
  1482. // set image base here since in some cases a DLL directive is seen
  1483. // after FPass1DefFile()
  1484. if (!Switch.Link.Base) {
  1485. // Set image base (to 1M) if not set by user in case of DLLs
  1486. ImageOptionalHdr.ImageBase = fDLL(pimage) ? 0x10000000 : 0x00400000;
  1487. }
  1488. #undef ImageFileHdr
  1489. #undef ImageOptionalHdr
  1490. #undef Switch
  1491. #undef SwitchInfo
  1492. }
  1493. void
  1494. CheckSwitchesForIncrementalLink(PIMAGE pimage)
  1495. {
  1496. #define Switch (pimage->Switch)
  1497. fINCR = fIncrSwitchValue;
  1498. if (pimage->imaget != imagetPE) {
  1499. // Turn off ilink for non-PE images (i.e. VXDs)
  1500. if (fINCR) {
  1501. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "VXD");
  1502. fINCR = FALSE;
  1503. }
  1504. return;
  1505. }
  1506. if (Switch.Link.fProfile) {
  1507. // Turn off ilink if user wants to profile
  1508. if (fINCR) {
  1509. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "PROFILE");
  1510. fINCR = FALSE;
  1511. }
  1512. Switch.Link.fMap = TRUE;
  1513. return;
  1514. }
  1515. if (fPdb && (dtUser != CvDebug) && (dtUser != 0) && (Switch.Link.DebugInfo != None)) {
  1516. if (fINCR) {
  1517. // Incremental link isn't supported if non-CV format debugging is requested
  1518. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "DEBUGTYPE");
  1519. fINCR = FALSE;
  1520. }
  1521. return;
  1522. }
  1523. if (!fIncrSwitchUsed) {
  1524. // Turn on ilink by default for debug builds
  1525. fINCR = (Switch.Link.DebugInfo != None);
  1526. }
  1527. if (!fINCR) {
  1528. return;
  1529. }
  1530. if (!fPdb && (Switch.Link.DebugInfo != None)) {
  1531. // Turn off ilink if /PDB:NONE & /DEBUG requested, can't handle debug info
  1532. if (fIncrSwitchUsed) {
  1533. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "PDB");
  1534. }
  1535. fINCR = FALSE;
  1536. return;
  1537. }
  1538. if (fExplicitOptRef && Switch.Link.fTCE) {
  1539. // Turn off ilink if tce was specified, interferes with ilink
  1540. if (fIncrSwitchUsed) {
  1541. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "OPT");
  1542. }
  1543. fINCR = FALSE;
  1544. return;
  1545. }
  1546. if (Switch.Link.fOrder) {
  1547. // Turn off ilink if /order was specified
  1548. if (fIncrSwitchUsed) {
  1549. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "ORDER");
  1550. }
  1551. fINCR = FALSE;
  1552. return;
  1553. }
  1554. if (Switch.Link.fMap) {
  1555. // Turn off ilink if /map was specified
  1556. if (fIncrSwitchUsed) {
  1557. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "MAP");
  1558. }
  1559. fINCR = FALSE;
  1560. return;
  1561. }
  1562. if (Switch.Link.fChecksum) {
  1563. // Turn off ilink if /release was specified
  1564. if (fIncrSwitchUsed) {
  1565. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "RELEASE");
  1566. }
  1567. fINCR = FALSE;
  1568. return;
  1569. }
  1570. if (Switch.Link.Force != ftNone) {
  1571. // Turn off ilink if /FORCE was specified
  1572. // (ILK/EXE del if mul/undef present & no FORCE)
  1573. if (fIncrSwitchUsed) {
  1574. Warning(NULL, SWITCH_IGNORED, "INCREMENTAL", "FORCE");
  1575. }
  1576. fINCR = FALSE;
  1577. return;
  1578. }
  1579. // Verify possible to ilink for the machine.
  1580. if (!FIncrementalLinkSupported(pimage)) {
  1581. if (fIncrSwitchUsed) {
  1582. // UNDONE: There should be a warning
  1583. }
  1584. fINCR = FALSE;
  1585. return;
  1586. }
  1587. #undef Switch
  1588. }
  1589. void
  1590. FlushWorkingSet(void)
  1591. {
  1592. HINSTANCE hInstKernel32;
  1593. BOOL (WINAPI *pfnSetProcessWorkingSetSize)(HANDLE, DWORD, DWORD);
  1594. hInstKernel32 = GetModuleHandle("KERNEL32.DLL");
  1595. if (hInstKernel32 == NULL) {
  1596. return;
  1597. }
  1598. // Get the address
  1599. pfnSetProcessWorkingSetSize = (BOOL (WINAPI *)(HANDLE, DWORD, DWORD))
  1600. GetProcAddress(hInstKernel32, "SetProcessWorkingSetSize");
  1601. if (pfnSetProcessWorkingSetSize == NULL) {
  1602. return;
  1603. }
  1604. // Set working set size
  1605. (*pfnSetProcessWorkingSetSize)(GetCurrentProcess(), 0xFFFFFFFF, 0xFFFFFFFF);
  1606. }
  1607. INT
  1608. SpawnFullBuildVXD(DWORD cbHeaderSize)
  1609. {
  1610. const char **newargv;
  1611. int i;
  1612. int rc;
  1613. char rgch[64];
  1614. // Cleanup a bit
  1615. FileCloseAll();
  1616. RemoveConvertTempFiles();
  1617. sprintf(rgch, "/hdrsize:0x%lX", cbHeaderSize);
  1618. fflush(NULL);
  1619. assert(savArgc);
  1620. assert(savArgv);
  1621. newargv = (const char **) PvAlloc((savArgc+3) * sizeof(const char *));
  1622. for (i = 0; i < savArgc; i++) {
  1623. newargv[i] = savArgv[i];
  1624. }
  1625. newargv[savArgc] = rgch;
  1626. newargv[savArgc+1] = "/nologo";
  1627. newargv[savArgc+2] = NULL;
  1628. FlushWorkingSet();
  1629. if ((rc = _spawnv(P_WAIT, _pgmptr, newargv)) == -1) {
  1630. Fatal(NULL, SPAWNFAILED, _pgmptr);
  1631. }
  1632. FreePv(newargv);
  1633. return(rc);
  1634. }
  1635. INT
  1636. SpawnFullBuild(BOOL fIncrBuild)
  1637. {
  1638. const char **newargv;
  1639. int rc;
  1640. fflush(NULL);
  1641. assert(savArgc);
  1642. assert(savArgv);
  1643. newargv = (const char **) PvAlloc((2+4) * sizeof(const char *));
  1644. char *szargv0 = (char *) PvAlloc(strlen(savArgv[0])+3);
  1645. sprintf(szargv0, "\"%s\"", savArgv[0]);
  1646. newargv[0] = szargv0;
  1647. // second arg will be the entire command string except for argv[0]
  1648. char *szCmdLine = GetCommandLine();
  1649. char ch = ' ';
  1650. if (*szCmdLine == '"') { // in case argv[o] is a lfn, then it is quoted
  1651. ch = '"';
  1652. szCmdLine++; // skip over leading quote
  1653. }
  1654. // skip over argv[0]. Assumes that there are no embedded quotes.
  1655. while (*szCmdLine != ch) {
  1656. szCmdLine++;
  1657. } // end while
  1658. if (*szCmdLine == '"') { // skip over closing quote if applicable
  1659. szCmdLine++;
  1660. }
  1661. assert(*szCmdLine == ' '); // gotta have the blank char
  1662. newargv[1] = ++szCmdLine;
  1663. if (fIncrBuild) {
  1664. newargv[2] = "/incremental:yes";
  1665. } else {
  1666. newargv[2] = "/incremental:no";
  1667. }
  1668. newargv[3] = "/nologo";
  1669. newargv[4] = "/fullbuild";
  1670. newargv[5] = NULL;
  1671. FlushWorkingSet();
  1672. if ((rc = _spawnv(P_WAIT, _pgmptr, newargv)) == -1) {
  1673. Fatal(NULL, SPAWNFAILED, _pgmptr);
  1674. }
  1675. FreePv(newargv);
  1676. FreePv(szargv0);
  1677. return(rc);
  1678. }
  1679. void
  1680. ResetLibsAndMods(PIMAGE pimage)
  1681. {
  1682. ENM_LIB enm_lib;
  1683. InitEnmLib(&enm_lib, pimage->libs.plibHead);
  1684. while (FNextEnmLib(&enm_lib)) {
  1685. ENM_MOD enm_mod;
  1686. InitEnmMod(&enm_mod, enm_lib.plib);
  1687. while (FNextEnmMod(&enm_mod)) {
  1688. enm_mod.pmod->rgci = NULL; // causes section headers to be reread
  1689. enm_mod.pmod->fInclude = FALSE; // sets up for next ilink
  1690. }
  1691. if (enm_lib.plib->flags & LIB_DontSearch) {
  1692. continue;
  1693. }
  1694. enm_lib.plib->rgszSym = NULL;
  1695. }
  1696. EndEnmLib(&enm_lib);
  1697. }
  1698. void
  1699. SaveImage(PIMAGE pimage)
  1700. {
  1701. // reset libs so that they are preprocessed on ilink
  1702. ResetLibsAndMods(pimage);
  1703. // save away imodidx
  1704. pimage->imodidx = imodidx;
  1705. // save away pmodlinkerdefined
  1706. pimage->pmodLinkerDefined = pmodLinkerDefined;
  1707. // save away pmod that defines the entrypoint on full build
  1708. if (!fIncrDbFile) {
  1709. pimage->pmodEntryPoint = (pextEntry && pextEntry->pcon) ?
  1710. PmodPCON(pextEntry->pcon) : NULL;
  1711. }
  1712. // reset symbol table for insertions
  1713. AllowInserts(pimage->pst);
  1714. if (psecDebug) {
  1715. // Need to reset the flags
  1716. psecDebug->flagsOrig &= ~IMAGE_SCN_LNK_REMOVE;
  1717. }
  1718. SaveEXEInfo(OutFilename, pimage);
  1719. WriteIncrDbFile(pimage);
  1720. DBEXEC(DB_DUMPIMAGE, DumpImage(pimage));
  1721. }
  1722. INT
  1723. CvPackExe(void)
  1724. /*++
  1725. Routine Description:
  1726. Packs the debug info in EXE.
  1727. Arguments:
  1728. None.
  1729. Return Value:
  1730. Return value of _spawnv[p](). 0 on success & !0 on failure.
  1731. --*/
  1732. {
  1733. const char *argv[4];
  1734. #if 1
  1735. char szOutArg[2+_MAX_PATH];
  1736. #endif
  1737. char szDrive[_MAX_DRIVE];
  1738. char szDir[_MAX_DIR];
  1739. char szCvpackPath[_MAX_PATH];
  1740. int rc;
  1741. fflush(NULL);
  1742. #if 1
  1743. strcpy(szOutArg, "\"");
  1744. strcat(szOutArg, OutFilename);
  1745. strcat(szOutArg, "\"");
  1746. #endif
  1747. argv[0] = "cvpack";
  1748. argv[1] = "/nologo";
  1749. #if 1
  1750. argv[2] = szOutArg;
  1751. #else
  1752. argv[2] = OutFilename;
  1753. #endif
  1754. argv[3] = NULL;
  1755. // Look for CVPACK.EXE in the directory from which we were loaded
  1756. _splitpath(_pgmptr, szDrive, szDir, NULL, NULL);
  1757. _makepath(szCvpackPath, szDrive, szDir, "cvpack", ".exe");
  1758. FlushWorkingSet();
  1759. rc = _spawnv(P_WAIT, szCvpackPath, argv);
  1760. if (rc == -1) {
  1761. // Run CVPACK.EXE from the path
  1762. rc = _spawnvp(P_WAIT, "cvpack.exe", argv);
  1763. }
  1764. return(rc);
  1765. }
  1766. MainFunc
  1767. LinkerMain(int Argc, char *Argv[])
  1768. /*++
  1769. Routine Description:
  1770. Linker entrypoint.
  1771. Arguments:
  1772. Argc - Standard C argument count.
  1773. Argv - Standard C argument strings.
  1774. Return Value:
  1775. 0 Link was successful.
  1776. !0 Linker error index.
  1777. --*/
  1778. {
  1779. #define ImageOptionalHdr (pimage->ImgOptHdr)
  1780. #define Switch (pimage->Switch)
  1781. PIMAGE pimage;
  1782. IMAGET imaget;
  1783. INT rc;
  1784. BOOL fCvpack;
  1785. #ifdef ILINKLOG
  1786. {
  1787. extern DWORD dwBegin;
  1788. dwBegin = GetTickCount();
  1789. }
  1790. #endif // ILINKLOG
  1791. if (Argc < 2) {
  1792. LinkerUsage();
  1793. }
  1794. CheckForReproDir();
  1795. #ifdef INSTRUMENT
  1796. Log = LogOpen();
  1797. LogNoteEvent(Log, SZILINK, NULL, letypeBegin, NULL);
  1798. #endif // INSTRUMENT
  1799. ParseCommandLine(Argc, Argv, "LINK");
  1800. // Scan the command line to determine the basic image type. This
  1801. // means that the "VXD" option in the .DEF file isn't adequate by
  1802. // itself. You still must specify /VXD on the linker command line.
  1803. imaget = FScanSwitches("vxd") ? imagetVXD : imagetPE;
  1804. // scan the command line to see if /nologo is specified;
  1805. // ProcessLinkerSwitches() can invoke PrintBanner()
  1806. fNeedBanner = FScanSwitches("nologo") ? FALSE : TRUE;
  1807. // Initialize EXE image; image created in memory as fINCR is FALSE
  1808. InitImage(&pimage, imaget);
  1809. ProcessLinkerSwitches(pimage, NULL, NULL);
  1810. // Set the debugtype.
  1811. Switch.Link.DebugType = dtUser;
  1812. if (Switch.Link.DebugType == NoDebug) {
  1813. // Default is CV debug
  1814. Switch.Link.DebugType = CvDebug;
  1815. }
  1816. if (Switch.Link.DebugType & (CoffDebug | CvDebug)) {
  1817. // Always turn on FPO and misc. info if other info is being generated.
  1818. Switch.Link.DebugType = (DEBUG_TYPE) (Switch.Link.DebugType | FpoDebug | MiscDebug);
  1819. }
  1820. if (pimage->imaget == imagetVXD) {
  1821. // VXDs can only support CV debug
  1822. // UNDONE: Issue a warning is user specified debug type is disabled?
  1823. Switch.Link.DebugType = (DEBUG_TYPE) (Switch.Link.DebugType & CvDebug);
  1824. if (!fPdb || IncludeDebugSection) {
  1825. // UNDONE: Issue a warning?
  1826. Switch.Link.DebugType = NoDebug;
  1827. }
  1828. // UNDONE: There is probably a better place for this.
  1829. ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_NATIVE;
  1830. }
  1831. if (Switch.Link.DebugInfo == None) {
  1832. Switch.Link.DebugType = NoDebug;
  1833. }
  1834. // Check switches to decide if linking incremental or not.
  1835. CheckSwitchesForIncrementalLink(pimage);
  1836. if ((Switch.Link.DebugType & CvDebug) == 0) {
  1837. // If there is no CodeView debug info, there is no use for a PDB.
  1838. fPdb = FALSE;
  1839. }
  1840. if ((ImageOptionalHdr.Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) && fDLL(pimage)) {
  1841. // Set the default subsystem for a DLL to WINDOWS_GUI
  1842. // UNDONE: Why? Better to do this with import lib or C runtime
  1843. ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
  1844. }
  1845. if (Switch.Link.fROM) {
  1846. // Never checksum ROM images
  1847. Switch.Link.fChecksum = FALSE;
  1848. }
  1849. if (fNeedBanner) {
  1850. PrintBanner();
  1851. }
  1852. savArgc = Argc;
  1853. savArgv = Argv;
  1854. if (fINCR) {
  1855. // Read in incr db file if possible
  1856. ReadIncrDbFile(&pimage);
  1857. if (fINCR) {
  1858. // Determine timestamps of all files if incr build is still on
  1859. DetermineTimeStamps();
  1860. }
  1861. }
  1862. if (!fExplicitOptRef) {
  1863. // -OPT:REF is the default for non-incremental non-debug links
  1864. Switch.Link.fTCE = !fINCR && (Switch.Link.DebugInfo == None);
  1865. }
  1866. if (fINCR && !fIncrDbFile && Switch.Link.fNotifyFullBuild && fTest) {
  1867. // Let user know that a full build has been kicked off
  1868. PostNote(NULL, FULLBUILD);
  1869. }
  1870. rc = -1;
  1871. if (fIncrDbFile) {
  1872. #ifdef ILINKLOG
  1873. wMachine = pimage->ImgFileHdr.Machine;
  1874. #endif // ILINKLOG
  1875. // Try an incremental link
  1876. rc = IncrBuildImage(&pimage);
  1877. if (rc == -1) {
  1878. // Incremental link failed, spawn a full link
  1879. return(SpawnFullBuild(TRUE));
  1880. }
  1881. }
  1882. if (!fINCR || (!fIncrDbFile && rc)) {
  1883. // Non incremental link OR a full ilink build (rc=0 after spawn)
  1884. rc = BuildImage(pimage, &fCvpack);
  1885. #ifdef ILINKLOG
  1886. wMachine = pimage->ImgFileHdr.Machine;
  1887. #endif // ILINKLOG
  1888. // If a full ilink save the image file
  1889. if (fINCR) {
  1890. SaveImage(pimage);
  1891. }
  1892. }
  1893. FileCloseAll();
  1894. RemoveConvertTempFiles();
  1895. if (fINCR) {
  1896. #ifdef INSTRUMENT
  1897. LogNoteEvent(Log, SZILINK, NULL, letypeEnd, NULL);
  1898. LogClose(Log);
  1899. #endif // INSTRUMENT
  1900. #ifdef ILINKLOG
  1901. IlinkLog((UINT)-1); // ilink success
  1902. #endif // ILINKLOG
  1903. if (fIncrDbFile) {
  1904. return(fTest ? 6 : 0);
  1905. }
  1906. return(0);
  1907. }
  1908. if (fCvpack) {
  1909. assert(rc == 0);
  1910. fflush(NULL);
  1911. if ((rc = CvPackExe()) != 0) {
  1912. Fatal(NULL, CVPACKERROR);
  1913. } else if (VerifyImageSize) {
  1914. FileReadHandle = FileOpen(OutFilename, O_RDONLY | O_BINARY, 0);
  1915. FileSeek(FileReadHandle, CoffHeaderSeek + sizeof(IMAGE_FILE_HEADER), SEEK_SET);
  1916. FileRead(FileReadHandle, &ImageOptionalHdr, pimage->ImgFileHdr.SizeOfOptionalHeader);
  1917. FileClose(FileReadHandle, TRUE);
  1918. }
  1919. }
  1920. if (VerifyImageSize && ImageOptionalHdr.SizeOfImage > VerifyImageSize) {
  1921. Warning(NULL, IMAGELARGERTHANKEY, ImageOptionalHdr.SizeOfImage, VerifyImageSize);
  1922. }
  1923. if (Switch.Link.fMap) {
  1924. EmitMap(pimage, OutFilename);
  1925. }
  1926. fclose(InfoStream);
  1927. if (szReproDir != NULL) {
  1928. CloseReproDir();
  1929. }
  1930. #ifdef INSTRUMENT
  1931. LogNoteEvent(Log, SZILINK, NULL, letypeEnd, NULL);
  1932. LogClose(Log);
  1933. #endif // INSTRUMENT
  1934. #ifdef ILINKLOG
  1935. IlinkLog((UINT)-1); // full link success
  1936. #endif // ILINKLOG
  1937. return(rc);
  1938. #undef ImageOptionalHdr
  1939. #undef Switch
  1940. }
  1941. void
  1942. BuildArgList (
  1943. PIMAGE pimage,
  1944. PCON pcon,
  1945. PNAME_LIST pnl,
  1946. char *Arguments
  1947. )
  1948. /*++
  1949. Routine Description:
  1950. Builds the list of args specified as a glob in the directives section.
  1951. Arguments:
  1952. pimage - ptr to image.
  1953. pmod - pmod that contained the directives.
  1954. pnl - ptr of list to add args to.
  1955. Arguments - A pointer to a string containing linker switches.
  1956. Return Value:
  1957. None.
  1958. --*/
  1959. {
  1960. PMOD pmod;
  1961. const char *szToken;
  1962. pmod = PmodPCON(pcon);
  1963. szToken = SzGetArgument(Arguments, NULL);
  1964. while (szToken) {
  1965. char c;
  1966. // Fetch first character of argument.
  1967. c = *szToken;
  1968. // If argument is a switch, then add it to
  1969. // the switch list (but don't include the switch character).
  1970. if (c == '/' || c == '-') {
  1971. char *szName;
  1972. if (szToken[1] == '?') {
  1973. szToken++;
  1974. }
  1975. szName = SzDup(szToken+1);
  1976. if (fINCR && !fIncrDbFile && !FIsLibPMOD(pmod)) {
  1977. // On full-links save all directives; currently no libs done
  1978. SaveDirectiveSz(szName, pimage->pstDirective, pmod);
  1979. }
  1980. AddArgument(pnl, szName);
  1981. }
  1982. szToken = SzGetArgument(NULL, NULL);
  1983. }
  1984. }
  1985. void
  1986. ApplyDirectives(
  1987. PIMAGE pimage,
  1988. PCON pcon,
  1989. char *Arguments
  1990. )
  1991. /*++
  1992. Routine Description:
  1993. Applys directives from object or library files in the form
  1994. of switches.
  1995. Arguments:
  1996. Arguments - A pointer to a string containing linker switches.
  1997. pst - external symbol table
  1998. Filename - name of the file that had the directives
  1999. pcon - pcon that is the .drectve section.
  2000. Return Value:
  2001. None.
  2002. --*/
  2003. {
  2004. char szComFileName[_MAX_PATH * 2];
  2005. SwitchArguments.First = SwitchArguments.Last = 0;
  2006. SwitchArguments.Count = 0;
  2007. BuildArgList(pimage, pcon, &SwitchArguments, Arguments);
  2008. SzComNamePMOD(PmodPCON(pcon), szComFileName);
  2009. ProcessLinkerSwitches(pimage, pcon, szComFileName);
  2010. }