| ... | ... | @@ -2784,7 +2784,7 @@ fn writeHeader(coff: *Coff) !void { |
| 2784 | 2784 | const writer = buffer.writer(); |
| 2785 | 2785 | |
| 2786 | 2786 | try buffer.ensureTotalCapacity(coff.getSizeOfHeaders()); |
| 2787 | | writer.writeAll(msdos_stub) catch unreachable; |
| 2787 | writer.writeAll(&msdos_stub) catch unreachable; |
| 2788 | 2788 | mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little); |
| 2789 | 2789 | |
| 2790 | 2790 | writer.writeAll("PE\x00\x00") catch unreachable; |
| ... | ... | @@ -3748,4 +3748,63 @@ const Value = @import("../Value.zig"); |
| 3748 | 3748 | const AnalUnit = InternPool.AnalUnit; |
| 3749 | 3749 | const dev = @import("../dev.zig"); |
| 3750 | 3750 | |
| 3751 | | const msdos_stub = @embedFile("msdos-stub.bin"); |
| 3751 | /// This is the start of a Portable Executable (PE) file. |
| 3752 | /// It starts with a MS-DOS header followed by a MS-DOS stub program. |
| 3753 | /// This data does not change so we include it as follows in all binaries. |
| 3754 | /// |
| 3755 | /// In this context, |
| 3756 | /// A "paragraph" is 16 bytes. |
| 3757 | /// A "page" is 512 bytes. |
| 3758 | /// A "long" is 4 bytes. |
| 3759 | /// A "word" is 2 bytes. |
| 3760 | const msdos_stub: [120]u8 = .{ |
| 3761 | 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format). |
| 3762 | 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub. |
| 3763 | 0x01, 0x00, // Number of pages. |
| 3764 | 0x00, 0x00, // Number of entries in the relocation table. |
| 3765 | 0x04, 0x00, // The number of paragraphs taken up by the header. 4 * 16 = 64, which matches the header size (all bytes before the MS-DOS stub program). |
| 3766 | 0x00, 0x00, // The number of paragraphs required by the program. |
| 3767 | 0x00, 0x00, // The number of paragraphs requested by the program. |
| 3768 | 0x00, 0x00, // Initial value for SS (relocatable segment address). |
| 3769 | 0x00, 0x00, // Initial value for SP. |
| 3770 | 0x00, 0x00, // Checksum. |
| 3771 | 0x00, 0x00, // Initial value for IP. |
| 3772 | 0x00, 0x00, // Initial value for CS (relocatable segment address). |
| 3773 | 0x40, 0x00, // Absolute offset to relocation table. 64 matches the header size (all bytes before the MS-DOS stub program). |
| 3774 | 0x00, 0x00, // Overlay number. Zero means this is the main executable. |
| 3775 | } |
| 3776 | // Reserved words. |
| 3777 | ++ .{ 0x00, 0x00 } ** 4 |
| 3778 | // OEM-related fields. |
| 3779 | ++ .{ |
| 3780 | 0x00, 0x00, // OEM identifier. |
| 3781 | 0x00, 0x00, // OEM information. |
| 3782 | } |
| 3783 | // Reserved words. |
| 3784 | ++ .{ 0x00, 0x00 } ** 10 |
| 3785 | // Address of the PE header (a long). This matches the size of this entire MS-DOS stub, so that's the address of what's after this MS-DOS stub. |
| 3786 | ++ .{ 0x78, 0x00, 0x00, 0x00 } |
| 3787 | // What follows is a 16-bit x86 MS-DOS program of 7 instructions that prints the bytes after these instructions and then exits. |
| 3788 | ++ .{ |
| 3789 | // Set the value of the data segment to the same value as the code segment. |
| 3790 | 0x0e, // push cs |
| 3791 | 0x1f, // pop ds |
| 3792 | // Set the DX register to the address of the message. |
| 3793 | // If you count all bytes of these 7 instructions you get 14, so that's the address of what's after these instructions. |
| 3794 | 0xba, 14, 0x00, // mov dx, 14 |
| 3795 | // Set AH to the system call code for printing a message. |
| 3796 | 0xb4, 0x09, // mov ah, 0x09 |
| 3797 | // Perform the system call to print the message. |
| 3798 | 0xcd, 0x21, // int 0x21 |
| 3799 | // Set AH to 0x4c which is the system call code for exiting, and set AL to 0x01 which is the exit code. |
| 3800 | 0xb8, 0x01, 0x4c, // mov ax, 0x4c01 |
| 3801 | // Peform the system call to exit the program with exit code 1. |
| 3802 | 0xcd, 0x21, // int 0x21 |
| 3803 | } |
| 3804 | // Message to print. |
| 3805 | ++ "This program cannot be run in DOS mode.".* |
| 3806 | // Message terminators. |
| 3807 | ++ .{ |
| 3808 | '$', // We do not pass a length to the print system call; the string is terminated by this character. |
| 3809 | 0x00, 0x00, // Terminating zero bytes. |
| 3810 | }; |