Starting with the fact they have a dedicated set of "subsystem" values: https://docs.microsoft.com/en-us/windows/win32/debug/pe-form... - the win32 loader won't load anything that isn't the CUI or the GUI Windows one, although the kernel also knows about the native one. You'll just get the "this is not a Windows application" messagebox.
With NASM, you can also override that linker stub. For example save this to a file:
org 100h
start:
mov dx, msg
mov ah, 9
int 21h
mov ah, 4Ch
int 21h
msg db 'Are you still running DOS in 2022? Wow! 640K enough for you!',13,10,'$'
nasm -fbin -o stub.com stub.asmthen if you are using Microsoft's tools you can use LINK.EXE <usual args> /STUB:stub.com and voila, if anyone _happens_ to (try to) your code under DOS, they'll get an amusing message.
If you want it to take up minimum space, use this one:
org 100h
start:
mov ah,4Ch
int 21h
which will just exit that program if run under dos.Apparently the header is hardcoded in mingw, but you could easily binary patch it in the resulting executable.
I think I read somewhere you can also remove the stub completely, but I've never tried it.
Edit: for my last comment, yes, you can definitely drop it: https://stackoverflow.com/a/9659538.
No. They are not Windows executables. They won’t run under Windows at all for multiple reasons. They are PE executables.
PE is the executable format developed for Windows, and yes, it is backwards compatible with MZ executables, so it has the now-confusing MZ header even though that doesn’t make sense under EFI. It also has some other weird details kind of hardcoded in, like some of the data directories, many of which don’t make that much sense under EFI. Worse, it’s a little weird to parse, with many things being deduced by using known structure sizes combined with offsets specified in fields.
However, PE as a format is totally fine. Good, even. In its purest form, it really doesn’t have that much baggage. It flat out has some advantages over ELF whose symbol table non-sense is notoriously complicated. Not so under PE: explicit table of exports, explicit table of imports. The imports go to specific modules. Symbols don’t conflict. It’s got cruft, but it’s very simple to write a parser or loader, and I’ve done so a number of times before. With PE the runtime linking is handled by whatever OS is running, be it EFI or Windows; none of the INTERP stuff is needed.
Frankly, I’d be OK with using PE on Linux too. When I was a kid, I toyed around with making a binfmt for PE. Of course I didn’t finish (most notably, I never figured out how to do linking, since the ELF binfmt didn’t really do that) but it’s quite straightforward to get the actual loader going.
As for the rest of the grievances… As far as I know, FAT and GPT are only required to be supported by EFI, not required to be used. Some EFI implementations support other filesystems for the ESP (like Apple with HFS+,) and I’ve not used one that won’t happily use an ESP on an MBR.