1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// File: main.cpp
5//
6
7//
8
9#include "ilasmpch.h"
10
11#include "asmparse.h"
12#include "ndpversion.h"
13#include "shimload.h"
14
15#include "strsafe.h"
16#define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS(__FILE__, (expr))
17
18WCHAR* EqualOrColon(__in __nullterminated WCHAR* szArg)
19{
20 WCHAR* pchE = wcschr(szArg,L'=');
21 WCHAR* pchC = wcschr(szArg,L':');
22 WCHAR* ret;
23 if(pchE == NULL) ret = pchC;
24 else if(pchC == NULL) ret = pchE;
25 else ret = (pchE < pchC)? pchE : pchC;
26 return ret;
27}
28
29static DWORD g_dwSubsystem=(DWORD)-1,g_dwComImageFlags=(DWORD)-1,g_dwFileAlignment=0,g_dwTestRepeat=0;
30static ULONGLONG g_stBaseAddress=0;
31static size_t g_stSizeOfStackReserve=0;
32extern unsigned int g_uConsoleCP;
33#ifdef FEATURE_PAL
34char * g_pszExeFile;
35#endif
36
37void MakeTestFile(__in __nullterminated char* szFileName)
38{
39 if(g_dwTestRepeat)
40 {
41 FILE* pF = NULL;
42 if(fopen_s(&pF,szFileName,"wt")==0 && pF != NULL)
43 {
44 printf("Making test file\n");
45 fprintf(pF,".assembly extern mscorlib {}\n");
46 fprintf(pF,".assembly test%d {}\n",g_dwTestRepeat);
47 fprintf(pF,".module test%d.exe\n",g_dwTestRepeat);
48 fprintf(pF,".method public static void Exec() { .entrypoint\n");
49 for(unsigned i=0; i<g_dwTestRepeat*1000; i++)
50 {
51 fprintf(pF,"ldc.i4.1\ncall void [mscorlib]System.Console::WriteLine(int32)\n");
52 }
53 fprintf(pF,"ret }\n");
54 fclose(pF);
55 }
56 }
57}
58
59void MakeProperSourceFileName(__in __nullterminated WCHAR* wzOrigName,
60 unsigned uCodePage,
61 __out_ecount(MAX_FILENAME_LENGTH) WCHAR* wzProperName,
62 __out_ecount(MAX_FILENAME_LENGTH*3) char* szProperName)
63{
64 wcscpy_s(wzProperName,MAX_FILENAME_LENGTH, wzOrigName);
65 size_t j = wcslen(wzProperName);
66 do
67 {
68 j--;
69 if(wzProperName[j] == '.') break;
70 if((wzProperName[j] == '\\')||(j == 0))
71 {
72 wcscat_s(wzProperName,MAX_FILENAME_LENGTH,W(".il"));
73 break;
74 }
75 }
76 while(j);
77 WszWideCharToMultiByte(uCodePage,0,wzProperName,-1,szProperName,MAX_FILENAME_LENGTH*3-1,NULL,NULL);
78}
79
80char* FullFileName(__in __nullterminated WCHAR* wzFileName, unsigned uCodePage)
81{
82 static WCHAR wzFullPath[MAX_FILENAME_LENGTH];
83 WCHAR* pwz;
84 WszGetFullPathName(wzFileName,MAX_FILENAME_LENGTH,wzFullPath,&pwz);
85 char szFullPath[MAX_FILENAME_LENGTH*3];
86 WszWideCharToMultiByte(uCodePage,0,wzFullPath,-1,szFullPath,MAX_FILENAME_LENGTH*3-1,NULL,NULL);
87 char* sz = new char[strlen(szFullPath)+1];
88 if(sz) strcpy_s(sz,strlen(szFullPath)+1,szFullPath);
89 return sz;
90}
91
92WCHAR *pwzInputFiles[1024];
93WCHAR *pwzDeltaFiles[1024];
94
95char szInputFilename[MAX_FILENAME_LENGTH*3];
96WCHAR wzInputFilename[MAX_FILENAME_LENGTH];
97WCHAR wzOutputFilename[MAX_FILENAME_LENGTH];
98
99
100#ifdef _PREFAST_
101#pragma warning(push)
102#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
103#endif
104
105extern "C" int _cdecl wmain(int argc, __in WCHAR **argv)
106{
107 int i, NumFiles = 0, NumDeltaFiles = 0;
108 bool IsDLL = false, IsOBJ = false;
109 Assembler *pAsm;
110 MappedFileStream *pIn;
111 AsmParse *pParser;
112 int exitval=1;
113 bool = TRUE;
114 bool bReportProgress = TRUE;
115 BOOL bNoDebug = TRUE;
116 WCHAR* wzIncludePath = NULL;
117 int exitcode = 0;
118 unsigned uCodePage;
119
120 bool bClock = false;
121 Clockwork cw;
122
123 // SWI has requested that the exact form of the function call below be used. For details
124 // see http://swi/SWI%20Docs/Detecting%20Heap%20Corruption.doc
125 (void)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
126
127 memset(pwzInputFiles,0,1024*sizeof(WCHAR*));
128 memset(pwzDeltaFiles,0,1024*sizeof(WCHAR*));
129 memset(&cw,0,sizeof(Clockwork));
130 cw.cBegin = GetTickCount();
131
132 g_uConsoleCP = GetConsoleOutputCP();
133 memset(wzOutputFilename,0,sizeof(wzOutputFilename));
134
135#ifdef _DEBUG
136 DisableThrowCheck();
137 //CONTRACT_VIOLATION(ThrowsViolation);
138#endif
139
140 if(argc < 2) goto ErrorExit;
141#ifdef _PREFAST_
142#pragma warning(push)
143#pragma warning(disable:26000) // "Suppress prefast warning about index overflow"
144#endif
145 if (! wcscmp(argv[1], W("/?")) || ! wcscmp(argv[1],W("-?")))
146#ifdef _PREFAST_
147#pragma warning(pop)
148#endif
149 {
150 printf("\nMicrosoft (R) .NET Framework IL Assembler version " VER_FILEVERSION_STR);
151 printf("\n%S\n\n", VER_LEGALCOPYRIGHT_LOGO_STR_L);
152 goto PrintUsageAndExit;
153
154 ErrorExit:
155 exitcode = 1;
156 PrintUsageAndExit:
157 printf("\n\nUsage: ilasm [Options] <sourcefile> [Options]");
158 printf("\n\nOptions:");
159 printf("\n/NOLOGO Don't type the logo");
160 printf("\n/QUIET Don't report assembly progress");
161 printf("\n/NOAUTOINHERIT Disable inheriting from System.Object by default");
162 printf("\n/DLL Compile to .dll");
163 printf("\n/EXE Compile to .exe (default)");
164 printf("\n/PDB Create the PDB file without enabling debug info tracking");
165 printf("\n/APPCONTAINER Create an AppContainer exe or dll");
166 printf("\n/DEBUG Disable JIT optimization, create PDB file, use sequence points from PDB");
167 printf("\n/DEBUG=IMPL Disable JIT optimization, create PDB file, use implicit sequence points");
168 printf("\n/DEBUG=OPT Enable JIT optimization, create PDB file, use implicit sequence points");
169 printf("\n/OPTIMIZE Optimize long instructions to short");
170 printf("\n/FOLD Fold the identical method bodies into one");
171 printf("\n/CLOCK Measure and report compilation times");
172// printf("\n/ERROR Try to create .exe or .dll file despite errors reported");
173// printf("\n Warning! Results are unpredictable, use this option at your own risk!");
174 printf("\n/OUTPUT=<targetfile> Compile to file with specified name \n\t\t\t(user must provide extension, if any)");
175 printf("\n/KEY=<keyfile> Compile with strong signature \n\t\t\t(<keyfile> contains private key)");
176 printf("\n/KEY=@<keysource> Compile with strong signature \n\t\t\t(<keysource> is the private key source name)");
177 printf("\n/INCLUDE=<path> Set path to search for #include'd files");
178 printf("\n/SUBSYSTEM=<int> Set Subsystem value in the NT Optional header");
179 printf("\n/SSVER=<int>.<int> Set Subsystem version number in the NT Optional header");
180 printf("\n/FLAGS=<int> Set CLR ImageFlags value in the CLR header");
181 printf("\n/ALIGNMENT=<int> Set FileAlignment value in the NT Optional header");
182 printf("\n/BASE=<int> Set ImageBase value in the NT Optional header (max 2GB for 32-bit images)");
183 printf("\n/STACK=<int> Set SizeOfStackReserve value in the NT Optional header");
184 printf("\n/MDV=<version_string> Set Metadata version string");
185 printf("\n/MSV=<int>.<int> Set Metadata stream version (<major>.<minor>)");
186 printf("\n/PE64 Create a 64bit image (PE32+)");
187 printf("\n/HIGHENTROPYVA Set High Entropy Virtual Address capable PE32+ images (default for /APPCONTAINER)");
188 printf("\n/NOCORSTUB Suppress generation of CORExeMain stub");
189 printf("\n/STRIPRELOC Indicate that no base relocations are needed");
190 printf("\n/X64 Target processor: 64bit AMD processor");
191 printf("\n/ARM Target processor: ARM (AArch32) processor");
192 printf("\n/ARM64 Target processor: ARM64 (AArch64) processor");
193 printf("\n/32BITPREFERRED Create a 32BitPreferred image (PE32)");
194 printf("\n/ENC=<file> Create Edit-and-Continue deltas from specified source file");
195
196 printf("\n\nKey may be '-' or '/'\nOptions are recognized by first 3 characters (except ARM/ARM64)\nDefault source file extension is .il\n");
197
198 printf("\nTarget defaults:");
199 printf("\n/PE64 => /PE64 /X64");
200 printf("\n/X64 => /PE64 /X64");
201 printf("\n/ARM64 => /PE64 /ARM64");
202
203 printf("\n\n");
204 exit(exitcode);
205 }
206
207 uCodePage = CP_UTF8;
208 WszSetEnvironmentVariable(W("COMP_ENC_OPENSCOPE"), W(""));
209 WszSetEnvironmentVariable(W("COMP_ENC_EMIT"), W(""));
210 if((pAsm = new Assembler()))
211 {
212 pAsm->SetCodePage(uCodePage);
213 //if(pAsm->Init())
214 {
215 pAsm->SetStdMapping(1);
216 //-------------------------------------------------
217 for (i = 1; i < argc; i++)
218 {
219#ifdef FEATURE_PAL
220 if(argv[i][0] == L'-')
221#else
222 if((argv[i][0] == L'/') || (argv[i][0] == L'-'))
223#endif
224 {
225 char szOpt[3 + 1] = { 0 };
226 WszWideCharToMultiByte(uCodePage, 0, &argv[i][1], 3, szOpt, sizeof(szOpt), NULL, NULL);
227 if (!_stricmp(szOpt, "NOA"))
228 {
229 pAsm->m_fAutoInheritFromObject = FALSE;
230 }
231 else if (!_stricmp(szOpt, "QUI"))
232 {
233 pAsm->m_fReportProgress = FALSE;
234 bReportProgress = FALSE;
235 bLogo = FALSE;
236 }
237 else if (!_stricmp(szOpt, "NOL"))
238 {
239 bLogo = FALSE;
240 }
241 else if (!_stricmp(szOpt, "FOL"))
242 {
243 pAsm->m_fFoldCode = TRUE;
244 }
245 else if (!_stricmp(szOpt, "DEB"))
246 {
247 pAsm->m_dwIncludeDebugInfo = 0x101;
248 // PDB is ignored under 'DEB' option for ilasm on CoreCLR.
249 // https://github.com/dotnet/coreclr/issues/2982
250 bNoDebug = FALSE;
251
252 WCHAR *pStr = EqualOrColon(argv[i]);
253 if(pStr != NULL)
254 {
255 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
256 if(wcslen(pStr)==0) goto InvalidOption; //if no suboption
257 else
258 {
259 WCHAR wzSubOpt[8];
260 wcsncpy_s(wzSubOpt,8,pStr,3);
261 wzSubOpt[3] = 0;
262 if(0 == _wcsicmp(wzSubOpt,W("OPT")))
263 pAsm->m_dwIncludeDebugInfo = 0x3;
264 else if(0 == _wcsicmp(wzSubOpt,W("IMP")))
265 pAsm->m_dwIncludeDebugInfo = 0x103;
266 else
267 {
268 const WCHAR *pFmt =((*pStr == '0')&&(*(pStr+1) == 'x'))? W("%lx") : W("%ld");
269 if(swscanf_s(pStr,pFmt,&(pAsm->m_dwIncludeDebugInfo))!=1)
270 goto InvalidOption; // bad subooption
271 }
272 }
273 }
274 }
275 else if (!_stricmp(szOpt, "PDB"))
276 {
277 // 'PDB' option is ignored for ilasm on CoreCLR.
278 // https://github.com/dotnet/coreclr/issues/2982
279 bNoDebug = FALSE;
280 }
281 else if (!_stricmp(szOpt, "CLO"))
282 {
283 bClock = true;
284 pAsm->SetClock(&cw);
285 }
286 else if (!_stricmp(szOpt, "DLL"))
287 {
288 IsDLL = true; IsOBJ = false;
289 }
290 else if (!_stricmp(szOpt, "OBJ"))
291 {
292 //IsOBJ = true; IsDLL = false;
293 printf("Option /OBJECT is not supported.\n");
294 goto ErrorExit;
295 }
296 else if (!_stricmp(szOpt, "ERR"))
297 {
298 pAsm->OnErrGo = true;
299 }
300 else if (!_stricmp(szOpt, "EXE"))
301 {
302 IsDLL = false;
303 }
304 else if (!_stricmp(szOpt, "APP"))
305 {
306 pAsm->m_fAppContainer = TRUE;
307 }
308 else if (!_stricmp(szOpt, "HIG"))
309 {
310 pAsm->m_fHighEntropyVA = TRUE;
311 }
312 else if (!_stricmp(szOpt, "OPT"))
313 {
314 pAsm->m_fOptimize = TRUE;
315 }
316 else if (!_stricmp(szOpt, "X64"))
317 {
318 pAsm->m_dwCeeFileFlags &= ~ICEE_CREATE_MACHINE_MASK;
319 pAsm->m_dwCeeFileFlags |= ICEE_CREATE_MACHINE_AMD64;
320 }
321 else if (!_stricmp(szOpt, "ARM"))
322 {
323 // szOpt is only 3 characters long. That is not enough to distinguish "ARM" and "ARM64".
324 // We could change it to be longer, but that would affect the existing usability (ARM64 was
325 // added much later). Thus, just distinguish the two here.
326 char szOpt2[5 + 1] = { 0 };
327 WszWideCharToMultiByte(uCodePage, 0, &argv[i][1], 5, szOpt2, sizeof(szOpt2), NULL, NULL);
328 if (!_stricmp(szOpt2, "ARM"))
329 {
330 pAsm->m_dwCeeFileFlags &= ~ICEE_CREATE_MACHINE_MASK;
331 pAsm->m_dwCeeFileFlags |= ICEE_CREATE_MACHINE_ARM;
332 }
333 else if (!_stricmp(szOpt2, "ARM64"))
334 {
335 pAsm->m_dwCeeFileFlags &= ~ICEE_CREATE_MACHINE_MASK;
336 pAsm->m_dwCeeFileFlags |= ICEE_CREATE_MACHINE_ARM64;
337 }
338 else
339 {
340 goto InvalidOption;
341 }
342 }
343 else if (!_stricmp(szOpt, "32B"))
344 {
345 if (g_dwComImageFlags == (DWORD)-1)
346 g_dwComImageFlags = pAsm->m_dwComImageFlags;
347 COR_SET_32BIT_PREFERRED(g_dwComImageFlags);
348 }
349 else if (!_stricmp(szOpt, "PE6"))
350 {
351 pAsm->m_dwCeeFileFlags &= ~ICEE_CREATE_FILE_PE32;
352 pAsm->m_dwCeeFileFlags |= ICEE_CREATE_FILE_PE64;
353 }
354 else if (!_stricmp(szOpt, "NOC"))
355 {
356 pAsm->m_dwCeeFileFlags &= ~ICEE_CREATE_FILE_CORMAIN_STUB;
357 }
358 else if (!_stricmp(szOpt, "STR"))
359 {
360 pAsm->m_dwCeeFileFlags |= ICEE_CREATE_FILE_STRIP_RELOCS;
361 }
362 else if (!_stricmp(szOpt, "OPT"))
363 {
364 pAsm->m_fOptimize = TRUE;
365 }
366 else if (!_stricmp(szOpt, "LIS"))
367 {
368 printf("Option /LISTING is not supported, use ILDASM.EXE\n");
369 }
370 else if (!_stricmp(szOpt, "RES"))
371 {
372 if(pAsm->m_wzResourceFile==NULL)
373 {
374 WCHAR *pStr = EqualOrColon(argv[i]);
375 if(pStr == NULL) goto ErrorExit;
376 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
377 if(wcslen(pStr)==0) goto InvalidOption; //if no file name
378 pAsm->m_wzResourceFile = pStr;
379 }
380 else
381 printf("Multiple resource files not allowed. Option %ls skipped\n",argv[i]);
382 }
383 else if (!_stricmp(szOpt, "KEY"))
384 {
385 WCHAR *pStr = EqualOrColon(argv[i]);
386 if(pStr == NULL) goto InvalidOption;
387 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
388 if(wcslen(pStr)==0) goto InvalidOption; //if no file name
389 pAsm->m_wzKeySourceName = pStr;
390 }
391 else if (!_stricmp(szOpt, "INC"))
392 {
393 WCHAR *pStr = EqualOrColon(argv[i]);
394 if(pStr == NULL) goto InvalidOption;
395 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
396 if(wcslen(pStr)==0) goto InvalidOption; //if no file name
397 wzIncludePath = pStr;
398 }
399 else if (!_stricmp(szOpt, "OUT"))
400 {
401 WCHAR *pStr = EqualOrColon(argv[i]);
402 if(pStr == NULL) goto InvalidOption;
403 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
404 if(wcslen(pStr)==0) goto InvalidOption; //if no file name
405 if(wcslen(pStr) >= MAX_FILENAME_LENGTH)
406 {
407 fprintf(stderr,"\nError: Output file name exceeds %d characters\n",MAX_FILENAME_LENGTH-1);
408 goto ErrorExit;
409 }
410 wcscpy_s(wzOutputFilename,MAX_FILENAME_LENGTH,pStr);
411 }
412 else if (!_stricmp(szOpt, "MDV"))
413 {
414 WCHAR *pStr = EqualOrColon(argv[i]);
415 if(pStr == NULL) goto InvalidOption;
416 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
417 if(wcslen(pStr)==0) goto InvalidOption; //if no version string
418 pAsm->m_wzMetadataVersion = pStr;
419 }
420 else if (!_stricmp(szOpt, "MSV"))
421 {
422 WCHAR *pStr = EqualOrColon(argv[i]);
423 if(pStr == NULL) goto InvalidOption;
424 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
425 if(wcslen(pStr)==0) goto InvalidOption; //if no version
426 {
427 int major=-1,minor=-1;
428 if(swscanf_s(pStr,W("%d.%d"),&major, &minor)==2)
429 {
430 if((major >= 0)&&(major < 0xFF))
431 pAsm->m_wMSVmajor = (WORD)major;
432 if((minor >= 0)&&(minor < 0xFF))
433 pAsm->m_wMSVminor = (WORD)minor;
434 }
435 }
436 }
437 else if (!_stricmp(szOpt, "ENC"))
438 {
439 WCHAR *pStr = EqualOrColon(argv[i]);
440 if(pStr == NULL) goto InvalidOption;
441 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
442 if(wcslen(pStr)==0) goto InvalidOption; //if no file name
443 pwzDeltaFiles[NumDeltaFiles++] = pStr;
444 pAsm->m_fTolerateDupMethods = TRUE;
445 }
446 else if (!_stricmp(szOpt, "SUB"))
447 {
448 WCHAR *pStr = EqualOrColon(argv[i]);
449 if(pStr == NULL) goto InvalidOption;
450 pStr++;
451 const WCHAR *pFmt = ((*pStr=='0')&&(*(pStr+1) == 'x'))? W("%lx") : W("%ld");
452 if(swscanf_s(pStr,pFmt,&g_dwSubsystem)!=1) goto InvalidOption;
453 }
454 else if (!_stricmp(szOpt, "SSV"))
455 {
456 WCHAR *pStr = EqualOrColon(argv[i]);
457 if(pStr == NULL) goto InvalidOption;
458 for(pStr++; *pStr == L' '; pStr++); //skip the blanks
459 if(wcslen(pStr)==0) goto InvalidOption; //if no version
460 {
461 int major=-1,minor=-1;
462 if(swscanf_s(pStr,W("%d.%d"),&major, &minor)==2)
463 {
464 if((major >= 0)&&(major < 0xFFFF))
465 pAsm->m_wSSVersionMajor = (WORD)major;
466 if((minor >= 0)&&(minor < 0xFFFF))
467 pAsm->m_wSSVersionMinor = (WORD)minor;
468 } else
469 goto InvalidOption;
470 }
471 }
472 else if (!_stricmp(szOpt, "ALI"))
473 {
474 WCHAR *pStr = EqualOrColon(argv[i]);
475 if(pStr == NULL) goto InvalidOption;
476 pStr++;
477 const WCHAR *pFmt = ((*pStr=='0')&&(*(pStr+1) == 'x'))? W("%lx") : W("%ld");
478 if(swscanf_s(pStr,pFmt,&g_dwFileAlignment)!=1) goto InvalidOption;
479 if((g_dwFileAlignment & (g_dwFileAlignment-1))
480 || (g_dwFileAlignment < 0x200) || (g_dwFileAlignment > 0x10000))
481 {
482 fprintf(stderr,"\nFile Alignment must be power of 2 from 0x200 to 0x10000\n");
483 if(!pAsm->OnErrGo) goto InvalidOption;
484 }
485 }
486 else if (!_stricmp(szOpt, "FLA"))
487 {
488 WCHAR *pStr = EqualOrColon(argv[i]);
489 if(pStr == NULL) goto InvalidOption;
490 pStr++;
491 const WCHAR *pFmt = ((*pStr=='0')&&(*(pStr+1) == 'x'))? W("%lx") : W("%ld");
492 if(swscanf_s(pStr,pFmt,&g_dwComImageFlags)!=1) goto InvalidOption;
493 }
494 else if (!_stricmp(szOpt, "BAS"))
495 {
496 WCHAR *pStr = EqualOrColon(argv[i]);
497 if(pStr == NULL) goto InvalidOption;
498 pStr++;
499 const WCHAR *pFmt = ((*pStr=='0')&&(*(pStr+1) == 'x'))? W("%I64x") : W("%I64d");
500 if(swscanf_s(pStr,pFmt,&g_stBaseAddress)!=1) goto InvalidOption;
501 if(g_stBaseAddress & 0xFFFF)
502 {
503 fprintf(stderr,"\nBase address must be 0x10000-aligned\n");
504 if(!pAsm->OnErrGo) goto InvalidOption;
505 }
506 }
507 else if (!_stricmp(szOpt, "STA"))
508 {
509 WCHAR *pStr = EqualOrColon(argv[i]);
510 if(pStr == NULL) goto InvalidOption;
511 pStr++;
512 const WCHAR *pFmt = ((*pStr=='0')&&(*(pStr+1) == 'x'))? W("%lx") : W("%ld");
513 if(swscanf_s(pStr,pFmt,&g_stSizeOfStackReserve)!=1) goto InvalidOption;
514 }
515#ifdef _SPECIAL_INTERNAL_USE_ONLY
516 else if (!_stricmp(szOpt, "TES"))
517 {
518 WCHAR *pStr = EqualOrColon(argv[i]);
519 if(pStr == NULL) goto InvalidOption;
520 pStr++;
521 WCHAR *pFmt = ((*pStr=='0')&&(*(pStr+1) == 'x'))? L"%lx" : L"%ld";
522 if(swscanf_s(pStr,pFmt,&g_dwTestRepeat)!=1) goto InvalidOption;
523 }
524#endif
525 else
526 {
527 InvalidOption:
528 fprintf(stderr, "Error : Invalid Option: %LS\n", argv[i]);
529 goto ErrorExit;
530 }
531 }
532 else
533 {
534 if(wcslen(argv[i]) >= MAX_FILENAME_LENGTH)
535 {
536 printf("\nError: Input file name exceeds %d characters\n",MAX_FILENAME_LENGTH-1);
537 goto ErrorExit;
538 }
539 pwzInputFiles[NumFiles++] = argv[i];
540 if(NumFiles == 1)
541 {
542 MakeProperSourceFileName(argv[i], uCodePage, wzInputFilename, szInputFilename);
543 }
544 }
545
546 }
547 if(NumFiles == 0)
548 {
549 delete pAsm;
550 goto ErrorExit;
551 }
552 if(pAsm->m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64)
553 {
554 if((pAsm->m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386)
555 ||(pAsm->m_dwCeeFileFlags & ICEE_CREATE_MACHINE_ARM))
556 {
557 printf("\nMachine type /ARM64 or /X64 must be specified for 64 bit targets.");
558 if(!pAsm->OnErrGo)
559 {
560 pAsm->m_dwCeeFileFlags &= ~ICEE_CREATE_MACHINE_MASK;
561 pAsm->m_dwCeeFileFlags |= ICEE_CREATE_MACHINE_AMD64;
562 printf(" Type set to X64.");
563 }
564 printf("\n");
565 }
566 }
567 else
568 {
569 if((pAsm->m_dwCeeFileFlags & ICEE_CREATE_MACHINE_ARM64)
570 ||(pAsm->m_dwCeeFileFlags & ICEE_CREATE_MACHINE_AMD64))
571 {
572 printf("\n64 bit target must be specified for machine type /ARM64 or /X64.");
573 if(!pAsm->OnErrGo)
574 {
575 pAsm->m_dwCeeFileFlags &= ~ICEE_CREATE_FILE_PE32;
576 pAsm->m_dwCeeFileFlags |= ICEE_CREATE_FILE_PE64;
577 printf(" Target set to 64 bit.");
578 }
579 printf("\n");
580 }
581 }
582 if(pAsm->m_dwCeeFileFlags & ICEE_CREATE_FILE_PE32)
583 {
584 if(g_stBaseAddress > 0x80000000)
585 {
586 fprintf(stderr,"Invalid Image Base specified for 32-bit target\n");
587 delete pAsm;
588 goto ErrorExit;
589 }
590 }
591 if (COR_IS_32BIT_PREFERRED(pAsm->m_dwComImageFlags) &&
592 ((pAsm->m_dwCeeFileFlags & ICEE_CREATE_FILE_PE64) ||
593 ((pAsm->m_dwCeeFileFlags & ICEE_CREATE_FILE_PE32) == 0) ||
594 ((pAsm->m_dwCeeFileFlags & ICEE_CREATE_MACHINE_I386) == 0) ||
595 ((pAsm->m_dwComImageFlags & COMIMAGE_FLAGS_ILONLY) == 0)))
596 {
597 fprintf(stderr,"/32BITPREFERRED valid only with PE32/X86/ILONLY images\n");
598 delete pAsm;
599 goto ErrorExit;
600 }
601 if(!pAsm->Init())
602 {
603 fprintf(stderr,"Failed to initialize Assembler\n");
604 delete pAsm;
605 goto ErrorExit;
606 }
607 if(g_dwTestRepeat)
608 MakeTestFile(szInputFilename);
609
610 if(wzOutputFilename[0] == 0)
611 {
612 wcscpy_s(wzOutputFilename,MAX_FILENAME_LENGTH,pwzInputFiles[0]);
613 size_t j = wcslen(wzOutputFilename);
614 do
615 {
616 j--;
617 if(wzOutputFilename[j] == L'.')
618 {
619 wzOutputFilename[j] = 0;
620 break;
621 }
622 }
623 while(j);
624 wcscat_s(wzOutputFilename, MAX_FILENAME_LENGTH,(IsDLL ? W(".dll") : (IsOBJ ? W(".obj") : W(".exe"))));
625 }
626 if(wzIncludePath == NULL)
627 {
628 PathString wzIncludePathBuffer;
629 if (0 != WszGetEnvironmentVariable(W("ILASM_INCLUDE"), wzIncludePathBuffer))
630 {
631 wzIncludePath = wzIncludePathBuffer.GetCopyOfUnicodeString();
632
633 }
634 }
635 //------------ Assembler initialization done. Now, to business -----------------------
636 if((pParser = new AsmParse(NULL, pAsm)))
637 {
638 uCodePage = CP_UTF8;
639 pAsm->SetCodePage(uCodePage);
640 pParser->SetIncludePath(wzIncludePath);
641 //======================================================================
642 if(bLogo)
643 {
644 printf("\nMicrosoft (R) .NET Framework IL Assembler. Version " VER_FILEVERSION_STR);
645 printf("\n%S", VER_LEGALCOPYRIGHT_LOGO_STR_L);
646 }
647
648 pAsm->SetDLL(IsDLL);
649 pAsm->SetOBJ(IsOBJ);
650 wcscpy_s(pAsm->m_wzOutputFileName,MAX_FILENAME_LENGTH,wzOutputFilename);
651 strcpy_s(pAsm->m_szSourceFileName,MAX_FILENAME_LENGTH*3+1,szInputFilename);
652
653 if (SUCCEEDED(pAsm->InitMetaData()))
654 {
655 int iFile;
656 BOOL fAllFilesPresent = TRUE;
657 if(bClock) cw.cParsBegin = GetTickCount();
658 for(iFile = 0; iFile < NumFiles; iFile++)
659 {
660 uCodePage = CP_UTF8;
661 pAsm->SetCodePage(uCodePage);
662 if(iFile) // for the first file, it's already done
663 {
664 MakeProperSourceFileName(pwzInputFiles[iFile], uCodePage, wzInputFilename, szInputFilename);
665 }
666 if(pAsm->m_fReportProgress)
667 {
668 pParser->msg("\nAssembling '%s' ", szInputFilename);
669 if(pAsm->m_fCPlusPlus) pParser->msg(" C++");
670 if(pAsm->m_fWindowsCE) pParser->msg(" WINCE");
671 if(!pAsm->m_fAutoInheritFromObject) pParser->msg(" NOAUTOINHERIT");
672 pParser->msg(IsDLL ? " to DLL" : (IsOBJ? " to OBJ" : " to EXE"));
673 //======================================================================
674 if (pAsm->m_fStdMapping == FALSE)
675 pParser->msg(", with REFERENCE mapping");
676
677 {
678 char szOutputFilename[MAX_FILENAME_LENGTH*3];
679 memset(szOutputFilename,0,sizeof(szOutputFilename));
680 WszWideCharToMultiByte(uCodePage,0,wzOutputFilename,-1,szOutputFilename,MAX_FILENAME_LENGTH*3-1,NULL,NULL);
681 pParser->msg(" --> '%s'\n", szOutputFilename);
682 }
683 }
684
685 pIn = new MappedFileStream(wzInputFilename);
686
687 if ((!pIn) || !(pIn->IsValid()))
688 {
689 pParser->msg("Could not open %s\n", szInputFilename);
690 fAllFilesPresent = FALSE;
691 }
692 else
693 {
694#ifndef FEATURE_PAL
695 DWORD dwBinType;
696 if(GetBinaryTypeA(szInputFilename,&dwBinType))
697 {
698 pParser->msg("%s is not a text file\n",szInputFilename);
699 fAllFilesPresent = FALSE;
700 }
701 else
702#endif
703 {
704 pAsm->SetSourceFileName(FullFileName(wzInputFilename,uCodePage)); // deletes the argument!
705
706 pParser->ParseFile(pIn);
707 }
708 }
709 if(pIn)
710 {
711 pIn->set_namew(NULL);
712 delete pIn;
713 }
714 } // end for(iFile)
715 if(bClock) cw.cParsEnd = GetTickCount();
716 if ((pParser->Success() && fAllFilesPresent) || pAsm->OnErrGo)
717 {
718 HRESULT hr;
719 if(g_dwSubsystem != (DWORD)-1) pAsm->m_dwSubsystem = g_dwSubsystem;
720 if(g_dwComImageFlags != (DWORD)-1) pAsm->m_dwComImageFlags = g_dwComImageFlags;
721 if(g_dwFileAlignment) pAsm->m_dwFileAlignment = g_dwFileAlignment;
722 if(g_stBaseAddress) pAsm->m_stBaseAddress = g_stBaseAddress;
723 if(g_stSizeOfStackReserve) pAsm->m_stSizeOfStackReserve = g_stSizeOfStackReserve;
724 if(FAILED(hr=pAsm->CreatePEFile(wzOutputFilename)))
725 pParser->msg("Could not create output file, error code=0x%08X\n",hr);
726 else
727 {
728 if(pAsm->m_fFoldCode && pAsm->m_fReportProgress)
729 pParser->msg("%d methods folded\n",pAsm->m_dwMethodsFolded);
730 if(pParser->Success() && fAllFilesPresent) exitval = 0;
731 else
732 {
733 pParser->msg("Output file contains errors\n");
734 if(pAsm->OnErrGo) exitval = 0;
735 }
736 if(exitval == 0) // Write the output file
737 {
738 if(bClock) cw.cFilegenEnd = GetTickCount();
739 if(pAsm->m_fReportProgress) pParser->msg("Writing %s file\n", pAsm->m_fOBJ ? "COFF" : "PE");
740 // Generate the file
741 if (FAILED(hr = pAsm->m_pCeeFileGen->GenerateCeeFile(pAsm->m_pCeeFile)))
742 {
743 exitval = 1;
744 pParser->msg("Failed to write output file, error code=0x%08X\n",hr);
745 }
746 if(bClock) cw.cEnd = GetTickCount();
747#define ENC_ENABLED
748 if(exitval==0)
749 {
750 pAsm->m_fENCMode = TRUE;
751 WCHAR wzNewOutputFilename[MAX_FILENAME_LENGTH+16];
752 for(iFile = 0; iFile < NumDeltaFiles; iFile++)
753 {
754 wcscpy_s(wzNewOutputFilename,MAX_FILENAME_LENGTH+16,wzOutputFilename);
755 exitval = _snwprintf_s(&wzNewOutputFilename[wcslen(wzNewOutputFilename)], 32, _TRUNCATE,
756 W(".%d"),iFile+1);
757 MakeProperSourceFileName(pwzDeltaFiles[iFile], uCodePage, wzInputFilename, szInputFilename);
758 if(pAsm->m_fReportProgress)
759 {
760 pParser->msg("\nAssembling delta '%s' ", szInputFilename);
761 if(pAsm->m_fCPlusPlus) pParser->msg(" C++");
762 if(pAsm->m_fWindowsCE) pParser->msg(" WINCE");
763 if(!pAsm->m_fAutoInheritFromObject) pParser->msg(" NOAUTOINHERIT");
764 pParser->msg(" to DMETA,DIL");
765 //======================================================================
766 if (pAsm->m_fStdMapping == FALSE)
767 pParser->msg(", with REFERENCE mapping");
768
769 pParser->msg(" --> '%S.*'\n", wzNewOutputFilename);
770 }
771 exitval = 0;
772 pIn = new MappedFileStream(wzInputFilename);
773
774 if ((!pIn) || !(pIn->IsValid()))
775 {
776 pParser->msg("Could not open %s\n", szInputFilename);
777 fAllFilesPresent = FALSE;
778 }
779 else
780 {
781#ifndef FEATURE_PAL
782 DWORD dwBinType;
783 if(GetBinaryTypeA(szInputFilename,&dwBinType))
784 {
785 pParser->msg("%s is not a text file\n",szInputFilename);
786 fAllFilesPresent = FALSE;
787 }
788 else
789#endif
790 if (SUCCEEDED(pAsm->InitMetaDataForENC(wzNewOutputFilename)))
791 {
792 pAsm->SetSourceFileName(FullFileName(wzInputFilename,uCodePage)); // deletes the argument!
793
794 pParser->ParseFile(pIn);
795 if (pParser->Success() || pAsm->OnErrGo)
796 {
797 exitval = 1;
798 if(FAILED(hr=pAsm->CreateDeltaFiles(wzNewOutputFilename)))
799 pParser->msg("Could not create output delta files, error code=0x%08X\n",hr);
800 else
801 {
802 if(pAsm->m_fFoldCode && pAsm->m_fReportProgress)
803 pParser->msg("%d methods folded\n",pAsm->m_dwMethodsFolded);
804 if(pParser->Success()) exitval = 0;
805 else pParser->msg("Output delta files contain errors\n");
806
807#ifdef GENERATE_SUMMARY_PE_FILE
808 if(pAsm->OnErrGo) exitval = 0;
809
810 //if(FAILED(hr=pAsm->CreatePEFile(wzOutputFilename)))
811 // pParser->msg("Could not create output file, error code=0x%08X\n",hr);
812 //else
813 {
814 if(pAsm->m_fReportProgress) pParser->msg("Writing %s file\n", pAsm->m_fOBJ ? "COFF" : "PE");
815 // Generate the file
816 if (FAILED(hr = pAsm->m_pCeeFileGen->GenerateCeeFile(pAsm->m_pCeeFile)))
817 {
818 exitval = 1;
819 pParser->msg("Failed to write output file, error code=0x%08X\n",hr);
820 }
821 else if (pAsm->m_pManifest->m_sStrongName.m_fFullSign)
822 {
823 // Strong name sign the resultant assembly.
824 if(pAsm->m_fReportProgress) pParser->msg("Signing file with strong name\n");
825 if (FAILED(hr=pAsm->StrongNameSign()))
826 {
827 exitval = 1;
828 pParser->msg("Failed to strong name sign output file, error code=0x%08X\n",hr);
829 }
830 }
831 }
832#endif
833 }
834 } // end if (pParser->Success() || pAsm->OnErrGo)
835 } //end if (SUCCEEDED(pAsm->InitMetaDataForENC()))
836 } // end if ((!pIn) || !(pIn->IsValid())) -- else
837 if(pIn)
838 {
839 pIn->set_namew(NULL);
840 delete pIn;
841 }
842 } // end for(iFile)
843 } // end if(exitval==0)
844 }
845
846 }
847 }
848 }
849 else pParser->msg("Failed to initialize Meta Data\n");
850 delete pParser;
851 }
852 else printf("Could not create parser\n");
853 }
854 //else printf("Failed to initialize Assembler\n");
855 delete pAsm;
856 }
857 else printf("Insufficient memory\n");
858
859 WszSetEnvironmentVariable(W("COMP_ENC_OPENSCOPE"), W(""));
860 WszSetEnvironmentVariable(W("COMP_ENC_EMIT"), W(""));
861
862 if(exitval || bNoDebug)
863 {
864 // PE file was not created, or no debug info required. Kill PDB if any
865 WCHAR* pc = wcsrchr(wzOutputFilename,L'.');
866 if(pc==NULL)
867 {
868 pc = &wzOutputFilename[wcslen(wzOutputFilename)];
869 *pc = L'.';
870 }
871 wcscpy_s(pc+1,4,W("PDB"));
872#undef DeleteFileW
873 DeleteFileW(wzOutputFilename);
874 }
875 if (exitval == 0)
876 {
877 if(bReportProgress) printf("Operation completed successfully\n");
878 if(bClock)
879 {
880 printf("Timing (msec): Total run %d\n",(cw.cEnd-cw.cBegin));
881 printf(" Startup %d\n",(cw.cParsBegin-cw.cBegin));
882 printf(" - MD initialization %d\n",(cw.cMDInitEnd - cw.cMDInitBegin));
883 printf(" Parsing %d\n",(cw.cParsEnd - cw.cParsBegin));
884 printf(" Emitting MD %d\n",(cw.cMDEmitEnd - cw.cRef2DefEnd)+(cw.cRef2DefBegin - cw.cMDEmitBegin));
885 //printf(" - global fixups %d\n",(cw.cMDEmit1 - cw.cMDEmitBegin));
886 printf(" - SN sig alloc %d\n",(cw.cMDEmit2 - cw.cMDEmitBegin));
887 printf(" - Classes,Methods,Fields %d\n",(cw.cRef2DefBegin - cw.cMDEmit2));
888 printf(" - Events,Properties %d\n",(cw.cMDEmit3 - cw.cRef2DefEnd));
889 printf(" - MethodImpls %d\n",(cw.cMDEmit4 - cw.cMDEmit3));
890 printf(" - Manifest,CAs %d\n",(cw.cMDEmitEnd - cw.cMDEmit4));
891 printf(" Ref to Def resolution %d\n",(cw.cRef2DefEnd - cw.cRef2DefBegin));
892 printf(" Fixup and linking %d\n",(cw.cFilegenBegin - cw.cMDEmitEnd));
893 printf(" CEE file generation %d\n",(cw.cFilegenEnd - cw.cFilegenBegin));
894 printf(" PE file writing %d\n",(cw.cEnd - cw.cFilegenEnd));
895 }
896 }
897 else
898 {
899 printf("\n***** FAILURE ***** \n");
900 }
901 exit(exitval);
902 return exitval;
903}
904#ifdef _PREFAST_
905#pragma warning(pop)
906#endif
907
908
909#ifdef FEATURE_PAL
910int main(int argc, char* str[])
911{
912 g_pszExeFile = str[0];
913 if (0 != PAL_Initialize(argc, str))
914 {
915 fprintf(stderr,"Error: Fail to PAL_Initialize\n");
916 exit(1);
917 }
918
919 WCHAR **argv = new WCHAR*[argc];
920 for (int i = 0; i < argc; i++) {
921 int length = MultiByteToWideChar(CP_ACP, 0, str[i], -1, NULL, 0);
922 ASSERTE_ALL_BUILDS(length != 0);
923
924 LPWSTR result = new (nothrow) WCHAR[length];
925 ASSERTE_ALL_BUILDS(result != NULL);
926
927 length = MultiByteToWideChar(CP_ACP, 0, str[i], -1, result, length);
928 ASSERTE_ALL_BUILDS (length != 0);
929
930 argv[i] = result;
931 }
932
933 int ret = wmain(argc, argv);
934
935 for (int i = 0 ; i < argc; i++) {
936 delete[] argv[i];
937 }
938 delete[] argv;
939
940 return ret;
941}
942#endif // FEATURE_PAL
943
944