Fun fact. The COM file size was limited to 64K. The program size was not. Most COM memory models set CS=DS=SS=ES. However, the Zortech C compiler, would have CS set differently.
CS pointed to the start of the code segment, DS to the start of the data segment. As long as the code segment plus the initialized data of the data segment was less than 64K, you could have a considerably larger runtime footprint (up to 128K) and still be a COM file with all near pointers.
There was a technique that used a thing called overlays[0]. You could write a program that is much larger than the available address space (64k on MS/PCDOS) but you split it up into functional areas or modules that are loaded on demand into a reserved area of your 64k address space.
I'm not sure when it started, but the .com and .exe extensions were ignored, and the loader looked at the first two bytes to see if it was "MZ" and was an exe file.
I like that every windows exe/dll still have the MZ on the front. Also a working DOS program there in the first hundred bytes which is pretty much a program to say 'hey run this in windows'. As the real windows header is 100 bytes in.