The reason that gcc with a -o option generates a.exe is because an incorrect value is being passed to the specs processing code for the link options. To dump a copy of the specs, use
gcc -dumpspecs >gcc1420.specs
The gory details of spec file syntax is at
https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.htmlTo see how gcc is processing the specs, use something like
gcc -v tmp.c
where tmp.c is minimal c program. I used
g++ -t -t v xcpt.cpp
because it was handy. The g++ output includes
COLLECT_GCC_OPTIONS='-pipe' '-v' '-t' '-t' '-mtune=generic' '-march=i686' '-dumpdir' 'a.'
ld.exe -o a.exe -t -t /@unixroot/usr/lib/crt0.o -LD:/usr2/local1420/bin/../lib/gcc/i686-pc-os2-emx/14 -LD:/usr2/local1420/bin/../lib/gcc -LD:/USR2/LOCAL1420/lib -L. -LD:/usr2/local1420/bin/../lib/gcc/i686-pc-os2-emx/14/../../.. -L/@unixroot/usr/lib E:\TMP/ccc6HJA2.o -lstdc++ -lm -lgcc_so_d -lc_alias -lc_dll -los2 -lgcc_so_d -lc_alias -lc_dll -los2 -lgcc_so_d -lc_alias -lc_dll -los2 -lgcc_so_d -lc_alias -lc_dll -los2
which is consistent with the symptoms. Note that the COLLECT_GCC_OPTIONS value for 9.2.0 omits the -dumpdir option, but this has no effect on the -o logic.
The -o is generated by the part of the *link: action that reads
%{!o*:-o %b%{Zdll|shared:.dll}%{!Zdll:%{!shared:%{!Zexe:.exe}}}}
which says if there is no explict -o switch use the value of the %b variable to build the executable name.
What we need to do is track down where %b is set and figure out why it defaults to "a" in 14.2.0. I suspect a lost patch since gcc on other plaforms is going to default the executable name to a.out.
FWIW, -t -t option sequence in my testcase has no effect here since emxomfld is not used.