Merge remote branch 'upstream/master'
[mono.git] / mcs / class / IKVM.Reflection / Writer / PEWriter.cs
1 /*
2   Copyright (C) 2008 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.IO;
26 using BYTE = System.Byte;
27 using WORD = System.UInt16;
28 using DWORD = System.UInt32;
29 using ULONGLONG = System.UInt64;
30
31 namespace IKVM.Reflection.Writer
32 {
33         sealed class PEWriter
34         {
35                 private readonly BinaryWriter bw;
36                 private readonly IMAGE_NT_HEADERS hdr = new IMAGE_NT_HEADERS();
37
38                 internal PEWriter(Stream stream)
39                 {
40                         bw = new BinaryWriter(stream);
41                         WriteMSDOSHeader();
42                 }
43
44                 public IMAGE_NT_HEADERS Headers
45                 {
46                         get { return hdr; }
47                 }
48
49                 public uint HeaderSize
50                 {
51                         get
52                         {
53                                 return (uint)
54                                         ((8 * 16) +     // MSDOS header
55                                         4 +                             // signature
56                                         20 +                    // IMAGE_FILE_HEADER
57                                         hdr.FileHeader.SizeOfOptionalHeader +
58                                         hdr.FileHeader.NumberOfSections * 40);
59                         }
60                 }
61
62                 private void WriteMSDOSHeader()
63                 {
64                         bw.Write(new byte[] {
65                                 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,
66                                 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
67                                 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00,     0x00, 0x00,
68                                 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72                                 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
73                                 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD,
74                                 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68,
75                                 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
76                                 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F,
77                                 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E,
78                                 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20,
79                                 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
80                                 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81                         });
82                 }
83
84                 internal void WritePEHeaders()
85                 {
86                         bw.Write(hdr.Signature);
87
88                         // IMAGE_FILE_HEADER
89                         bw.Write(hdr.FileHeader.Machine);
90                         bw.Write(hdr.FileHeader.NumberOfSections);
91                         bw.Write(hdr.FileHeader.TimeDateStamp);
92                         bw.Write(hdr.FileHeader.PointerToSymbolTable);
93                         bw.Write(hdr.FileHeader.NumberOfSymbols);
94                         bw.Write(hdr.FileHeader.SizeOfOptionalHeader);
95                         bw.Write(hdr.FileHeader.Characteristics);
96
97                         // IMAGE_OPTIONAL_HEADER
98                         hdr.OptionalHeader.Write(bw);
99                 }
100
101                 internal void WriteSectionHeader(SectionHeader sectionHeader)
102                 {
103                         byte[] name = new byte[8];
104                         System.Text.Encoding.UTF8.GetBytes(sectionHeader.Name, 0, sectionHeader.Name.Length, name, 0);
105                         bw.Write(name);
106                         bw.Write(sectionHeader.VirtualSize);
107                         bw.Write(sectionHeader.VirtualAddress);
108                         bw.Write(sectionHeader.SizeOfRawData);
109                         bw.Write(sectionHeader.PointerToRawData);
110                         bw.Write(sectionHeader.PointerToRelocations);
111                         bw.Write(sectionHeader.PointerToLinenumbers);
112                         bw.Write(sectionHeader.NumberOfRelocations);
113                         bw.Write(sectionHeader.NumberOfLinenumbers);
114                         bw.Write(sectionHeader.Characteristics);
115                 }
116
117                 internal uint ToFileAlignment(uint p)
118                 {
119                         return (p + (Headers.OptionalHeader.FileAlignment - 1)) & ~(Headers.OptionalHeader.FileAlignment - 1);
120                 }
121
122                 internal uint ToSectionAlignment(uint p)
123                 {
124                         return (p + (Headers.OptionalHeader.SectionAlignment - 1)) & ~(Headers.OptionalHeader.SectionAlignment - 1);
125                 }
126         }
127
128         sealed class IMAGE_NT_HEADERS
129         {
130                 public DWORD Signature = 0x00004550;    // "PE\0\0"
131                 public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
132                 public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
133         }
134
135         sealed class IMAGE_FILE_HEADER
136         {
137                 public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c;
138                 public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200;
139                 public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664;
140
141                 public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100;
142                 public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
143                 public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
144                 public const WORD IMAGE_FILE_DLL = 0x2000;
145
146                 public WORD Machine;
147                 public WORD NumberOfSections;
148                 public DWORD TimeDateStamp = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
149                 public DWORD PointerToSymbolTable = 0;
150                 public DWORD NumberOfSymbols = 0;
151                 public WORD SizeOfOptionalHeader = 0xE0;
152                 public WORD Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
153         }
154
155         sealed class IMAGE_OPTIONAL_HEADER
156         {
157                 public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
158                 public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
159
160                 public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2;
161                 public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3;
162
163                 public const WORD IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040;
164                 public const WORD IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100;
165                 public const WORD IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400;
166                 public const WORD IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000;
167
168                 public WORD Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
169                 public BYTE MajorLinkerVersion = 8;
170                 public BYTE MinorLinkerVersion = 0;
171                 public DWORD SizeOfCode;
172                 public DWORD SizeOfInitializedData;
173                 public DWORD SizeOfUninitializedData;
174                 public DWORD AddressOfEntryPoint;
175                 public DWORD BaseOfCode;
176                 public DWORD BaseOfData;
177                 public ULONGLONG ImageBase;
178                 public DWORD SectionAlignment = 0x2000;
179                 public DWORD FileAlignment = 0x200;
180                 public WORD MajorOperatingSystemVersion = 4;
181                 public WORD MinorOperatingSystemVersion = 0;
182                 public WORD MajorImageVersion = 0;
183                 public WORD MinorImageVersion = 0;
184                 public WORD MajorSubsystemVersion = 4;
185                 public WORD MinorSubsystemVersion = 0;
186                 public DWORD Win32VersionValue = 0;
187                 public DWORD SizeOfImage;
188                 public DWORD SizeOfHeaders;
189                 public DWORD CheckSum = 0;
190                 public WORD Subsystem;
191                 public WORD DllCharacteristics;
192                 public ULONGLONG SizeOfStackReserve = 0x100000;
193                 public ULONGLONG SizeOfStackCommit = 0x1000;
194                 public ULONGLONG SizeOfHeapReserve = 0x100000;
195                 public ULONGLONG SizeOfHeapCommit = 0x1000;
196                 public DWORD LoaderFlags = 0;
197                 public DWORD NumberOfRvaAndSizes = 16;
198                 public IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16];
199
200                 internal void Write(BinaryWriter bw)
201                 {
202                         bw.Write(Magic);
203                         bw.Write(MajorLinkerVersion);
204                         bw.Write(MinorLinkerVersion);
205                         bw.Write(SizeOfCode);
206                         bw.Write(SizeOfInitializedData);
207                         bw.Write(SizeOfUninitializedData);
208                         bw.Write(AddressOfEntryPoint);
209                         bw.Write(BaseOfCode);
210                         if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
211                         {
212                                 bw.Write(BaseOfData);
213                                 bw.Write((DWORD)ImageBase);
214                         }
215                         else
216                         {
217                                 bw.Write(ImageBase);
218                         }
219                         bw.Write(SectionAlignment);
220                         bw.Write(FileAlignment);
221                         bw.Write(MajorOperatingSystemVersion);
222                         bw.Write(MinorOperatingSystemVersion);
223                         bw.Write(MajorImageVersion);
224                         bw.Write(MinorImageVersion);
225                         bw.Write(MajorSubsystemVersion);
226                         bw.Write(MinorSubsystemVersion);
227                         bw.Write(Win32VersionValue);
228                         bw.Write(SizeOfImage);
229                         bw.Write(SizeOfHeaders);
230                         bw.Write(CheckSum);
231                         bw.Write(Subsystem);
232                         bw.Write(DllCharacteristics);
233                         if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
234                         {
235                                 bw.Write((DWORD)SizeOfStackReserve);
236                         }
237                         else
238                         {
239                                 bw.Write(SizeOfStackReserve);
240                         }
241                         if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
242                         {
243                                 bw.Write((DWORD)SizeOfStackCommit);
244                         }
245                         else
246                         {
247                                 bw.Write(SizeOfStackCommit);
248                         }
249                         if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
250                         {
251                                 bw.Write((DWORD)SizeOfHeapReserve);
252                         }
253                         else
254                         {
255                                 bw.Write(SizeOfHeapReserve);
256                         }
257                         if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
258                         {
259                                 bw.Write((DWORD)SizeOfHeapCommit);
260                         }
261                         else
262                         {
263                                 bw.Write(SizeOfHeapCommit);
264                         }
265                         bw.Write(LoaderFlags);
266                         bw.Write(NumberOfRvaAndSizes);
267                         for (int i = 0; i < DataDirectory.Length; i++)
268                         {
269                                 bw.Write(DataDirectory[i].VirtualAddress);
270                                 bw.Write(DataDirectory[i].Size);
271                         }
272                 }
273         }
274
275         struct IMAGE_DATA_DIRECTORY
276         {
277                 public DWORD VirtualAddress;
278                 public DWORD Size;
279         }
280
281         class SectionHeader
282         {
283                 public const DWORD IMAGE_SCN_CNT_CODE = 0x00000020;
284                 public const DWORD IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
285                 public const DWORD IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
286                 public const DWORD IMAGE_SCN_MEM_EXECUTE = 0x20000000;
287                 public const DWORD IMAGE_SCN_MEM_READ = 0x40000000;
288                 public const DWORD IMAGE_SCN_MEM_WRITE = 0x80000000;
289
290                 public string Name;             // 8 byte UTF8 encoded 0-padded
291                 public DWORD VirtualSize;
292                 public DWORD VirtualAddress;
293                 public DWORD SizeOfRawData;
294                 public DWORD PointerToRawData;
295 #pragma warning disable 649 // the follow fields are never assigned to
296                 public DWORD PointerToRelocations;
297                 public DWORD PointerToLinenumbers;
298                 public WORD NumberOfRelocations;
299                 public WORD NumberOfLinenumbers;
300 #pragma warning restore 649
301                 public DWORD Characteristics;
302         }
303 }