[netcore] Remove local copy of static alc resolve methods
[mono-project.git] / mcs / class / PEAPI / PEAPI.cs
bloba52bf41960a2cf78711cd2fc44e5bb1b77a85df2
1 using System;
2 using System.IO;
3 using System.Collections;
4 using System.Text;
6 namespace PEAPI {
8 /**************************************************************************/
9 /// <summary>
10 /// Image for a PEFile
11 /// File Structure
12 /// DOS Header (128 bytes)
13 /// PE Signature ("PE\0\0")
14 /// PEFileHeader (20 bytes)
15 /// PEOptionalHeader (224 bytes)
16 /// SectionHeaders (40 bytes * NumSections)
17 ///
18 /// Sections .text (always present - contains metadata)
19 /// .sdata (contains any initialised data in the file - may not be present)
20 /// (for ilams /debug this contains the Debug table)
21 /// .reloc (always present - in pure CIL only has one fixup)
22 /// others??? c# produces .rsrc section containing a Resource Table
23 ///
24 /// .text layout
25 /// IAT (single entry 8 bytes for pure CIL)
26 /// CLIHeader (72 bytes)
27 /// CIL instructions for all methods (variable size)
28 /// MetaData
29 /// Root (20 bytes + UTF-8 Version String + quad align padding)
30 /// StreamHeaders (8 bytes + null terminated name string + quad align padding)
31 /// Streams
32 /// #~ (always present - holds metadata tables)
33 /// #Strings (always present - holds identifier strings)
34 /// #US (Userstring heap)
35 /// #Blob (signature blobs)
36 /// #GUID (guids for assemblies or Modules)
37 /// ImportTable (40 bytes)
38 /// ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
39 /// Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
40 /// ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
41 /// Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
42 ///
43 /// #~ stream structure
44 /// Header (24 bytes)
45 /// Rows (4 bytes * numTables)
46 /// Tables
47 /// </summary>
48 internal class FileImage : BinaryWriter {
50 internal readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
51 internal readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
52 0x0000000000FF0000, 0x00000000FF000000,
53 0x000000FF00000000, 0x0000FF0000000000,
54 0x00FF000000000000, 0xFF00000000000000 };
55 internal readonly static uint nibble0Mask = 0x0000000F;
56 internal readonly static uint nibble1Mask = 0x000000F0;
58 private static readonly byte[] DOSHeader = { 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,
59 0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,
60 0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
61 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
62 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
63 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
64 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
65 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
66 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,
67 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
68 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,
69 0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
70 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,
71 0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
72 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,
73 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
74 0x50,0x45,0x00,0x00};
75 private static byte[] PEHeader = { 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0xE0, 0x00, 0x0E, 0x01, // PE Header Standard Fields
78 0x0B, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
83 private static readonly uint minFileAlign = 0x200;
84 private static readonly uint maxFileAlign = 0x1000;
85 private static readonly uint fileHeaderSize = 0x178;
86 private static readonly uint sectionHeaderSize = 40;
87 private static readonly uint SectionAlignment = 0x2000;
88 private static readonly uint ImageBase = 0x400000;
89 private static readonly uint ImportTableSize = 40;
90 private static readonly uint IATSize = 8;
91 private static readonly uint CLIHeaderSize = 72;
92 private uint runtimeFlags = 0x01; // COMIMAGE_FLAGS_ILONLY
93 // 32BITREQUIRED 0x02, STRONGNAMESIGNED 0x08, TRACKDEBUGDATA 0x10000
94 private static readonly uint StrongNameSignatureSize = 128;
95 private bool reserveStrongNameSignatureSpace = false;
97 private static readonly uint relocFlags = 0x42000040;
98 private static readonly ushort exeCharacteristics = 0x010E;
99 private static readonly ushort dllCharacteristics = 0x210E;
100 // section names are all 8 bytes
101 private static readonly string textName = ".text\0\0\0";
102 private static readonly string sdataName = ".sdata\0\0";
103 private static readonly string relocName = ".reloc\0\0";
104 private static readonly string rsrcName = ".rsrc\0\0\0";
105 private static readonly string exeHintNameTable = "\0\0_CorExeMain\0";
106 private static readonly string dllHintNameTable = "\0\0_CorDllMain\0";
107 private static readonly string runtimeEngineName = "mscoree.dll\0\0";
109 private Section text, sdata;
110 static readonly Section rsrc = null;
111 ArrayList data;
112 BinaryWriter reloc = new BinaryWriter(new MemoryStream());
113 uint dateStamp = 0;
114 DateTime origin = new DateTime(1970,1,1);
115 uint numSections = 2; // always have .text and .reloc sections
116 internal SubSystem subSys = SubSystem.Windows_CUI; // default is Windows Console mode
117 internal long stackReserve = 0x100000; // default is 1Mb
118 internal uint fileAlign = minFileAlign;
119 uint entryPointOffset, entryPointPadding, imageSize, headerSize, headerPadding, entryPointToken = 0;
120 uint relocOffset, relocRVA, relocSize, relocPadding, relocTide, hintNameTableOffset;
121 uint metaDataOffset, runtimeEngineOffset, initDataSize = 0, importTablePadding;
122 uint resourcesSize, resourcesOffset;
123 uint strongNameSigOffset;
124 uint importTableOffset, importLookupTableOffset, totalImportTableSize;
125 MetaData metaData;
126 char[] runtimeEngine = runtimeEngineName.ToCharArray(), hintNameTable;
127 bool doDLL, largeStrings, largeGUID, largeUS, largeBlob;
128 ushort characteristics;
130 internal FileImage(bool makeDLL, string fileName) : base(new FileStream(fileName,FileMode.Create))
132 InitFileImage(makeDLL);
133 TimeSpan tmp = System.IO.File.GetCreationTime(fileName).Subtract(origin);
134 dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
137 internal FileImage(bool makeDLL, Stream str) : base(str)
139 InitFileImage(makeDLL);
140 TimeSpan tmp = DateTime.Now.Subtract(origin);
141 dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
144 private void InitFileImage(bool makeDLL)
146 doDLL = makeDLL;
147 if (doDLL) {
148 hintNameTable = dllHintNameTable.ToCharArray();
149 characteristics = dllCharacteristics;
150 } else {
151 hintNameTable = exeHintNameTable.ToCharArray();
152 characteristics = exeCharacteristics;
154 text = new Section(textName,0x60000020); // IMAGE_SCN_CNT CODE, EXECUTE, READ
155 // rsrc = new Section(rsrcName,0x40000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ
156 metaData = new MetaData(this);
159 internal MetaData GetMetaData()
161 return metaData;
164 private uint GetNextSectStart(uint rva, uint tide)
166 uint c = tide / SectionAlignment;
167 if ((tide % SectionAlignment) != 0)
168 c++;
169 return rva + (c * SectionAlignment);
172 private void BuildTextSection()
174 // .text layout
175 // IAT (single entry 8 bytes for pure CIL)
176 // CLIHeader (72 bytes)
177 // CIL instructions for all methods (variable size)
178 // MetaData
179 // ImportTable (40 bytes)
180 // ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
181 // Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
182 // ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
183 // Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
184 metaData.BuildMetaData(IATSize + CLIHeaderSize);
185 metaDataOffset = IATSize + CLIHeaderSize;
186 // Console.WriteLine("Code starts at " + metaDataOffset);
187 metaDataOffset += metaData.CodeSize();
188 // resourcesStart =
189 resourcesOffset = metaDataOffset + metaData.Size ();
190 resourcesSize = metaData.GetResourcesSize ();
191 if (reserveStrongNameSignatureSpace) {
192 strongNameSigOffset = resourcesOffset + resourcesSize;
193 // fixUps = RVA for vtable
194 importTableOffset = strongNameSigOffset + StrongNameSignatureSize;
195 } else {
196 strongNameSigOffset = 0;
197 // fixUps = RVA for vtable
198 importTableOffset = resourcesOffset + resourcesSize;
200 importTablePadding = NumToAlign(importTableOffset,16);
201 importTableOffset += importTablePadding;
202 importLookupTableOffset = importTableOffset + ImportTableSize;
203 hintNameTableOffset = importLookupTableOffset + IATSize;
204 runtimeEngineOffset = hintNameTableOffset + (uint)hintNameTable.Length;
205 entryPointOffset = runtimeEngineOffset + (uint)runtimeEngine.Length;
206 totalImportTableSize = entryPointOffset - importTableOffset;
207 // Console.WriteLine("total import table size = " + totalImportTableSize);
208 // Console.WriteLine("entrypoint offset = " + entryPointOffset);
209 entryPointPadding = NumToAlign(entryPointOffset,4) + 2;
210 entryPointOffset += entryPointPadding;
211 text.AddReloc(entryPointOffset+2);
212 text.IncTide(entryPointOffset + 6);
213 //if (text.Tide() < fileAlign) fileAlign = minFileAlign;
214 text.SetSize(NumToAlign(text.Tide(),fileAlign));
215 // Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
216 // Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
217 // Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
218 // Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
219 // Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
220 // Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
221 // Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
222 // Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
226 internal void BuildRelocSection()
228 text.DoRelocs(reloc);
229 if (sdata != null) sdata.DoRelocs(reloc);
230 if (rsrc != null) rsrc.DoRelocs(reloc);
231 relocTide = (uint)reloc.Seek(0,SeekOrigin.Current);
232 relocPadding = NumToAlign(relocTide,fileAlign);
233 relocSize = relocTide + relocPadding;
234 imageSize = relocRVA + SectionAlignment;
235 initDataSize += relocSize;
238 private void CalcOffsets()
240 if (sdata != null)
241 numSections++;
242 if (rsrc != null)
243 numSections++;
244 headerSize = fileHeaderSize + (numSections * sectionHeaderSize);
245 headerPadding = NumToAlign(headerSize,fileAlign);
246 headerSize += headerPadding;
247 uint offset = headerSize;
248 uint rva = SectionAlignment;
249 text.SetOffset(offset);
250 text.SetRVA(rva);
251 offset += text.Size();
252 rva = GetNextSectStart(rva,text.Tide());
253 // Console.WriteLine("headerSize = " + headerSize);
254 // Console.WriteLine("headerPadding = " + headerPadding);
255 // Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
256 if (sdata != null) {
257 sdata.SetSize(NumToAlign(sdata.Tide(),fileAlign));
258 sdata.SetOffset(offset);
259 sdata.SetRVA(rva);
260 offset += sdata.Size();
261 rva = GetNextSectStart(rva,sdata.Tide());
262 initDataSize += sdata.Size();
264 if (rsrc != null) {
265 rsrc.SetSize(NumToAlign(rsrc.Tide(),fileAlign));
266 rsrc.SetOffset(offset);
267 rsrc.SetRVA(rva);
268 offset += rsrc.Size();
269 rva = GetNextSectStart(rva,rsrc.Tide());
270 initDataSize += rsrc.Size();
272 relocOffset = offset;
273 relocRVA = rva;
276 internal void MakeFile()
278 if (doDLL) hintNameTable = dllHintNameTable.ToCharArray();
279 else hintNameTable = exeHintNameTable.ToCharArray();
280 BuildTextSection();
281 CalcOffsets();
282 BuildRelocSection();
283 // now write it out
284 WriteHeader();
285 WriteSections();
286 Flush();
287 Close();
290 private void WriteHeader()
292 Write(DOSHeader);
293 // Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
294 WritePEHeader();
295 // Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
296 text.WriteHeader(this,relocRVA);
297 if (sdata != null) sdata.WriteHeader(this,relocRVA);
298 if (rsrc != null) rsrc.WriteHeader(this,relocRVA);
299 // Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
300 WriteRelocSectionHeader();
301 // Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
302 WriteZeros(headerPadding);
305 private void WriteSections()
307 // Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
308 WriteTextSection();
309 if (sdata != null) WriteSDataSection();
310 if (rsrc != null) WriteRsrcSection();
311 WriteRelocSection();
314 private void WriteIAT()
316 Write(text.RVA() + hintNameTableOffset);
317 Write(0);
320 private void WriteImportTables()
322 // Import Table
323 WriteZeros(importTablePadding);
324 // Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
325 Write(importLookupTableOffset + text.RVA());
326 WriteZeros(8);
327 Write(runtimeEngineOffset + text.RVA());
328 Write(text.RVA()); // IAT is at the beginning of the text section
329 WriteZeros(20);
330 // Import Lookup Table
331 WriteIAT(); // lookup table and IAT are the same
332 // Hint/Name Table
333 // Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
334 Write(hintNameTable);
335 Write(runtimeEngineName.ToCharArray());
338 private void WriteTextSection()
340 WriteIAT();
341 WriteCLIHeader();
342 // Console.WriteLine("Writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
343 metaData.WriteByteCodes(this);
344 // Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
345 largeStrings = metaData.LargeStringsIndex();
346 largeGUID = metaData.LargeGUIDIndex();
347 largeUS = metaData.LargeUSIndex();
348 largeBlob = metaData.LargeBlobIndex();
349 metaData.WriteMetaData(this);
350 metaData.WriteResources (this);
351 if (reserveStrongNameSignatureSpace) {
352 WriteZeros(StrongNameSignatureSize);
354 WriteImportTables();
355 WriteZeros(entryPointPadding);
356 Write((ushort)0x25FF);
357 Write(ImageBase + text.RVA());
358 WriteZeros(text.Padding());
361 private void WriteCLIHeader()
363 Write(CLIHeaderSize); // Cb
364 Write((short)2); // Major runtime version
365 Write((short)0); // Minor runtime version
366 Write(text.RVA() + metaDataOffset);
367 Write(metaData.Size());
368 Write(runtimeFlags);
369 Write(entryPointToken);
370 if (resourcesSize > 0) {
371 Write (text.RVA () + resourcesOffset);
372 Write (resourcesSize);
373 } else {
374 WriteZeros (8);
376 // Strong Name Signature (RVA, size)
377 if (reserveStrongNameSignatureSpace) {
378 Write(text.RVA() + strongNameSigOffset);
379 Write(StrongNameSignatureSize);
380 } else {
381 WriteZeros(8);
383 WriteZeros(8); // CodeManagerTable
384 WriteZeros(8); // VTableFixups NYI
385 WriteZeros(16); // ExportAddressTableJumps, ManagedNativeHeader
388 private void WriteSDataSection()
390 long size = sdata.Size ();
391 long start = BaseStream.Position;
392 for (int i=0; i < data.Count; i++) {
393 ((DataConstant)data[i]).Write(this);
395 while (BaseStream.Position < (start + size))
396 Write ((byte) 0);
399 private void WriteRsrcSection()
403 private void WriteRelocSection()
405 // Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
406 MemoryStream str = (MemoryStream)reloc.BaseStream;
407 Write(str.ToArray());
408 WriteZeros(NumToAlign((uint)str.Position,fileAlign));
411 internal void SetEntryPoint(uint entryPoint)
413 entryPointToken = entryPoint;
416 internal void AddInitData(DataConstant cVal)
418 if (sdata == null) {
419 sdata = new Section(sdataName,0xC0000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ, WRITE
420 data = new ArrayList();
422 data.Add(cVal);
423 cVal.DataOffset = sdata.Tide();
424 sdata.IncTide(cVal.GetSize());
427 internal void WriteZeros(uint numZeros)
429 for (int i=0; i < numZeros; i++) {
430 Write((byte)0);
434 internal void WritePEHeader()
436 Write((ushort)0x014C); // Machine - always 0x14C for Managed PE Files (allow others??)
437 Write((ushort)numSections);
438 Write(dateStamp);
439 WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
440 Write((ushort)0x00E0); // Size of Optional Header
441 Write(characteristics);
442 // PE Optional Header
443 Write((ushort)0x010B); // Magic
444 Write((byte)0x6); // LMajor pure-IL = 6 C++ = 7
445 Write((byte)0x0); // LMinor
446 Write(text.Size());
447 Write(initDataSize);
448 Write(0); // Check other sections here!!
449 Write(text.RVA() + entryPointOffset);
450 Write(text.RVA());
451 uint dataBase = 0;
452 if (sdata != null) dataBase = sdata.RVA();
453 else if (rsrc != null) dataBase = rsrc.RVA();
454 else dataBase = relocRVA;
455 Write(dataBase);
456 Write(ImageBase);
457 Write(SectionAlignment);
458 Write(fileAlign);
459 Write((ushort)0x04); // OS Major
460 WriteZeros(6); // OS Minor, User Major, User Minor
461 Write((ushort)0x04); // SubSys Major
462 WriteZeros(6); // SybSys Minor, Reserved
463 Write(imageSize);
464 Write(headerSize);
465 Write((int)0); // File Checksum
466 Write((ushort)subSys);
467 Write((short)0); // DLL Flags
468 Write((uint)stackReserve); // Stack Reserve Size
469 Write((uint)0x1000); // Stack Commit Size
470 Write((uint)0x100000); // Heap Reserve Size
471 Write((uint)0x1000); // Heap Commit Size
472 Write(0); // Loader Flags
473 Write(0x10); // Number of Data Directories
474 WriteZeros(8); // Export Table
475 Write(importTableOffset + text.RVA());
476 Write(totalImportTableSize);
477 WriteZeros(24); // Resource, Exception and Certificate Tables
478 Write(relocRVA);
479 Write(relocTide);
480 WriteZeros(48); // Debug, Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
481 Write(text.RVA()); // IATRVA - IAT is at start of .text Section
482 Write(IATSize);
483 WriteZeros(8); // Delay Import Descriptor
484 Write(text.RVA()+IATSize); // CLIHeader immediately follows IAT
485 Write(CLIHeaderSize);
486 WriteZeros(8); // Reserved
489 internal void WriteRelocSectionHeader()
491 Write(relocName.ToCharArray());
492 Write(relocTide);
493 Write(relocRVA);
494 Write(relocSize);
495 Write(relocOffset);
496 WriteZeros(12);
497 Write(relocFlags);
500 private void Align (MemoryStream str, int val)
502 if ((str.Position % val) != 0) {
503 for (int i=val - (int)(str.Position % val); i > 0; i--) {
504 str.WriteByte(0);
509 private uint Align(uint val, uint alignVal)
511 if ((val % alignVal) != 0) {
512 val += alignVal - (val % alignVal);
514 return val;
517 private uint NumToAlign(uint val, uint alignVal)
519 if ((val % alignVal) == 0) return 0;
520 return alignVal - (val % alignVal);
523 internal void StringsIndex(uint ix)
525 if (largeStrings) Write(ix);
526 else Write((ushort)ix);
529 internal void GUIDIndex(uint ix)
531 if (largeGUID) Write(ix);
532 else Write((ushort)ix);
535 internal void USIndex(uint ix)
537 if (largeUS) Write(ix);
538 else Write((ushort)ix);
541 internal void BlobIndex(uint ix)
543 if (largeBlob) Write(ix);
544 else Write((ushort)ix);
547 internal void WriteIndex(MDTable tabIx,uint ix)
549 if (metaData.LargeIx(tabIx)) Write(ix);
550 else Write((ushort)ix);
553 internal void WriteCodedIndex(CIx code, MetaDataElement elem)
555 metaData.WriteCodedIndex(code,elem,this);
558 internal void WriteCodeRVA(uint offs)
560 Write(text.RVA() + offs);
563 internal void WriteDataRVA(uint offs)
565 Write(sdata.RVA() + offs);
568 internal void Write3Bytes(uint val)
570 byte b3 = (byte)((val & FileImage.iByteMask[2]) >> 16);
571 byte b2 = (byte)((val & FileImage.iByteMask[1]) >> 8);;
572 byte b1 = (byte)(val & FileImage.iByteMask[0]);
573 Write(b1);
574 Write(b2);
575 Write(b3);
578 internal bool ReserveStrongNameSignatureSpace {
579 get { return reserveStrongNameSignatureSpace; }
580 set { reserveStrongNameSignatureSpace = value; }
585 /**************************************************************************/
586 /// <summary>
587 /// Base class for the PEFile (starting point)
588 /// </summary>
589 public class PEFile {
591 private static readonly string mscorlibName = "mscorlib";
592 private Module thisMod;
593 private ClassDef moduleClass;
594 private ArrayList resources = new ArrayList ();
595 private Assembly thisAssembly;
596 private static bool isMSCorlib;
597 private int corFlags = 1;
598 FileImage fileImage;
599 MetaData metaData;
601 /// <summary>
602 /// Create a new PEFile. Each PEFile is a module.
603 /// </summary>
604 /// <param name="name">module name, also used for the file name</param>
605 /// <param name="isDLL">create a .dll or .exe file</param>
606 /// <param name="hasAssembly">this file is an assembly and
607 /// will contain the assembly manifest. The assembly name is the
608 /// same as the module name</param>
609 public PEFile(string name, bool isDLL, bool hasAssembly)
610 : this (name, null, isDLL, hasAssembly, null, null)
612 // Console.WriteLine(Hex.Byte(0x12));
613 // Console.WriteLine(Hex.Short(0x1234));
614 // Console.WriteLine(Hex.Int(0x12345678));
617 /// <summary>
618 /// Create a new PEFile. Each PEFile is a module.
619 /// </summary>
620 /// <param name="name">module name, also used for the file name</param>
621 /// <param name="isDLL">create a .dll or .exe file</param>
622 /// <param name="hasAssembly">this file is an assembly and
623 /// will contain the assembly manifest. The assembly name is the
624 /// same as the module name</param>
625 /// <param name="outputDir">write the PEFile to this directory. If this
626 /// string is null then the output will be to the current directory</param>
627 public PEFile(string name, bool isDLL, bool hasAssembly, string outputDir)
628 : this (name, null, isDLL, hasAssembly, outputDir, null)
630 // Console.WriteLine(Hex.Byte(0x12));
631 // Console.WriteLine(Hex.Short(0x1234));
632 // Console.WriteLine(Hex.Int(0x12345678));
635 /// <summary>
636 /// Create a new PEFile
637 /// </summary>
638 /// <param name="name">module name</param>
639 /// <param name="isDLL">create a .dll or .exe</param>
640 /// <param name="hasAssembly">this PEfile is an assembly and
641 /// will contain the assemly manifest. The assembly name is the
642 /// same as the module name</param>
643 /// <param name="outStream">write the PEFile to this stream instead
644 /// of to a new file</param>
645 public PEFile(string name, bool isDLL, bool hasAssembly, Stream outStream)
646 : this (name, null, isDLL, hasAssembly, null, outStream)
650 public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, Stream outStream)
651 : this (name, module_name, isDLL, hasAssembly, null, outStream)
655 public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, string outputDir, Stream outStream)
657 SetName (name);
658 string fname = module_name == null ? MakeFileName (outputDir, name, isDLL) : module_name;
659 if (outStream == null)
660 fileImage = new FileImage (isDLL, fname);
661 else
662 fileImage = new FileImage (isDLL, outStream);
664 InitPEFile (name, fname, hasAssembly);
667 private void SetName (string name)
669 if (name == "mscorlib")
670 isMSCorlib = true;
673 private void InitPEFile(string name, string fName, bool hasAssembly)
675 metaData = fileImage.GetMetaData();
676 thisMod = new Module(fName,metaData);
677 if (hasAssembly) {
678 thisAssembly = new Assembly(name,metaData);
679 metaData.AddToTable(MDTable.Assembly,thisAssembly);
681 moduleClass = AddClass(TypeAttr.Private,"","<Module>");
682 moduleClass.SpecialNoSuper();
683 metaData.AddToTable(MDTable.Module,thisMod);
686 internal static bool IsMSCorlib {
687 get { return isMSCorlib; }
690 public ClassDef ModuleClass {
691 get { return moduleClass; }
694 /// <summary>
695 /// Set the subsystem (.subsystem) (Default is Windows Console mode)
696 /// </summary>
697 /// <param name="subS">subsystem value</param>
698 public void SetSubSystem(SubSystem subS)
700 fileImage.subSys = subS;
703 /// <summary>
704 /// Set the flags (.corflags)
705 /// </summary>
706 /// <param name="flags">the flags value</param>
707 public void SetCorFlags(int flags)
709 corFlags = flags;
712 public void SetStackReserve (long stackReserve)
714 fileImage.stackReserve = stackReserve;
717 private string MakeFileName(string dirName, string name, bool isDLL)
719 string result = "";
720 if ((dirName != null) && (dirName.CompareTo("") != 0)) {
721 result = dirName;
722 if (!dirName.EndsWith("\\")) result += "\\";
724 result += name;
726 // if (isDLL) result += ".dll"; else result += ".exe";
728 return result;
731 /// <summary>
732 /// Add an external assembly to this PEFile (.assembly extern)
733 /// </summary>
734 /// <param name="assemName">the external assembly name</param>
735 /// <returns>a descriptor for this external assembly</returns>
736 public AssemblyRef AddExternAssembly(string assemName)
738 if (assemName.CompareTo(mscorlibName) == 0) return metaData.mscorlib;
739 AssemblyRef anAssem = new AssemblyRef(metaData,assemName);
740 metaData.AddToTable(MDTable.AssemblyRef,anAssem);
741 // Console.WriteLine("Adding assembly " + assemName);
742 return anAssem;
745 /// <summary>
746 /// Add an external module to this PEFile (.module extern)
747 /// </summary>
748 /// <param name="name">the external module name</param>
749 /// <returns>a descriptor for this external module</returns>
750 public ModuleRef AddExternModule(string name)
752 ModuleRef modRef = new ModuleRef(metaData,name);
753 metaData.AddToTable(MDTable.ModuleRef,modRef);
754 return modRef;
757 public ClassRef AddExternClass(string ns, string name, TypeAttr attrs, MetaDataElement declRef)
759 return new ExternClassRef (attrs, ns, name, declRef, metaData);
762 /// <summary>
763 /// Add a "global" method to this module
764 /// </summary>
765 /// <param name="name">method name</param>
766 /// <param name="retType">return type</param>
767 /// <param name="pars">method parameters</param>
768 /// <returns>a descriptor for this new "global" method</returns>
769 public MethodDef AddMethod (string name, Param ret_param, Param [] pars)
771 return moduleClass.AddMethod (name, ret_param, pars);
774 public MethodDef AddMethod(string name, Type retType, Param[] pars)
776 return AddMethod (name, new Param (ParamAttr.Default, "", retType), pars);
779 /// <summary>
780 /// Add a "global" method to this module
781 /// </summary>
782 /// <param name="mAtts">method attributes</param>
783 /// <param name="iAtts">method implementation attributes</param>
784 /// <param name="name">method name</param>
785 /// <param name="retType">return type</param>
786 /// <param name="pars">method parameters</param>
787 /// <returns>a descriptor for this new "global" method</returns>
788 public MethodDef AddMethod (MethAttr mAtts, ImplAttr iAtts, string name, Param ret_param, Param [] pars)
790 return moduleClass.AddMethod (mAtts, iAtts, name, ret_param, pars);
793 public MethodDef AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, Type retType, Param[] pars)
795 return AddMethod (mAtts, iAtts, name, new Param (ParamAttr.Default, "", retType), pars);
798 public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars)
800 return AddMethodToTypeSpec (item, name, retType, pars, 0);
803 public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars, int gen_param_count)
805 MethodRef meth = new MethodRef (item.GetTypeSpec (metaData), name, retType, pars, false, null, gen_param_count);
806 metaData.AddToTable (MDTable.MemberRef,meth);
807 return meth;
810 public MethodRef AddVarArgMethodToTypeSpec (Type item, string name, Type retType,
811 Type[] pars, Type[] optPars) {
812 MethodRef meth = new MethodRef(item.GetTypeSpec (metaData), name,retType,pars,true,optPars, 0);
813 metaData.AddToTable(MDTable.MemberRef,meth);
814 return meth;
817 public FieldRef AddFieldToTypeSpec (Type item, string name, Type fType)
819 FieldRef field = new FieldRef (item.GetTypeSpec (metaData), name,fType);
820 metaData.AddToTable (MDTable.MemberRef,field);
821 return field;
824 public Method AddMethodSpec (Method m, GenericMethodSig g_sig)
826 MethodSpec ms = new MethodSpec (m, g_sig);
827 metaData.AddToTable (MDTable.MethodSpec, ms);
828 return ms;
831 /// <summary>
832 /// Add a "global" field to this module
833 /// </summary>
834 /// <param name="name">field name</param>
835 /// <param name="fType">field type</param>
836 /// <returns>a descriptor for this new "global" field</returns>
837 public FieldDef AddField(string name, Type fType)
839 return moduleClass.AddField(name,fType);
842 /// <summary>
843 /// Add a "global" field to this module
844 /// </summary>
845 /// <param name="attrSet">attributes of this field</param>
846 /// <param name="name">field name</param>
847 /// <param name="fType">field type</param>
848 /// <returns>a descriptor for this new "global" field</returns>
849 public FieldDef AddField(FieldAttr attrSet, string name, Type fType)
851 return moduleClass.AddField(attrSet,name,fType);
854 /// <summary>
855 /// Add a class to this module
856 /// </summary>
857 /// <param name="attrSet">attributes of this class</param>
858 /// <param name="nsName">name space name</param>
859 /// <param name="name">class name</param>
860 /// <returns>a descriptor for this new class</returns>
861 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name)
863 return AddClass (attrSet, nsName, name, null);
866 /// <summary>
867 /// Add a class which extends System.ValueType to this module
868 /// </summary>
869 /// <param name="attrSet">attributes of this class</param>
870 /// <param name="nsName">name space name</param>
871 /// <param name="name">class name</param>
872 /// <returns>a descriptor for this new class</returns>
873 public ClassDef AddValueClass(TypeAttr attrSet, string nsName, string name, ValueClass vClass)
875 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
876 if (!ClassDef.IsValueType (nsName, name) && !ClassDef.IsEnum (nsName, name)) {
877 aClass.MakeValueClass(vClass);
878 } else {
879 if (ClassDef.IsEnum (nsName, name))
880 aClass.SetSuper (metaData.mscorlib.ValueType ());
881 else
882 aClass.SetSuper (metaData.mscorlib.GetSpecialSystemClass (PrimitiveType.Object));
884 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
886 aClass.SetTypeIndex (PrimitiveType.ValueType.GetTypeIndex ());
887 metaData.AddToTable(MDTable.TypeDef,aClass);
888 return aClass;
891 /// <summary>
892 /// Add a class to this module
893 /// </summary>
894 /// <param name="attrSet">attributes of this class</param>
895 /// <param name="nsName">name space name</param>
896 /// <param name="name">class name</param>
897 /// <param name="superType">super type of this class (extends)</param>
898 /// <returns>a descriptor for this new class</returns>
899 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name, Class superType)
901 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
902 if (superType != null)
903 aClass.SetSuper(superType);
904 if (PEFile.IsMSCorlib)
905 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
906 metaData.AddToTable(MDTable.TypeDef,aClass);
907 return aClass;
910 public void AddGenericClass (GenericTypeInst gti)
912 metaData.AddToTable (MDTable.TypeSpec, gti);
915 public void AddGenericParam (GenParam param)
917 metaData.AddToTable (MDTable.TypeSpec, param);
920 public FileRef AddFile(string fName, byte[] hashBytes, bool hasMetaData, bool entryPoint)
922 FileRef file = new FileRef(fName,hashBytes,hasMetaData,entryPoint,metaData);
923 metaData.AddToTable(MDTable.File,file);
924 return file;
927 public PrimitiveTypeRef AddPrimitiveType (PrimitiveType type)
929 return new PrimitiveTypeRef (type, metaData);
932 /// <summary>
933 /// Add a manifest resource to this PEFile NOT YET IMPLEMENTED
934 /// </summary>
935 /// <param name="mr"></param>
936 public void AddManifestResource(ManifestResource mr)
938 metaData.AddToTable(MDTable.ManifestResource,mr);
939 resources.Add (mr);
940 //mr.FixName(metaData);
943 public void AddCustomAttribute (Method meth, byte [] data, MetaDataElement element)
945 metaData.AddCustomAttribute (new CustomAttribute (element, meth, data));
946 element.HasCustomAttr = true;
949 public void AddCustomAttribute (Method meth, Constant constant, MetaDataElement element)
951 metaData.AddCustomAttribute (new CustomAttribute (element, meth, constant));
952 element.HasCustomAttr = true;
955 public void AddDeclSecurity (SecurityAction sec_action, byte [] data, MetaDataElement element)
957 metaData.AddDeclSecurity (new DeclSecurity (element, (ushort) sec_action, data));
960 public void AddDeclSecurity (SecurityAction sec_action, PEAPI.PermissionSet ps, MetaDataElement element)
962 metaData.AddDeclSecurity (new DeclSecurity_20 (element, (ushort) sec_action, ps));
965 /// <summary>
966 /// Add a managed resource from another assembly.
967 /// </summary>
968 /// <param name="resName">The name of the resource</param>
969 /// <param name="assem">The assembly where the resource is</param>
970 /// <param name="isPublic">Access for the resource</param>
971 public void AddExternalManagedResource (string resName, AssemblyRef assem, uint flags)
973 resources.Add (new ManifestResource (resName, flags, assem));
976 /// <summary>
977 /// Add a managed resource from another assembly.
978 /// </summary>
979 /// <param name="mr"></param>
980 /// <param name="isPublic"></param>
981 public void AddExternalManagedResource (ManifestResource mr)
983 resources.Add (new ManifestResource (mr));
985 /// <summary>
986 /// Find a resource
987 /// </summary>
988 /// <param name="name">The name of the resource</param>
989 /// <returns>The resource with the name "name" or null </returns>
990 public ManifestResource GetResource (string name)
992 for (int i = 0; i < resources.Count; i ++) {
993 if (((ManifestResource) resources [i]).Name == name)
994 return (ManifestResource) resources [i];
996 return null;
999 public ManifestResource [] GetResources()
1001 return (ManifestResource []) resources.ToArray (typeof (ManifestResource));
1004 /// <summary>
1005 /// Write out the PEFile (the "bake" function)
1006 /// </summary>
1007 public void WritePEFile() { /* the "bake" function */
1008 if (thisAssembly != null)
1009 fileImage.ReserveStrongNameSignatureSpace = thisAssembly.HasPublicKey;
1010 fileImage.MakeFile();
1013 /// <summary>
1014 /// Get the descriptor of this module
1015 /// </summary>
1016 /// <returns>the descriptor for this module</returns>
1017 public Module GetThisModule()
1019 return thisMod;
1022 /// <summary>
1023 /// Get the descriptor for this assembly. The PEFile must have been
1024 /// created with hasAssembly = true
1025 /// </summary>
1026 /// <returns>the descriptor for this assembly</returns>
1027 public Assembly GetThisAssembly()
1029 return thisAssembly;
1034 /**************************************************************************/
1035 /// <summary>
1036 /// Descriptor for a Section in a PEFile eg .text, .sdata
1037 /// </summary>
1038 internal class Section {
1039 private static readonly uint relocPageSize = 4096; // 4K pages for fixups
1041 char[] name;
1042 uint offset = 0, tide = 0, size = 0, rva = 0, relocTide = 0;
1043 //uint relocOff = 0;
1044 uint flags = 0, padding = 0;
1045 uint[] relocs;
1047 internal Section(string sName, uint sFlags)
1049 name = sName.ToCharArray();
1050 flags = sFlags;
1053 internal uint Tide() { return tide; }
1055 internal void IncTide(uint incVal) { tide += incVal; }
1057 internal uint Padding() { return padding; }
1059 internal uint Size() { return size; }
1061 internal void SetSize(uint pad)
1063 padding = pad;
1064 size = tide + padding;
1067 internal uint RVA() { return rva; }
1069 internal void SetRVA(uint rva) { this.rva = rva; }
1071 internal uint Offset() { return offset; }
1073 internal void SetOffset(uint offs) { offset = offs; }
1075 internal void DoBlock(BinaryWriter reloc, uint page, int start, int end)
1077 //Console.WriteLine("rva = " + rva + " page = " + page);
1078 reloc.Write(rva + page);
1079 reloc.Write((uint)(((end-start+1)*2) + 8));
1080 for (int j=start; j < end; j++) {
1081 //Console.WriteLine("reloc offset = " + relocs[j]);
1082 reloc.Write((ushort)((0x3 << 12) | (relocs[j] - page)));
1084 reloc.Write((ushort)0);
1087 internal void DoRelocs(BinaryWriter reloc)
1089 if (relocTide > 0) {
1090 //relocOff = (uint)reloc.Seek(0,SeekOrigin.Current);
1091 uint block = (relocs[0]/relocPageSize + 1) * relocPageSize;
1092 int start = 0;
1093 for (int i=1; i < relocTide; i++) {
1094 if (relocs[i] >= block) {
1095 DoBlock(reloc,block-relocPageSize,start,i);
1096 start = i;
1097 block = (relocs[i]/relocPageSize + 1) * relocPageSize;
1100 DoBlock(reloc,block-relocPageSize,start,(int)relocTide);
1104 internal void AddReloc(uint offs)
1106 int pos = 0;
1107 if (relocs == null) {
1108 relocs = new uint[5];
1109 } else {
1110 if (relocTide >= relocs.Length) {
1111 uint[] tmp = relocs;
1112 relocs = new uint[tmp.Length + 5];
1113 for (int i=0; i < relocTide; i++) {
1114 relocs[i] = tmp[i];
1117 while ((pos < relocTide) && (relocs[pos] < offs)) pos++;
1118 for (int i=pos; i < relocTide; i++) {
1119 relocs[i+1] = relocs[i];
1122 relocs[pos] = offs;
1123 relocTide++;
1126 internal void WriteHeader(BinaryWriter output, uint relocRVA)
1128 output.Write(name);
1129 output.Write(tide);
1130 output.Write(rva);
1131 output.Write(size);
1132 output.Write(offset);
1133 output.Write(0);
1134 //output.Write(relocRVA + relocOff);
1135 output.Write(0);
1136 output.Write(0);
1137 //output.Write((ushort)relocTide);
1138 //output.Write((ushort)0);
1139 output.Write(flags);
1144 public class Hex {
1145 readonly static char[] hexDigit = {'0','1','2','3','4','5','6','7',
1146 '8','9','A','B','C','D','E','F'};
1147 readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
1148 readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
1149 0x0000000000FF0000, 0x00000000FF000000,
1150 0x000000FF00000000, 0x0000FF0000000000,
1151 0x00FF000000000000, 0xFF00000000000000 };
1152 readonly static uint nibble0Mask = 0x0000000F;
1153 readonly static uint nibble1Mask = 0x000000F0;
1155 public static String Byte(int b)
1157 char[] str = new char[2];
1158 uint num = (uint)b;
1159 uint b1 = num & nibble0Mask;
1160 uint b2 = (num & nibble1Mask) >> 4;
1161 str[0] = hexDigit[b2];
1162 str[1] = hexDigit[b1];
1163 return new String(str);
1166 public static String Short(int b)
1168 char[] str = new char[4];
1169 uint num1 = (uint)b & iByteMask[0];
1170 uint num2 = ((uint)b & iByteMask[1]) >> 8;
1171 uint b1 = num1 & nibble0Mask;
1172 uint b2 = (num1 & nibble1Mask) >> 4;
1173 uint b3 = num2 & nibble0Mask;
1174 uint b4 = (num2 & nibble1Mask) >> 4;
1175 str[0] = hexDigit[b4];
1176 str[1] = hexDigit[b3];
1177 str[2] = hexDigit[b2];
1178 str[3] = hexDigit[b1];
1179 return new String(str);
1182 public static String Int(int val)
1184 char[] str = new char[8];
1185 uint num = (uint)val;
1186 int strIx = 7;
1187 for (int i=0; i < iByteMask.Length; i++) {
1188 uint b = num & iByteMask[i];
1189 b >>= (i*8);
1190 uint b1 = b & nibble0Mask;
1191 uint b2 = (b & nibble1Mask) >> 4;
1192 str[strIx--] = hexDigit[b1];
1193 str[strIx--] = hexDigit[b2];
1195 return new String(str);
1198 public static String Int(uint num)
1200 char[] str = new char[8];
1201 int strIx = 7;
1202 for (int i=0; i < iByteMask.Length; i++) {
1203 uint b = num & iByteMask[i];
1204 b >>= (i*8);
1205 uint b1 = b & nibble0Mask;
1206 uint b2 = (b & nibble1Mask) >> 4;
1207 str[strIx--] = hexDigit[b1];
1208 str[strIx--] = hexDigit[b2];
1210 return new String(str);
1213 public static String Long(long lnum)
1215 ulong num = (ulong)lnum;
1216 char[] str = new char[16];
1217 int strIx = 15;
1218 for (int i=0; i < lByteMask.Length; i++) {
1219 ulong b = num & lByteMask[i];
1220 b >>= (i*8);
1221 ulong b1 = b & nibble0Mask;
1222 ulong b2 = (b & nibble1Mask) >> 4;
1223 str[strIx--] = hexDigit[b1];
1224 str[strIx--] = hexDigit[b2];
1226 return new String(str);
1230 /// <summary>
1231 /// Error for invalid PE file
1232 /// </summary>
1233 public class PEFileException : System.Exception {
1234 public PEFileException(string msg) : base(msg) { }
1237 public class NotYetImplementedException : System.Exception {
1238 public NotYetImplementedException(string msg) : base(msg + " Not Yet Implemented") { }
1241 public class TypeSignatureException : System.Exception {
1242 public TypeSignatureException(string msg) : base(msg) { }