How to Run 16 Bit Code on 32 Bit Linux

How to run 16 bit code on 32 bit Linux?

qemu, dosbox, bochs

Is it possible to run 16 bit code in an operating system that supports Intel IA-32e mode?

16-bit DOS apps can't run under 64-bit Windows, because virtual-8086 mode isn't available in long mode

However 16-bit protected mode is still available, so technically it's possible to run 16-bit Windows 3.x apps. That's how Wine runs 16-bit Windows apps in 64-bit Linux. Unfortunately 64-bit Windows doesn't have the same capability, although the reason is not because 64-bit mode cannot run 16-bit instructions but because the significant part has been increased.

The primary reason is that handles have 32 significant bits on 64-bit Windows. Therefore, handles cannot be truncated and passed to 16-bit applications without loss of data.

https://learn.microsoft.com/en-us/windows/win32/winprog64/running-32-bit-applications

So if you want to run 16-bit apps on 64-bit Windows you have to use a virtual machine

For more detailed information please read Peter Cordes' answer

See also Can a 64-bit computer (x86) run a 16-bit OS natively, without emulation?

Porting 16-bit DOS x86 assembly to 32-bit Linux x86 assembly

Minor Problem

Probably the main problem of your code "conversion" is that you seem to connect some ideas with the terms "80836 assembly" and "at&t" that don't really apply.

Although this might just be a matter of naming conventions there is no "80386 assembly" vs. "at&t" difference but a "intel" vs. "at&T syntax" difference as both intel syntax and at&t syntax can be used to describe x86 assembly code.

If you are using GNU assembler (I don't know any other x86 assembler using AT&T syntax instead of intel) you might just want to use .intel_syntax and stay with the intel syntax used in your reference material instead.

.intel_syntax noprefix
; your code in intel syntax here
.att_syntax prefix
; code in at&t syntax here

Don't forget to switch to 16-bit mode.code16 if you intend to use it in real mode.

Bigger Problem

The far the bigger problem with your question seems to be that you are not only trying to transform the code from using "intel-syntax" to using "at&t-syntax" but rather to port it to a. another addressing mode and b. another operating system.

Especially your question about interrupt calling conventions leads me to the assumption you are trying to port 16-bit DOS code to some kind of 32-bit code running on a LINUX machine.

Just "reusing" the given code to perform system calls won't be possible by simply replacing numbers as there a different calling conventions involved.

Things you might try to fix your code include using syscall read instead of BIOS interrupt to read from stdin

storage:
.ascii " "

# ...

movl $3, %eax # syscall number
# (check syscall.h to see if it's 3 on your system)
movl $0, %ebx # file descriptor (0 designating stdin)
movl $storage, %ecx
movl $1, %edx # number of chars to read
int $0x80

Code utilizing DOS syscall mechanism int 0x21 would have to be fixed in addition using something like

    movl $4, %eax      # syscall number write
movl $0, %ebx # file descriptor (1 designating stdout)
movl $storage, %ecx
movl $1, %edx # number of chars to write
int $0x80

The last step should be fixing the exit syscall:

    movl $1, %eax      # syscall number exit
movl $0, %ebx # it doesn't hurt to set a reasonable exit code here.
int $0x80

Requested Documentation Source

  • Regarding DOS syscalls taking a look at http://en.wikipedia.org/wiki/MS-DOS_API should help to understand what int 0x20 and int 0x21 are used for in your example code.

  • Seraching for BIOS interrupt also wikipedia is your friend: http://en.wikipedia.org/wiki/Bios_interrupt should answer your question.

    in your case it is int 0x16 with 0 in ah - thus: read character.



Related Topics



Leave a reply



Submit