Frederick Gotham
2020-11-02 14:23:47 UTC
This is a follow-up to "Fat Binary - MS-Windows and four Linux" which I
multi-posted on 24 October 2020 to three newsgroups:
comp.lang.c, comp.lang.c++, comp.unix.programmer
You can see it here on comp.lang.c++:
https://groups.google.com/forum/#!topic/comp.lang.c++/uL2o62Ngk7c
Two days prior I posted "Making a Fat Binary for Linux and Mac", which
you can see here on comp.lang.c:
https://groups.google.com/forum/#!topic/comp.lang.c/Qev_btMilNI
I have now made a fat binary that contains 6 executable programs:
* 16-Bit MS-DOS (for 8088 processors and above)
* 32-Bit MS-Windows (which runs on x86_64 too)
* Linux arm32
* Linux arm64
* Linux x86_32
* Linux x86_64
For the Microsoft Windows executable file, I went with a 32-Bit
executable because it will run on both 32-Bit and 64-Bit versions of
MS-Windows.
I used the shareware "Pacific C" compiler to build the 16-Bit DOS
version, and originally I was going to embed this 16-Bit program as the
"MZ stub" inside the "PE" file for the Win32 program, however it was
simpler to keep the two programs separate and to use the method
described on the following webpage to embed a binary in a DOS batch file,
I used the "H2B" method that creates a COM program for printing hex as
binary:
http://www.massmind.org/techref/dos/binbat.htm
So here's how my 'combined Linux / DOS / Windows' script looks now. Note
that each line begins with four spaces. This script will run as an 'sh'
shell script on Linux, and will run as a batch file on MS-DOS and Windows.
[BEGIN SCRIPT]
:; if [ -z 0 ]; then #
@echo off
goto :MICROSOFT
fi
# Linux shell script starts here
# x86 32-Bit = i386, i686
# x86 64-bit = x86_64
# arm 32-Bit = arm
# arm 64-Bit = aarch64 aarch64_be armv8b armv8l
arch=`uname -m`
case ${arch} in
i386|i686)
skip=AAAAskipAAAA
count=AAAAcountAAA
;;
x86_64)
skip=BBBBskipBBBB
count=BBBBcountBBB
;;
arm|armv7l)
skip=CCCCskipCCCC
count=CCCCcountCCC
;;
aarch64|aarch64_be|armv8b|armv8l)
skip=DDDDskipDDDD
count=DDDDcountDDD
;;
*)
exit 1
;;
esac
tmpfile=$(mktemp /tmp/fatbinary_${arch}.XXXXXXXXXX)
dd if="$0" of=${tmpfile} bs=1 skip=${skip} count=${count} > /dev/null 2>&1
chmod +x ${tmpfile}
${tmpfile} "$@"
retval=$?
rm -rf "$tmpfile"
exit ${retval}
# Microsoft batch file starts here
:MICROSOFT
VER | FIND "Windows" > NUL
IF ERRORLEVEL 1 GOTO DOS_16_BIT
REM Script for Windows 95 and above starts here (32-Bit)
REM The next 6 lines are just for creating a temporary file
:loop
set /a y$$=%random%+100000
set y$$=temp%y$$:~1,2%.%y$$:~-3%
if exist "%temp%\%y$$%.exe" goto loop
set "y$$=%temp%\%y$$%"
set "tempfile=%y$$%.exe"
findstr /v /c:" " "%~f0" > %tempfile%
%tempfile% %1 %2 %3 %4 %5 %6 %7 %8 %9
set "finalerrorcode=%ERRORLEVEL%"
del %tempfile%
exit /b %finalerrorcode%
:DOS_16_BIT
REM Script for MS-DOS v6.22 and below starts here (16-Bit)
IF EXIST %0.BAT %0.BAT %1 %2 %3 %4 %5 %6 %7 %8 %9
REM The next 6 lines are to create the DOS COM program "hex to binary"
ECHO ***@jzh`0X-`/PPPPPPa(DE(DM(DO(Dh(Ls(Lu(LX(LeZRR]EEEUYRX2Dx=>%TEMP%\H2B_@!7$.COM
ECHO 0DxFP,0Xx.t0P,=XtGsB4o@$?PIyU WwX0GwUY Wv;ovBX2Gv0ExGIuht6>>%TEMP%\H2B_@!7$.COM
ECHO ?@}I{uNWEF~***@KLtH]~***@SuNS`{ECCttasae~BHM>>%TEMP%\H2B_@!7$.COM
ECHO AcjFnvnHAwrvx[}gIKDw??Frt\gqj~{?s?csIsqo{O_KtBve{Sx{nB{Eu@>>%TEMP%\H2B_@!7$.COM
ECHO fq`tkfk?***@oKCA_?_E@?WxAs?agBwRjnLK?***@w`G`LKLAcyA?@xAsZpk`L>>%TEMP%\H2B_@!7$.COM
ECHO ~***@vAc_A_yBJ@xAGZp?o?sBXq`***@xUrFQt=A_E?B?~rB?~r0>>%TEMP%\H2B_@!7$.COM
%TEMP%\H2B_@!7$ " ::dos16bit" < %0 > %TEMP%\S256@!7$.EXE
DEL %TEMP%\H2B_@!7$.COM
%TEMP%\S256@!7$.EXE %1 %2 %3 %4 %5 %6 %7 %8 %9
DEL %TEMP%\S256@!7$.EXE
EXIT
REM The exit command won't work so must use goto with a bad label
GOTO NO_SUCH_LABEL
[END SCRIPT]
The Linux part of the above script has "\n" line endings, whereas the
Microsoft part of the above script has "\r\n" line endings. See the
first link at the end of this post to get the original file which also
has the hex values for the 16-Bit DOS program at the end.
As for the program for which I chose to make a fat binary, I went with a
sha256 digest calculator, using code by Alain Mosnier from repository:
https://github.com/amosnier/sha-2
I have turned Mosnier's code into a single-source-file C program that
calculates the sha256 digest of its first command line argument. For the
C code, see the second link at the end of this post.
I compiled this C program 6 times and got the 6 following binaries:
-rwxr-xr-x 1 root root 7842 Nov 2 12:15 prog_dos16bit.exe
-rwxr-xr-x 1 root root 17422 Oct 24 11:10 prog_mswin_x86_32.exe
-rwxr-xr-x 1 root root 5464 Oct 24 13:50 prog_x86_32
-rwxr-xr-x 1 root root 10216 Oct 24 13:50 prog_x86_64
-rwxr-xr-x 1 root root 5528 Oct 24 13:50 prog_arm32
-rwxr-xr-x 1 root root 10080 Oct 24 13:50 prog_arm64
(See download links 3-8 at the end of this post)
The DOS program is concatenated to script as hex values:
cat prog_dos16bit.exe | xxd -p \
| awk '{ print \" ::dos16bit \" $s \"\\r\" }' >> script.txt
and I concatenated the 5 other binaries as follows:
cat script.txt prog_mswin_x86_32.exe prog_x86_32 prog_x86_64 \
prog_arm32 prog_arm64 > ftsha256.bat
The result is my fat binary with size 75 kilobytes:
-rwxr-xr-x 1 root root 75016 Nov 2 13:52 ftsha256.bat
(See download link 9 at the end of this post)
This file can be executed at the command line on any PC like this:
ftsha256.bat This is my message
And it prints the digest:
3311b7c0bd91b6c73a38212de8ade31c51910f17480ad212ed2b9798a35b7747
I have verified it works on:
* MS-DOS 6.22
* MS-Windows XP 64-Bit
* Linux arm32
* Linux arm64
* Linux x86_64
It should also work on Linux x86 32-Bit, let me know if someone tries
it. It might need more work on the ASCII/ANSI versions of MS-Windows
that came between Windows 3.11 and Windows 2000, I haven't tried it so
I'm not sure.
I'm gonna take a break from this for a while, but in the future I might
iron out the ASCII versions of MS-Windows, and then later add in
binaries for Apple MacOS.
Links:
1: http://virjacode.com/experimental3/script.txt
2: http://virjacode.com/experimental3/sha256.c
3: http://virjacode.com/experimental3/prog_dos16bit.exe
4: http://virjacode.com/experimental3/prog_mswin_x86_32.exe
5: http://virjacode.com/experimental3/prog_arm32
6: http://virjacode.com/experimental3/prog_arm64
7: http://virjacode.com/experimental3/prog_x86_32
8: http://virjacode.com/experimental3/prog_x86_64
9: http://virjacode.com/experimental3/ftsha256.bat
multi-posted on 24 October 2020 to three newsgroups:
comp.lang.c, comp.lang.c++, comp.unix.programmer
You can see it here on comp.lang.c++:
https://groups.google.com/forum/#!topic/comp.lang.c++/uL2o62Ngk7c
Two days prior I posted "Making a Fat Binary for Linux and Mac", which
you can see here on comp.lang.c:
https://groups.google.com/forum/#!topic/comp.lang.c/Qev_btMilNI
I have now made a fat binary that contains 6 executable programs:
* 16-Bit MS-DOS (for 8088 processors and above)
* 32-Bit MS-Windows (which runs on x86_64 too)
* Linux arm32
* Linux arm64
* Linux x86_32
* Linux x86_64
For the Microsoft Windows executable file, I went with a 32-Bit
executable because it will run on both 32-Bit and 64-Bit versions of
MS-Windows.
I used the shareware "Pacific C" compiler to build the 16-Bit DOS
version, and originally I was going to embed this 16-Bit program as the
"MZ stub" inside the "PE" file for the Win32 program, however it was
simpler to keep the two programs separate and to use the method
described on the following webpage to embed a binary in a DOS batch file,
I used the "H2B" method that creates a COM program for printing hex as
binary:
http://www.massmind.org/techref/dos/binbat.htm
So here's how my 'combined Linux / DOS / Windows' script looks now. Note
that each line begins with four spaces. This script will run as an 'sh'
shell script on Linux, and will run as a batch file on MS-DOS and Windows.
[BEGIN SCRIPT]
:; if [ -z 0 ]; then #
@echo off
goto :MICROSOFT
fi
# Linux shell script starts here
# x86 32-Bit = i386, i686
# x86 64-bit = x86_64
# arm 32-Bit = arm
# arm 64-Bit = aarch64 aarch64_be armv8b armv8l
arch=`uname -m`
case ${arch} in
i386|i686)
skip=AAAAskipAAAA
count=AAAAcountAAA
;;
x86_64)
skip=BBBBskipBBBB
count=BBBBcountBBB
;;
arm|armv7l)
skip=CCCCskipCCCC
count=CCCCcountCCC
;;
aarch64|aarch64_be|armv8b|armv8l)
skip=DDDDskipDDDD
count=DDDDcountDDD
;;
*)
exit 1
;;
esac
tmpfile=$(mktemp /tmp/fatbinary_${arch}.XXXXXXXXXX)
dd if="$0" of=${tmpfile} bs=1 skip=${skip} count=${count} > /dev/null 2>&1
chmod +x ${tmpfile}
${tmpfile} "$@"
retval=$?
rm -rf "$tmpfile"
exit ${retval}
# Microsoft batch file starts here
:MICROSOFT
VER | FIND "Windows" > NUL
IF ERRORLEVEL 1 GOTO DOS_16_BIT
REM Script for Windows 95 and above starts here (32-Bit)
REM The next 6 lines are just for creating a temporary file
:loop
set /a y$$=%random%+100000
set y$$=temp%y$$:~1,2%.%y$$:~-3%
if exist "%temp%\%y$$%.exe" goto loop
set "y$$=%temp%\%y$$%"
set "tempfile=%y$$%.exe"
findstr /v /c:" " "%~f0" > %tempfile%
%tempfile% %1 %2 %3 %4 %5 %6 %7 %8 %9
set "finalerrorcode=%ERRORLEVEL%"
del %tempfile%
exit /b %finalerrorcode%
:DOS_16_BIT
REM Script for MS-DOS v6.22 and below starts here (16-Bit)
IF EXIST %0.BAT %0.BAT %1 %2 %3 %4 %5 %6 %7 %8 %9
REM The next 6 lines are to create the DOS COM program "hex to binary"
ECHO ***@jzh`0X-`/PPPPPPa(DE(DM(DO(Dh(Ls(Lu(LX(LeZRR]EEEUYRX2Dx=>%TEMP%\H2B_@!7$.COM
ECHO 0DxFP,0Xx.t0P,=XtGsB4o@$?PIyU WwX0GwUY Wv;ovBX2Gv0ExGIuht6>>%TEMP%\H2B_@!7$.COM
ECHO ?@}I{uNWEF~***@KLtH]~***@SuNS`{ECCttasae~BHM>>%TEMP%\H2B_@!7$.COM
ECHO AcjFnvnHAwrvx[}gIKDw??Frt\gqj~{?s?csIsqo{O_KtBve{Sx{nB{Eu@>>%TEMP%\H2B_@!7$.COM
ECHO fq`tkfk?***@oKCA_?_E@?WxAs?agBwRjnLK?***@w`G`LKLAcyA?@xAsZpk`L>>%TEMP%\H2B_@!7$.COM
ECHO ~***@vAc_A_yBJ@xAGZp?o?sBXq`***@xUrFQt=A_E?B?~rB?~r0>>%TEMP%\H2B_@!7$.COM
%TEMP%\H2B_@!7$ " ::dos16bit" < %0 > %TEMP%\S256@!7$.EXE
DEL %TEMP%\H2B_@!7$.COM
%TEMP%\S256@!7$.EXE %1 %2 %3 %4 %5 %6 %7 %8 %9
DEL %TEMP%\S256@!7$.EXE
EXIT
REM The exit command won't work so must use goto with a bad label
GOTO NO_SUCH_LABEL
[END SCRIPT]
The Linux part of the above script has "\n" line endings, whereas the
Microsoft part of the above script has "\r\n" line endings. See the
first link at the end of this post to get the original file which also
has the hex values for the 16-Bit DOS program at the end.
As for the program for which I chose to make a fat binary, I went with a
sha256 digest calculator, using code by Alain Mosnier from repository:
https://github.com/amosnier/sha-2
I have turned Mosnier's code into a single-source-file C program that
calculates the sha256 digest of its first command line argument. For the
C code, see the second link at the end of this post.
I compiled this C program 6 times and got the 6 following binaries:
-rwxr-xr-x 1 root root 7842 Nov 2 12:15 prog_dos16bit.exe
-rwxr-xr-x 1 root root 17422 Oct 24 11:10 prog_mswin_x86_32.exe
-rwxr-xr-x 1 root root 5464 Oct 24 13:50 prog_x86_32
-rwxr-xr-x 1 root root 10216 Oct 24 13:50 prog_x86_64
-rwxr-xr-x 1 root root 5528 Oct 24 13:50 prog_arm32
-rwxr-xr-x 1 root root 10080 Oct 24 13:50 prog_arm64
(See download links 3-8 at the end of this post)
The DOS program is concatenated to script as hex values:
cat prog_dos16bit.exe | xxd -p \
| awk '{ print \" ::dos16bit \" $s \"\\r\" }' >> script.txt
and I concatenated the 5 other binaries as follows:
cat script.txt prog_mswin_x86_32.exe prog_x86_32 prog_x86_64 \
prog_arm32 prog_arm64 > ftsha256.bat
The result is my fat binary with size 75 kilobytes:
-rwxr-xr-x 1 root root 75016 Nov 2 13:52 ftsha256.bat
(See download link 9 at the end of this post)
This file can be executed at the command line on any PC like this:
ftsha256.bat This is my message
And it prints the digest:
3311b7c0bd91b6c73a38212de8ade31c51910f17480ad212ed2b9798a35b7747
I have verified it works on:
* MS-DOS 6.22
* MS-Windows XP 64-Bit
* Linux arm32
* Linux arm64
* Linux x86_64
It should also work on Linux x86 32-Bit, let me know if someone tries
it. It might need more work on the ASCII/ANSI versions of MS-Windows
that came between Windows 3.11 and Windows 2000, I haven't tried it so
I'm not sure.
I'm gonna take a break from this for a while, but in the future I might
iron out the ASCII versions of MS-Windows, and then later add in
binaries for Apple MacOS.
Links:
1: http://virjacode.com/experimental3/script.txt
2: http://virjacode.com/experimental3/sha256.c
3: http://virjacode.com/experimental3/prog_dos16bit.exe
4: http://virjacode.com/experimental3/prog_mswin_x86_32.exe
5: http://virjacode.com/experimental3/prog_arm32
6: http://virjacode.com/experimental3/prog_arm64
7: http://virjacode.com/experimental3/prog_x86_32
8: http://virjacode.com/experimental3/prog_x86_64
9: http://virjacode.com/experimental3/ftsha256.bat