I'm able to use NASM to assemble simple COM files from my modern Linux computer, but how can I create a DOS EXE file while still in Linux?

Specifically, I am interested in a solution that will target 8088 and 80286 processors from a X64 Linux host. Many modern solutions only target 80386 and above.

  • Would this Q be better on supercomputer.com? Or is it about retro hardware specifically somehow? – Xen2050 Jan 5 '18 at 7:19
  • 2
    @Xen2050 - most open source toolchains that target DOS do so on the assumption of a target running a modern processor, so tend to use 386-specific protected mode targets, which is unlikely to be what's wanted here. I'd say this is relevant here. – Jules Jan 5 '18 at 9:15
  • 4
    (Also: Wikipedia seems to believe versions of NASM prior to 0.90 never existed. Wikipedia is wrong.) – Jules Jan 5 '18 at 10:01
  • 2
    "Wikipedia is wrong." - wouldn't be the first time ;-) – Xen2050 Jan 5 '18 at 10:02
  • 1
    @RuiFRibeiro - Wikipedia policy is that you should generally avoid editing articles that are about yourself, and as I'm named in that article I'd probably be cutting it a bit too fine. I also don't have any useful references, which are also generally required for wikipedia policy. – Jules Jan 5 '18 at 11:29

It turns out that FASM can generate MZ 16-bit DOS executables directly:

format MZ

mov ah, 9h
mov dx, hello
int 21h

mov ax, 4c00h
int 21h

hello db 'Hello, world!', 13, 10, '$'

Which can be assembled and linked automatically:

$ fasm hello.asm

It's not the same format as NASM, but it works for my purposes for now.


NASM can generate OMF-format object files, which are the most common format for DOS programs (although there are other options -- e.g. DJGPP uses COFF format object files, but IIRC the results needs a 386 to run). A search for linkers that support this format turns up few possibilities:

  • JWLink is a fork of the old Watcom linker, which was open-sourced a while back. This is probably your best bet of all of the possibilities I list here because it's a known-working linker that has an officially supported Linux port. I'm including the other options below only for completeness sake, because I found them first. It seems that the only problem with this version is that it doesn't support the DOS/16M DOS extender environment that was usually used with Watcom's tools, so if you wanted to do that you'd probably need to run the official Watcom linker under DOS. I think it does support DOS/4GW, but that requires a 386 to run.

  • WarpLink, which seems to be primarily designed to run in DOS, and is largely written in assembly language modules written using the MASM syntax. You may be able to get this to assemble using JWASM, which is an open-source version of the Watcom assembler, which was somewhat compatible. Some modules are written in C, and if you're lucky this means the IO is handled in those modules so it may be possible to port to Linux. Unfortunately, I have no experience using it, so can't advise beyond this.

  • If you can't get that to run under Linux, another possibility would by JLoc. JLoc is shareware, rather than open source, and the standard distribution is for DOS 386 protected mode. However, its author John Fine was involved in NASM development back in the late 90s and if you can find him (his home page has disappeared, but he may still be contactable via the email address in the linked documentation) may be persuaded to either open source it or release a Linux version. The code is apparently written in C (for DJGPP) so should be somewhat easier to port.

If all else fails, if you have experience working in C writing a linker yourself isn't actually out of the question. The EXE (or "MZ" as it's sometimes known) file format is simple, and there are available libraries that can load object files -- or you can use NASM's "rdf" output format, which was intentionally designed to be as simple as possible in order to support writing custom linkers. There's an example of an extremely simple flat-format output linker in the NASM source code that could server as a starting point for a linker that produces EXE files. You may need to hack the NASM source code a bit to make RDF work in this context -- it doesn't support segment relocations at present, but it should be pretty simple to add them. If you get stuck on that, add a comment here with a way to contact you off this site and I'll try to find some time to assist. It's been a while since I did any hacking on NASM, but I don't think it's changed much since then, so I ought to be able to figure it out reasonably quickly.

(Edit: I previously also sugested 'alink', but having had a look through the source code it seems to only support 32-bit protected mode output using a DPMI DOS extender)


I think the easiest way is to use DOSBOX like emulator on Linux and use NASM inside it. That way you can test your code directly in MS-DOS environment (even if just emulated).

I am not a Linux user so I do not know if DOSBOX works correctly on Linux but simple google search DOSBox - Runs Old MS-DOS Games/Programs in Linux - Tecmint suggest it does. Just do not forget to increase the number of CPU tics to match desired Speed.

Both NASM and TASM works under Windows DOSBOX so I see no reason why it should not work in Linux either. Here few relate SO/SE QAs of mine (all are *.com however):

You just need NASM binaries for MS-DOS to make this work.

IIRC To create an *.exe file from NASM the code should look a bit differently than the *.com file and also the switches are a bit different.

In NASM the *.com file looks like this:

[BITS 16]
[ORG 100h]

[SEGMENT .text]
    ;here goes the code

And this is my vc.ext entry to compile it in Volcov commander:

    @c:\language\compil\nasm\nasm.exe -ic:\language\source\nasm\inc\ -w+orphan-labels -o !.com !.!

I did not do *.exe files at that time so I do not have any example. All I found is some protected mode demo and from it the source code for exe is different:

;;; Init Flat 32 bit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%include "pmode.lib"
;;; Main: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bits 32
_main:      sti

        mov     bx,101h
        mov     ax,4f02h
        int     10h

        call    _getselector
        mov     edx,0A0000h
        call    [_setselector]
        mov     es,ax

        mov edi,0
        mov al,13
        mov ecx,65535
        rep stosb

        mov ax,0
        int 16h
        mov ax,3
        int 10h

        mov     ax,es
        call    _freeselector
        mov     es,[_seldata]
        jmp     _exit
;;; End. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Where pmode.inc contains subroutines macros and stuff defined under:

section code
bits 16

The compilation and link vc.ext entry using turbo assembler linker:

    @c:\language\compil\nasm\nasm.exe -ic:\language\source\nasm\inc\ -w+orphan-labels -f obj !.!
    @c:\language\compil\tasm\tlink.exe /3 /x !.obj , !.exe
    @del !.obj

So without protected mode all the stuff should be in 16 bit I think...

Do not forget to use your own paths in the vc.ext file...

  • Seeing the lack of available linkers as I discovered researching my answer, I'd highly recommend taking this route. Unless you really need to run your build process in Linux, this is likely to be a much better way. – Jules Jan 5 '18 at 10:37
  • Another possibility rather than DOSBox would be the older DosEmu -- which just runs a standard DOS installation in the processor's V86 mode, rather than emulating an older processor, so should give faster performance than DOSBox. – Jules Jan 5 '18 at 10:39
  • @Jules faster emulation can lead to CRT200 error as many of the older MSDOS tools where Borland CRT based. In such case slow utility sometimes helps. In real MS-DOS I turn off the caches in BIOS but in such case I would not run LINUX ... – Spektre Jan 5 '18 at 10:45
  • 1
    I can't remember where I found it now, but I did some work a few years back that involved resurrecting some old Borland Pascal source code, and Borland Pascal had the same issue with timing loops; I found a tool at that time that could patch .EXE files produced using Borland tools and modify the timing loop that overflows so that it can work on modern hardware. – Jules Jan 5 '18 at 11:20
  • @Jules Yes I know of that fix but it does not work in all cases (IIRC it got problem with some packed executables). I still got it somewhere on the shelf under serious layer of dust probably. – Spektre Jan 5 '18 at 12:24

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.