With pe2boot you can run single 32-bit execuable on Windows, Linux/Wine,
DOS, or boot it on a bare hardware from CD/HD/FD/USB drive or via BOOTP.

Pe2boot takes a standard PE executable compiled with base relocations,
then compresses it and merges with a stub that lets it run everywhere.
Obviously, when running on Windows or Linux you can call Win32 functions,
however under DOS or on a bare hardware the app must use int86() instead.

You may use any compiler that can generate PE with base relocations:

   C:\> cl hello.c /link /fixed:no /subsystem:console /nodefaultlib msvcrt.lib

   C:\> tcc -shared hello.c -o hello.exe

   C:\> c:\mingw\bin\gcc -s -shared -nostdlib hello.c -o hello.exe -lmsvcrt

   $tux> mingw32msvc-gcc -s -shared -nostdlib hello.c -o hello.exe -lmsvcrt

Then run pe2boot (either on Windows or Linux) to create portable executable:

   pe2boot.exe -s pe_stub.bin  -i hello.exe -o hello.exe

Finally, pe2boot can create floppy or ISO images or make bootable USB drive:

   pe2boot.exe -b boot_fat.bin -i hello.exe -CD0 hello.iso   <- No emulation
   pe2boot.exe -b boot_fat.bin -i hello.exe -CD2 hello.iso   <- 1.44 emulation
   pe2boot.exe -b boot_fat.bin -i hello.exe -FLP hello.flp   <- 1.44 floppy
   pe2boot.exe -b boot_fat.bin -L "HELLO   EXE" -FAT \\.\U:  <- USB drive
   copy hello.exe u:\	 <- if you boot from USB drive it will load hello.exe

Now you can run or boot resulting executable in various environments:

  hello.exe           				<- "Hello World" Win32/Linux
  qemu -fda hello.flp 				<- "Hello World" boot floppy
  qemu -cdrom hello.iso				<- "Hello World" boot cdrom
  qemu -tftp . -bootp hello.exe -boot n 	<- Direct boot with BOOTP

pe_stub has a builtin debug monitor that traps execptions and "int 1":

	DBG 00001 CS IP/ERR_CD :stack+14 ...... :stack+2C ......
	AX=...... BP=...... SS :stack+10 ...... :stack+28 ......
	BX=...... SI=...... DS :stack+0C ...... :stack+24 ......
	CX=...... DI=...... ES :stack+08 ...... :stack+20 ......
	DX=...... FLAGS ...... :stack+04 ...... :stack+1C ......
	IP=...... [*EIP:3210]  :stack+00 ...... :stack+18 ......
	?   <-- type 'q,c,s' for Quit, Continue, or single Step.

After exception it dumps registers and quits, while "int 1" takes user inputs.


Here is more detailed technical info about the included runtimes:

  pe_stub - works everywhere: Windows,Linux,DOS,bare hardware  (1216 bytes)

	On DOS or noOS it detects memory, enables A20 line, sets up GDT, IDT,
	and switches into protected mode; IRQs are handled by real mode ints;
	exceptions are trapped by builtin debug monitor.

	Then, on all systems, it decompresses and rebases attached app code.
	Finally, on Windows or Wine, it loads DLLs and imports linked symbols.

  pe_win_stub - minimal subset of pe_stub for Windows/Linux only (352 bytes)

	It bends so many rules it is amazing it works on both Windows & Linux.

  pe_x86_stub - minimal subset of pe_stub for bare hardware only (141 bytes)

	Disables interrupts, sets GDT, and switches CPU into protected mode,
	then decompresses app and runs it passing boot disk# as an argument.
	Detecting memory, setting IDT, and handling IRQs is left to the app.

  pe_x86_test.c   -  "Hello World" example on top of pe_x86_stub (180 bytes)
  pe_x86_tiny.asm -  "Hello World" example on top of pe_x86_stub (172 bytes)

;
; Some technical details about compressed stream and decompression algoritm:
;
; Init control dword is followed by control dwords and data bytes
;
;  [init] [ctrl] ... data bytes ... [ctrl] ... data bytes ... [ctrl] ...
;
; Example: init=080081FDh: 3 prefix bits, 5 fixed bits, 8 extra bits (-X 358)
;
;		; bit stream		length code
;		; 1 xxxxx      		00..31
;		; 01 xxxxx     		32..63
;		; 000 xxxxx..xx  	00..2^(5+8=>13)-1
;		; 001 xxxxx..xx..xx	00..2^(5+8+8=>21)-1
;
; Then look at the suffix bits of the length code for next operation:
;
;   <n>  1 --> move n+1 bytes [src] -> [dst]
;   <n> 10 --> copy n+2 bytes [pop stack] -> [dst]
;   <n> 00 --> save dst into stack[n] position (stack shifts down)
;		if n >= stack_size then
;		<n>-stack_size ==> <x> 0 --> dword [dst] = <x>-1
;		<n>-stack_size ==> <x> 1 --> dword [dst] = <base>+<x>-1
;		<n>-stack_size ==> <0> 1 --> exit
;
; Operation after move is always copy or save (need only 1 suffix bit)
;
