(* * This file is part of ilLib * Copyright (c)2004-2013 Haxe Foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *) (* This data is based on the Microsoft Portable Executable and Common Object File Format Specification Revision 8.3 *) type machine_type = | TUnknown (* 0 - unmanaged PE files only *) | Ti386 (* 0x014c - i386 *) | TR3000 (* 0x0162 - R3000 MIPS Little Endian *) | TR4000 (* 0x0166 - R4000 MIPS Little Endian *) | TR10000 (* 0x0168 - R10000 MIPS Little Endian *) | TWCeMipsV2 (* 0x0169 - MIPS Little Endian running MS Windows CE 2 *) | TAlpha (* 0x0184 - Alpha AXP *) | TSh3 (* 0x01a2 - SH3 Little Endian *) | TSh3Dsp (* 0x01a3 SH3DSP Little Endian *) | TSh3e (* 0x01a4 SH3E Little Endian *) | TSh4 (* 0x01a6 SH4 Little Endian *) | TSh5 (* 0x01a8 SH5 *) | TArm (* 0x1c0 ARM Little Endian *) | TArmN (* 0x1c4 ARMv7 (or higher) Thumb mode only Little Endian *) | TArm64 (* 0xaa64 - ARMv8 in 64-bit mode *) | TEbc (* 0xebc - EFI byte code *) | TThumb (* 0x1c2 ARM processor with Thumb decompressor *) | TAm33 (* 0x1d3 AM33 processor *) | TPowerPC (* 0x01f0 IBM PowerPC Little Endian *) | TPowerPCFP (* 0x01f1 IBM PowerPC with FPU *) | TItanium64 (* 0x0200 Intel IA64 (Itanium) *) | TMips16 (* 0x0266 MIPS *) | TAlpha64 (* 0x0284 Alpha AXP64 *) | TMipsFpu (* 0x0366 MIPS with FPU *) | TMipsFpu16 (* 0x0466 MIPS16 with FPU *) | TTriCore (* 0x0520 Infineon *) | TAmd64 (* 0x8664 AMD x64 and Intel E64T *) | TM32R (* 0x9041 M32R *) | TOSXAmd64 (* 0xC020 = 0x8664 xor 0x4644 OSX AMD x64 *) | TLinuxAmd64 (* 0xFD1D = 0x8664 xor 0x7B79 Linux AMD x64 *) type coff_prop = | RelocsStripped (* 0x1 *) (* image file only. Indicates the file contains no base relocations and *) (* must be loaded at its preferred base address. Should not be set for MPE files *) | ExecutableImage (* 0x2 *) (* Indicates that the file is an image file (EXE or DLL). Should be set for MPE files *) | LineNumsStripped (* 0x4 *) (* COFF line numbers have been removed. This flag should not be set for MPE files *) (* because they do not use the debug info embedded in the PE file itself. They are saved on PDB files *) | LocalSymsStripped (* 0x8 *) (* COFF symbol table entries for local symbols have been removed. It should be set for MPE files *) | AgressiveWsTrim (* 0x10 *) (* Agressively trim the working set. This flag should not be set for pure-IL MPE files *) | LargeAddressAware (* 0x20 *) (* Application can handle addresses beyond the 2GB range. This flag should not be set for *) (* pure-IL MPE files of versions 1 and 1.1, but can be set for v2.0 files *) | BytesReversedLO (* 0x80 *) (* Little endian. This flag should not be set for pure-IL MPE files *) | Machine32Bit (* 0x100 *) (* Machine is based on 32-bit architecture. This flag is usually set by the current *) (* versions of code generators producing PE files. V2.0+ can produce 64-bit specific images *) (* which don't have this flag set *) | DebugStripped (* 0x200 *) (* Debug information has been removed from the image file *) | RemovableRunFromSwap (* 0x400 *) (* If the image file is on removable media, copy and run it from swap file. *) (* This flag should no be set for pure-IL MPE files *) | NetRunFromSwap (* 0x800 *) (* If the image file is on a network, copy and run it from the swap file. *) (* This flag should no be set for pure-IL MPE files *) | FileSystem (* 0x1000 *) (* The image file is a system file (for example, a device driver) *) (* This flag should not be set for pure-IL MPE files *) | FileDll (* 0x2000 *) (* This image file is a DLL rather than an EXE. It cannot be directly run. *) | UpSystemOnly (* 0x4000 *) (* The image file should be run on an uniprocessor machine only. *) (* This flag should not be set for pure-IL MPE files *) | BytesReversedHI (* 0x8000 *) (* Big endian *) (* This flag should not be set for pure-IL MPE files *) (* represents a virtual address pointer. It's 64-bit on 64-bit executables, and 32-bit otherwise *) type pointer = int64 (* represents a memory index address on the target architecture. It's 64-bit on 64-bit executables, and 32-bit otherwise *) type size_t = pointer (* relative virtual address. *) (* it's always 32-bit - which means that PE/COFF files are still limited to the 4GB size *) type rva = int32 (* represents a PE file-bound memory index *) type size_t_file = int32 (* represents a file offset *) (* there's no point in defining it as int32, as file seek operations need an int *) type pointer_file = int type coff_header = { coff_machine : machine_type; (* offset 0 - size 2 . *) (* If the managed PE file is intended for various machine types (AnyCPU), it should be Ti386 *) coff_nsections : int; (* O2S2 *) coff_timestamp : int32; (* O4S4 *) coff_symbol_table_pointer : rva; (* O8S4 *) (* File pointer of the COFF symbol table. In managed PE files, it is 0 *) coff_nsymbols : int; (* O12S4 *) (* Number of entries in the COFF symbol table. Should be 0 in managed PE files *) coff_optheader_size: int; (* O16S2 *) (* Size of the PE header *) coff_props : coff_prop list; } let coff_default_exe_props = [ ExecutableImage; LineNumsStripped; LocalSymsStripped; (* Machine32Bit; *) ] let coff_default_dll_props = [ ExecutableImage; LineNumsStripped; LocalSymsStripped; (* Machine32Bit; *) FileDll ] type pe_magic = | P32 (* 0x10b *) | PRom (* 0x107 *) | P64 (* 0x20b - called PE32+ on the docs *) (* allows 64-bit address space while limiting the image size to 2 gb *) type subsystem = | SUnknown (* 0 *) | SNative (* 1 *) (* Device drivers and native windows processes *) | SWGui (* 2 *) (* Windows GUI subsystem *) | SWCui (* 3 *) (* Windows character subsystem *) | SPCui (* 7 *) (* Posix character subsystem *) | SWCeGui (* 9 *) (* Windows CE subsystem *) | SEfi (* 10 *) (* EFI application *) | SEfiBoot (* 11 *) (* EFI driver with boot services *) | SEfiRuntime (* 12 *) (* EFI driver with run-time services *) | SEfiRom (* 13 *) (* EFI ROM Image *) | SXbox (* 14 *) type dll_prop = | DDynamicBase (* 0x0040 *) (* DLL can be relocated at load time *) | DForceIntegrity (* 0x0080 *) (* Code integrity checks are enforced *) | DNxCompat (* 0x0100 *) (* Image is NX compatible *) | DNoIsolation (* 0x0200 *) (* Isolation-aware, but do not isolate the image *) | DNoSeh (* 0x0400 *) (* No structured exception handling *) | DNoBind (* 0x0800 *) (* Do not bind the image *) | DWdmDriver (* 0x2000 *) (* A WDM driver *) | DTerminalServer (* 0x8000 *) (* Terminal server aware *) type directory_type = | ExportTable (* .edata *) (* contains information about four other tables, which hold data describing *) (* unmanaged exports of the PE file. ILAsm and VC++ linker are capable of exposing *) (* the managed PE file as unmanaged exports *) | ImportTable (* .idata *) (* data on unmanaged imports consumed by the PE file. Only the VC++ linker makes *) (* use of this table, by marking the imported unmanaged external functions used by *) (* the unmanaged native code embedded in the same assembly. Other compilers only *) (* contain a single entry - that of the CLR entry function *) | ResourceTable (* .rsrc *) (* unmanaged resources embedded in the PE file. Managed resources don't use this *) | ExceptionTable (* .pdata *) (* unmanaged exceptions only *) | CertificateTable (* points to a table of attribute certificates, used for file authentication *) (* the first field of this entry is a file pointer rather than an RVA *) | RelocTable (* .reloc *) (* relocation table. We need to be aware of it if we use native TLS. *) (* only the VC++ linker uses native TLS' *) | DebugTable (* unmanaged debug data starting address and size. A managed PE file doesn't carry *) (* embedded debug data, so this data is either all zero or points to a 30-byte debug dir entry *) (* of type 2 (IMAGE_DEBUG_TYPE_CODEVIEW), which in turn points to a CodeView-style header, containing *) (* the path to the PDB debug file. *) | ArchitectureTable (* for i386, Itanium64 or AMD64, this data is set to all zeros *) | GlobalPointer (* the RVA of the value to be stored in the global pointer register. Size must be 0. *) (* if the target architecture (e.g. i386 or AMD64) don't use the concept of a global pointer, *) (* it is set to all zeros *) | TlsTable (* .tls *) (* The thread-local storage data. Only the VC++ linker and IL assembler produce code that use it *) | LoadConfigTable (* data specific to Windows NT OS *) | BoundImportTable (* array of bound import descriptors, each of which describes a DLL this image was bound *) (* at link-time, along with time stamps of the bindings. Iff they are up-to-date, the OS loader *) (* uses these bindings as a "shortcut" for API import *) | ImportAddressTable (* referenced from the Import Directory table (data directory 1) *) | DelayImport (* delay-load imports are DLLs described as implicit imports but loaded as explicit imports *) (* (via calls to the LoadLibrary API) *) | ClrRuntimeHeader (* .cormeta *) (* pointer to the clr_runtime_header *) | Reserved (* must be zero *) | Custom of int let directory_type_info = function | ExportTable -> 0, "ExportTable" | ImportTable -> 1, "ImportTable" | ResourceTable -> 2, "ResourceTable" | ExceptionTable -> 3, "ExceptionTable" | CertificateTable -> 4, "CertificateTable" | RelocTable -> 5, "RelocTable" | DebugTable -> 6, "DebugTable" | ArchitectureTable -> 7, "ArchTable" | GlobalPointer -> 8, "GlobalPointer" | TlsTable -> 9, "TlsTable" | LoadConfigTable -> 10, "LoadConfigTable" | BoundImportTable -> 11, "BuildImportTable" | ImportAddressTable -> 12, "ImportAddressTable" | DelayImport -> 13, "DelayImport" | ClrRuntimeHeader -> 14, "ClrRuntimeHeader" | Reserved -> 15, "Reserved" | Custom i -> i, "Custom" ^ (string_of_int i) let directory_type_of_int = function | 0 -> ExportTable | 1 -> ImportTable | 2 -> ResourceTable | 3 -> ExceptionTable | 4 -> CertificateTable | 5 -> RelocTable | 6 -> DebugTable | 7 -> ArchitectureTable | 8 -> GlobalPointer | 9 -> TlsTable | 10 -> LoadConfigTable | 11 -> BoundImportTable | 12 -> ImportAddressTable | 13 -> DelayImport | 14 -> ClrRuntimeHeader | 15 -> Reserved | i -> Custom i type section_prop = | SNoPad (* 0x8 *) (* the section should not be padded to the next boundary. *) (* OBSOLETE - replaced by SAlign1Bytes *) | SHasCode (* 0x20 *) (* the section contains executable code *) | SHasIData (* 0x40 *) (* contains initialized data *) | SHasData (* 0x80 *) (* contains uninitialized data *) | SHasLinkInfo (* 0x200 *) (* contains comments or other information. only valid for object files *) | SLinkRemove (* 0x1000 *) (* this will not become part of the image. only valid for object files *) | SGlobalRel (* 0x8000 *) (* contains data referenced through the global pointer (GP) *) | SHas16BitMem (* 0x20000 *) (* for ARM architecture. The section contains Thumb code *) | SAlign1Bytes (* 0x100000 *) (* align data on a 1-byte boundary. valid only for object files *) | SAlign2Bytes (* 0x200000 *) | SAlign4Bytes (* 0x300000 *) | SAlign8Bytes (* 0x400000 *) | SAlign16Bytes (* 0x500000 *) | SAlign32Bytes (* 0x600000 *) | SAlign64Bytes (* 0x700000 *) | SAlign128Bytes (* 0x800000 *) | SAlign256Bytes (* 0x900000 *) | SAlign512Bytes (* 0xA00000 *) | SAlign1024Bytes (* 0xB00000 *) | SAlign2048Bytes (* 0xC00000 *) | SAlign4096Bytes (* 0xD00000 *) | SAlign8192Bytes (* 0xE00000 *) | SHasExtRelocs (* 0x1000000 *) (* section contains extended relocations *) | SCanDiscard (* 0x02000000 *) (* section can be discarded as needed *) | SNotCached (* 0x04000000 *) (* section cannot be cached *) | SNotPaged (* 0x08000000 *) (* section is not pageable *) | SShared (* 0x10000000 *) (* section can be shared in memory *) | SExec (* 0x20000000 *) (* section can be executed as code *) | SRead (* 0x40000000 *) (* section can be read *) | SWrite (* 0x80000000 *) (* section can be written to *) type pe_section = { s_name : string; (* an 8-byte, null-padded UTF-8 encoded string *) s_vsize : size_t_file; (* the total size of the section when loaded into memory. *) (* if less than s_rawsize, the section is zero-padded *) (* should be set to 0 on object files *) s_vaddr : rva; (* the RVA of the beginning of the section *) s_raw_size : size_t_file; (* the size of the initialized data on disk, rounded up to a multiple *) (* of the file alignment value. If it's less than s_vsize, it should be *) (* zero filled. It may happen that rawsize is greater than vsize. *) s_raw_pointer : pointer_file; (* the file pointer to the first page of the section within the COFF file *) (* on executable images, this must be a multiple of file aignment value. *) (* for object files, it should be aligned on a 4byte boundary *) s_reloc_pointer : pointer_file; (* the file pointer to the beginning of relocation entries for this section *) (* this is set to zero for executable images or if there are no relocations *) s_line_num_pointer : pointer_file; (* the file pointer to the beginning of line-number entries for this section *) (* must be 0 : COFF debugging image is deprecated *) s_nrelocs : int; (* number of relocation entries *) s_nline_nums : int; (* number of line number entries *) s_props : section_prop list; (* properties of the section *) } (* The size of the PE header is not fixed. It depends on the number of data directories defined in the header *) (* and is specified in the optheader_size in the COFF header *) (* object files don't have this; but it's required for image files *) type pe_header = { pe_coff_header : coff_header; (* Standard fields *) pe_magic : pe_magic; pe_major : int; pe_minor : int; pe_code_size : int; (* size of the code section (.text) or the sum of all code sections, *) (* if multiple sections exist. The IL assembler always emits a single code section *) pe_init_size : int; pe_uinit_size : int; pe_entry_addr : rva; (* RVA of the beginning of the entry point function. For unmanaged DLLs, this can be 0 *) (* For managed PE files, this always points to the CLR invocation stub *) pe_base_code : rva; (* The address that is relative to the image base of the beginning-of-code section *) (* when it's loaded into memory *) pe_base_data : rva; (* The address that is relative to the image base of the beginning-of-data section *) (* when it's loaded into memory *) (* COFF Windows extension *) pe_image_base : pointer; (* The preferred address of the first byte of image when loaded into memory. *) (* Should be a multiple of 64K *) pe_section_alignment : int; (* The alignment in bytes of sections when they are loaded into memory *) (* It must be greater than or equal to FileAlignment. The default is the page size *) (* for the architecture *) (* x86 MPE files should have an alignment of 8KB, even though only 4KB would be needed *) (* for compatibility with 64-bits *) pe_file_alignment : int; (* The alignment factor in bytes that is used to align the raw data of sections *) (* in the image file. The value should be a POT between 512 and 64K. *) (* If secion_alignment is less than architecture's page size, file_alignment must match *) (* secion_alignment *) pe_major_osver : int; pe_minor_osver : int; pe_major_imgver : int; pe_minor_imgver : int; pe_major_subsysver : int; pe_minor_subsysver : int; pe_image_size : int; (* the size of the image in bytes, as the image is loaded into memory *) (* must be a multiple of section_alignment *) pe_headers_size : int; (* the combined size of an MSDOS stub, PE header, and section headers *) (* rounded up to a multiple of FileAlignment *) pe_checksum : int32; pe_subsystem : subsystem; pe_dll_props : dll_prop list; (* in MPE files of v1.0, always set to 0; In MPE of v1.1 and later, *) (* always set to 0x400 (DNoSeh) *) pe_stack_reserve : size_t; (* the size of the stack to reserve. Only pe_stack_commit is committed *) pe_stack_commit : size_t; (* the size of the stack to commit *) pe_heap_reserve : size_t; (* the size of the local heap space to reserve. Only pe_heap_commit is committed *) pe_heap_commit : size_t; (* the size of the heap to commit *) pe_ndata_dir : int; (* the number of data-directory entries in the remainder of the optional header *) (* should be at least 16. Although is possible to emit more than 16 data directories, *) (* all existing managed compilers emit exactly 16 data directories, with the last never *) (* used (reserved) *) pe_data_dirs : (rva * size_t_file) array; (* data directories are RVA's that point to sections on the PE that have special significance *) (* see directory_type docs *) (* sections *) pe_sections : pe_section array; } (* raw .idata table *) (* not used : only here for documentation purposes *) type idata_table_raw = { impr_lookup_table : rva; (* the RVA of the lookup table *) impr_timestamp : int32; (* on bound images, it's set to the timestamp of the DLL *) impr_fchain : int32; (* the index of the first forwarder reference - which are references *) (* that are both imported and exported *) impr_name : rva; (* the RVA to an ASCII string that contains the name of the DLL *) impr_address_table : rva; (* RVA of the import address table. The contents are identical to the imp_lookup_table *) (* until the image is bound *) } (* a symbol lookup can happen either by name, or by ordinal. *) (* lookup by name happens to be an extra indirection, as the loader *) (* uses the name to look up the export ordinal anyway. *) (* Most (if not all) MPE will do a lookup by name, though *) type symbol_lookup = | SName of int * string | SOrdinal of int type idata_table = { imp_name : string; (* ASCII string that contains the name of the DLL *) imp_imports : symbol_lookup list; } type clr_flag = | FIlOnly (* 0x1 *) (* the image file contains IL code only, with no embedded native unmanaged code *) (* this can cause some problems on WXP+, because the .reloc section is ignored when this flag is set *) (* e.g. if native TLS support is used. In this case the VC++ compiler unsets this flag *) | F32BitRequired (* 0x2 *) (* the file can be only loaded into a 32-bit process *) | FIlLibrary (* 0x4 *) (* obsolete *) | FSigned (* 0x8 *) (* the image file is protected with a strong name signature *) | FNativeEntry (* 0x10 *) (* the executable's entry point is an unmanaged method. *) (* the EntryPointToken / EntryPointRVA field of the CLR header *) (* contains the RVA of this native method *) | FTrackDebug (* 0x10000 *) (* the CLR loader is required to track debug information about the methods. This flag is not used *) type clr_header = { clr_cb : int; (* size of header *) clr_major : int; clr_minor : int; (* symbol table and startup information *) clr_meta : rva * size_t_file; clr_flags : clr_flag list; clr_entry_point : rva; (* metadata identifier (token) of the entry point for the image file *) (* can be 0 for DLL images. This field identifies a method belonging to this module *) (* or a module containing the entry point method. This field may contain RVA of the *) (* embedded native entry point method, if FNativeEntry flag is set *) (* binding information *) clr_res : rva * size_t_file; (* RVA of managed resources *) clr_sig : rva * size_t_file; (* RVA of the hash data for this PE file, used by the loader for binding and versioning *) (* regular fixup and binding information *) clr_codeman : rva * size_t_file; (* code manager table - RESERVED and should be 0 *) clr_vtable_fix : rva * size_t_file; (* RVA of an array of vtable fixups. Only VC++ linker and IL assembler produce data in this array *) clr_export_address : rva * size_t_file; (* rva of addresses of jump thunks. obsolete and should be set to 0 *) } (* unused structure: documentation purposes only *) type clr_stream_header = { str_offset : pointer_file; (* the (relative to the start of metadata) offset in the file for this stream *) str_size : size_t_file; (* the size of the stream in bytes *) str_name : string; (* name of the stream - a zero-terminated ASCII string no longer than 31 characters (plus 0 terminator) *) (* if the stream name is smaller, it can be reduced - but must be padded to the 4-byte boundary *) } (* unused structure: documentation purposes only *) type clr_meta_table = { (* storage signature *) meta_magic : string; (* always BSJB *) meta_major : int; meta_minor : int; (* meta_extra : int; *) (* reserved; always 0 *) meta_ver : string; (* encoded by first passing its length *) (* storage header *) (* meta_flags : int; *) (* reserved; always 0 *) meta_nstreams : int; (* number of streams *) meta_strings_stream : clr_stream_header; (* #Strings: a string heap containing the names of metadata items *) meta_blob_stream : clr_stream_header; (* #Blob: blob heap containing internal metadata binary object, such as default values, signatures, etc *) meta_guid_stream : clr_stream_header; (* #GUID: a GUID heap *) meta_us_stream : clr_stream_header; (* #US: user-defined strings *) meta_meta_stream : clr_stream_header; (* may be either: *) (* #~: compressed (optimized) metadata stream *) (* #-: uncompressed (unoptimized) metadata stream *) meta_streams : clr_stream_header list; (* custom streams *) }