Created
March 25, 2017 11:28
-
-
Save rikkimax/314e3bce3f42b5a61ede60693454e43c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// From http://www.delorie.com/djgpp/doc/exe/ and winnt.h | |
| module definitions.msdos; | |
| import std.experimental.allocator : IAllocator, make, makeArray, dispose; | |
| /// | |
| final class MSDOS_Header { | |
| private { | |
| IAllocator allocator; | |
| } | |
| ~this() { | |
| allocator.dispose(relocs); | |
| allocator.dispose(overlay_data); | |
| } | |
| /// | |
| ushort bytes_in_last_block; | |
| /// | |
| ushort blocks_in_file; | |
| /// | |
| MZReloc[] relocs; | |
| /// | |
| ushort header_paragraphs; | |
| /// | |
| ushort min_extra_paragraphs; | |
| /// | |
| ushort max_extra_paragraphs; | |
| /// | |
| ushort ss; | |
| /// | |
| ushort sp; | |
| /// | |
| ushort checksum; | |
| /// | |
| ushort ip; | |
| /// | |
| ushort cs; | |
| /// Must be >= 0x40 | |
| ushort reloc_table_offset = 0x40; | |
| /// | |
| ushort overlay_number; | |
| //ushort[4] reserved1; | |
| /// | |
| ushort oem_identifier; | |
| /// | |
| ushort oem_information; | |
| //ushort[10] reserved2; | |
| /// | |
| uint extended_header_offset; | |
| /// overload data | |
| ubyte[] overlay_data; | |
| /// | |
| ubyte[] toBytes(IAllocator allocator) { | |
| import std.bitmanip : nativeToLittleEndian; | |
| // validation of relocation table offset | |
| if (reloc_table_offset < 0x40) | |
| return null; | |
| ubyte[] ret = allocator.makeArray!ubyte(fullFileSize); | |
| ret[0 .. 2] = cast(ubyte[2])"MZ"; | |
| ret[2 .. 4] = nativeToLittleEndian!ushort(bytes_in_last_block); | |
| ret[4 .. 6] = nativeToLittleEndian!ushort(blocks_in_file); | |
| ret[6 .. 8] = nativeToLittleEndian!ushort(cast(ushort)relocs.length); | |
| ret[8 .. 10] = nativeToLittleEndian!ushort(header_paragraphs); | |
| ret[10 .. 12] = nativeToLittleEndian!ushort(min_extra_paragraphs); | |
| ret[12 .. 14] = nativeToLittleEndian!ushort(max_extra_paragraphs); | |
| ret[14 .. 16] = nativeToLittleEndian!ushort(ss); | |
| ret[16 .. 18] = nativeToLittleEndian!ushort(sp); | |
| ret[18 .. 20] = nativeToLittleEndian!ushort(checksum); | |
| ret[20 .. 22] = nativeToLittleEndian!ushort(ip); | |
| ret[22 .. 24] = nativeToLittleEndian!ushort(cs); | |
| ret[24 .. 26] = nativeToLittleEndian!ushort(reloc_table_offset); | |
| ret[26 .. 28] = nativeToLittleEndian!ushort(overlay_number); | |
| ret[28 .. 36] = 0; | |
| ret[36 .. 38] = nativeToLittleEndian!ushort(oem_identifier); | |
| ret[38 .. 40] = nativeToLittleEndian!ushort(oem_information); | |
| ret[40 .. 60] = 0; | |
| ret[60 .. 64] = nativeToLittleEndian!uint(extended_header_offset); | |
| ret[64 .. 64 + overlay_data.length] = overlay_data; | |
| size_t offset = reloc_table_offset; | |
| foreach(reloc; relocs) { | |
| ret[offset .. offset + 2] = nativeToLittleEndian!ushort(reloc.offset); | |
| ret[offset + 2 .. offset + 4] = nativeToLittleEndian!ushort(reloc.segment); | |
| offset += 4; | |
| } | |
| return ret; | |
| } | |
| /// | |
| static bool from(ubyte[] data, IAllocator allocator, out MSDOS_Header ret) { | |
| import std.bitmanip : littleEndianToNative; | |
| if (data.length < 0x40) | |
| return false; | |
| if (data[0 .. 2] != "MZ") | |
| return false; | |
| ret = allocator.make!MSDOS_Header; | |
| ret.allocator = allocator; | |
| ret.bytes_in_last_block = littleEndianToNative!ushort(data[2 .. 4]); | |
| ret.blocks_in_file = littleEndianToNative!ushort(data[4 .. 6]); | |
| ret.relocs = allocator.makeArray!MZReloc(data[6 .. 8]); | |
| ret.header_paragraphs = littleEndianToNative!ushort(data[8 .. 10]); | |
| ret.min_extra_paragraphs = littleEndianToNative!ushort(data[10 .. 12]); | |
| ret.max_extra_paragraphs = littleEndianToNative!ushort(data[12 .. 14]); | |
| ret.ss = littleEndianToNative!ushort(data[14 .. 16]); | |
| ret.sp = littleEndianToNative!ushort(data[16 .. 18]); | |
| ret.checksum = littleEndianToNative!ushort(data[18 .. 20]); | |
| ret.ip = littleEndianToNative!ushort(data[20 .. 22]); | |
| ret.cs = littleEndianToNative!ushort(data[22 .. 24]); | |
| ret.reloc_table_offset = littleEndianToNative!ushort(data[24 .. 26]); | |
| ret.overlay_number = littleEndianToNative!ushort(data[26 .. 28]); | |
| ret.oem_identifier = littleEndianToNative!ushort(data[36 .. 38]); | |
| ret.oem_information = littleEndianToNative!ushort(data[38 .. 40]); | |
| ret.extended_header_offset = littleEndianToNative!uint(data[60 .. 64]); | |
| if (data.length < 64 + ret.reloc_table_offset) { | |
| allocator.dispose(ret.relocs); | |
| return false; | |
| } | |
| ret.overlay_data = allocator.makeArray!ubyte(ret.reloc_table_offset - 64); | |
| ret.overlay_data = data[64 .. 64 + ret.reloc_table_offset]; | |
| if (data.length < 64 + ret.reloc_table_offset + (4 * ret.relocs.length)) { | |
| allocator.dispose(ret.relocs); | |
| allocator.dispose(ret.overlay_data); | |
| return false; | |
| } | |
| size_t offset = ret.reloc_table_offset; | |
| foreach(ref reloc; ret.relocs) { | |
| reloc.offset = littleEndianToNative!ushort(*cast(ubyte[2]*)data[offset .. offset + 2].ptr); | |
| reloc.segment = littleEndianToNative!ushort(*cast(ubyte[2]*)data[offset + 2 .. offset + 4].ptr); | |
| offset += 4; | |
| } | |
| return true; | |
| } | |
| /// | |
| size_t fullFileSize() { | |
| assert(reloc_table_offset >= 0x40, "Invalid location of relocation table"); | |
| return reloc_table_offset + (4 * relocs.length) + overlay_data.length; | |
| } | |
| } | |
| /// | |
| struct MZReloc { | |
| /// | |
| ushort offset; | |
| /// | |
| ushort segment; | |
| } | |
| /// A common MS-DOS header that is ready for use by e.g. PE-COFF or OMF | |
| /// that probably won't be executable within DOS | |
| static const(ubyte)[] Empty_MSDOS_Header = cast(const(ubyte)[])x" | |
| 4d 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
| 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 | |
| "; | |
| /// An untested MS-DOS stub that should force the program to quit | |
| static const(ubyte)[] Empty_MSDOS_Stub = cast(const(ubyte)[])x" | |
| B8 4C 00 CD 21 | |
| "; | |
| /// A common MS-DOS header | |
| /// that should be executable within DOS | |
| static const(ubyte)[] Common_MSDOS_Header = cast(const(ubyte)[])x" | |
| 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 | |
| B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 | |
| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
| "; | |
| /// A common MS-DOS stub that is used with PE-COFF executables | |
| /// that should be executable within DOS | |
| static const(ubyte)[] Common_MSDOS_Stub = cast(const(ubyte)[])x" | |
| 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 | |
| 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F | |
| 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 | |
| 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 | |
| 83 C2 32 29 C7 A3 5C 7A C7 A3 5C 7A C7 A3 5C 7A | |
| CE DB D8 7A C6 A3 5C 7A CE DB C9 7A C5 A3 5C 7A | |
| CE DB CF 7A DA A3 5C 7A C7 A3 5D 7A 33 A3 5C 7A | |
| CE DB DF 7A D3 A3 5C 7A CE DB D5 7A CC A3 5C 7A | |
| CE DB C8 7A C6 A3 5C 7A CE DB CD 7A C6 A3 5C 7A | |
| 52 69 63 68 C7 A3 5C 7A 00 00 00 00 00 00 00 00 | |
| 00 00 00 00 00 00 00 00 | |
| "; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// http://pierrelib.pagesperso-orange.fr/exec_formats/OMF_v1.1.pdf | |
| /// TODO: representations of each record type | |
| module definitions.omf; | |
| import std.experimental.allocator : IAllocator, make, makeArray, dispose; | |
| /// | |
| final class OMF_Records { | |
| /// | |
| OMF_Record[] records; | |
| private { | |
| IAllocator allocator; | |
| } | |
| ~this() { | |
| foreach(record; records) { | |
| allocator.dispose(record.data); | |
| } | |
| allocator.dispose(records); | |
| } | |
| /// | |
| ubyte[] toBytes(IAllocator allocator) { | |
| import std.bitmanip : nativeToLittleEndian; | |
| ubyte[] ret = allocator.makeArray!ubyte(fullFileSize); | |
| size_t offset; | |
| foreach(record; records) { | |
| ret[offset] = cast(ubyte)record.type; | |
| ret[offset + 1 .. offset + 3] = nativeToLittleEndian!ushort(cast(ushort)record.data.length); | |
| ret[offset + 3] = record.checksum; | |
| offset += 4; | |
| ret[offset .. offset + record.data.length] = record.data[]; | |
| offset += record.data.length; | |
| } | |
| return ret; | |
| } | |
| /// | |
| static OMF_Records from(ubyte[] data, IAllocator allocator) { | |
| import std.bitmanip : littleEndianToNative; | |
| size_t i, countRecords; | |
| while(i + 4 <= data.length) { | |
| i += littleEndianToNative!ushort(*cast(ubyte[2]*)data[i + 1 .. i + 3].ptr) + 4; | |
| countRecords++; | |
| } | |
| OMF_Records ret = allocator.make!OMF_Records; | |
| ret.allocator = allocator; | |
| ret.records = allocator.makeArray!OMF_Record(countRecords); | |
| i = 0; | |
| countRecords = 0; | |
| while (i + 4 < data.length) { | |
| size_t dataLength = littleEndianToNative!ushort(*cast(ubyte[2]*)data[i + 1 .. i + 3].ptr); | |
| ubyte[] recdata = data[i + 3 .. i + 3 + dataLength]; | |
| ret.records[i].type = cast(OMF_Record_Type)data[i]; | |
| ret.records[i].checksum = data[i + 3 + dataLength]; | |
| ret.records[i].data = allocator.makeArray!ubyte(recdata.length); | |
| ret.records[i].data = recdata[]; | |
| i += dataLength + 4; | |
| countRecords++; | |
| } | |
| return ret; | |
| } | |
| /// | |
| size_t fullFileSize() { | |
| size_t ret; | |
| foreach(ref record; records) | |
| ret += 4 + record.data.length; | |
| return ret; | |
| } | |
| } | |
| /// | |
| enum OMF_Record_Type { | |
| /// | |
| THEADR = 0x80, | |
| /// | |
| LHEADR = 0x82, | |
| /// | |
| COMENT = 0x88, | |
| /// | |
| IMPDEF = COMENT, | |
| /// | |
| EXPDEF = COMENT, | |
| /// | |
| INCDEF = COMENT, | |
| /// | |
| LNKDEF = COMENT, | |
| /// | |
| LIBMOD = COMENT, | |
| /// | |
| EXESTR = COMENT, | |
| /// | |
| INCERR = COMENT, | |
| /// | |
| NOPAD = COMENT, | |
| /// | |
| WKEXT = COMENT, | |
| /// | |
| LZEXT = COMENT, | |
| /// | |
| MODEND_16 = 0x8A, | |
| /// | |
| MODEND_32 = 0x8B, | |
| /// | |
| EXTDEF = 0x8C, | |
| /// | |
| PUBDEF_16 = 0x90, | |
| /// | |
| PUBDEF_32 = 0x91, | |
| /// | |
| LINNUM_16 = 0x94, | |
| /// | |
| LINNUM_32 = 0x95, | |
| /// | |
| LNAMES = 0x96, | |
| /// | |
| SEGDEF_16 = 0x98, | |
| /// | |
| SEGDEF_32 = 0x99, | |
| /// | |
| GRPDEF = 0x9A, | |
| /// | |
| FIXUPP_16 = 0x9C, | |
| /// | |
| FIXUPP_32 = 0x9D, | |
| /// | |
| LEDATA_16 = 0xA0, | |
| /// | |
| LEDATA_32 = 0xA1, | |
| /// | |
| LIDATA_16 = 0xA2, | |
| /// | |
| LIDATA_32 = 0xA3, | |
| /// | |
| COMDEF = 0xB0, | |
| /// | |
| BAKPAT_16 = 0xB2, | |
| /// | |
| BAKPAT_32 = 0xB3, | |
| /// LEXTDEF_a == LEXTDEF_b | |
| LEXTDEF_a = 0xB4, | |
| /// LEXTDEF_a == LEXTDEF_b | |
| LEXTDEF_b = 0xB5, | |
| /// | |
| LPUBDEF_16 = 0xB6, | |
| /// | |
| LPUBDEF_32 = 0xB7, | |
| /// | |
| LCOMDEF = 0xB8, | |
| /// | |
| CEXTDEF = 0xBC, | |
| /// | |
| COMDAT_16 = 0xC2, | |
| /// | |
| COMDAT_32 = 0xC3, | |
| /// | |
| LINSYM_16 = 0xC4, | |
| /// | |
| LINSYM_32 = 0xC5, | |
| /// | |
| ALIAS = 0xC6, | |
| /// | |
| NBKPAT_16 = 0xC8, | |
| /// | |
| NBKPAT_32 = 0xC9, | |
| /// | |
| LLNAMES = 0xCA, | |
| /// | |
| VERNUM = 0xCC, | |
| /// | |
| VENDEXT = 0xCE | |
| } | |
| /// | |
| struct OMF_Record { | |
| /// | |
| OMF_Record_Type type; | |
| /// | |
| ubyte[] data; | |
| /// | |
| ubyte checksum; | |
| /// | |
| string getCountCharString(size_t offset) { | |
| if (data.length > offset) { | |
| size_t offset_e, length; | |
| if (data[offset] & 0x80) { | |
| if (data.length > offset + 1) { | |
| length = (data[offset] & 0x7F) * 0x100 + data[offset + 1]; | |
| offset_e = 1; | |
| } else | |
| return null; | |
| } else | |
| length = data[offset]; | |
| if (data.length >= offset + offset_e + 1 + length) { | |
| offset += 1 + offset_e; | |
| return cast(string)data[offset .. offset + length]; | |
| } else | |
| return null; | |
| } else | |
| return null; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment