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 | |
18 | WCHAR* 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 | |
29 | static DWORD g_dwSubsystem=(DWORD)-1,g_dwComImageFlags=(DWORD)-1,g_dwFileAlignment=0,g_dwTestRepeat=0; |
30 | static ULONGLONG g_stBaseAddress=0; |
31 | static size_t g_stSizeOfStackReserve=0; |
32 | extern unsigned int g_uConsoleCP; |
33 | #ifdef FEATURE_PAL |
34 | char * g_pszExeFile; |
35 | #endif |
36 | |
37 | void 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 | |
59 | void 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 | |
80 | char* 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 | |
92 | WCHAR *pwzInputFiles[1024]; |
93 | WCHAR *pwzDeltaFiles[1024]; |
94 | |
95 | char szInputFilename[MAX_FILENAME_LENGTH*3]; |
96 | WCHAR wzInputFilename[MAX_FILENAME_LENGTH]; |
97 | WCHAR 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 | |
105 | extern "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 bLogo = 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 |
910 | int 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 | |