Creating a Bootable Program in x86 Assembly Language

Booting the machine is the first step towards writing your own operating system. You’re the wind, baby.

1. Download and install the latest version of FASM (Flat Assembler), if you have not already done so. Details are given in a previous tutoral.

2. Download the latest version of QEMU, by Fabrice Bellard. QEMU is an open-source processor emulator, and is available as source code at Unfortunately, no precompiled binaries are available on the QEMU site itself. However, a link is provided to an “unofficial” archive of Windows binaries, which as of this writing is available at

3. Install QEMU by uncompressing the archive file to any desired directory. Make a note of where the file “qemu.exe” is located.

4. In any convenient location, create a new directory named “HelloWorldBootable”.

5. In the newly created HelloWorldBootable directory, create a new text file named “HelloWorldBootable.asm”, containing the following text.

use16       ; 16-bit mode
org 0x7C00 ; this is the address of the boot sector

    mov ah,0x00 ; reset disk
    mov dl,0    ; drive number
    int 0x13    ; call BIOS interrupt routine
    ; load the sector from disk using BIOS interrupt 0x13
    mov ah,0x02 ; read sectors into memory
    mov al,1    ; number of sectors to read
    mov dl,0    ; drive number
    mov ch,0    ; cylinder number
    mov dh,0    ; head number
    mov cl,2    ; starting sector number
    mov bx,Main ; memory location to load to 
    int 0x13    ; call BIOS interrupt routine
    jmp Main    ; now that it's been loaded

    ; pad out all but the last two bytes of the sector with zeroes
    times ((0x200 - 2) - ($ - $$)) db 0x00

    dw 0xAA55 ; these must be the last two bytes in the boot sector


org 0x7E00 ; the address of the sector after the boot sector


    mov si,TextHelloWorld ; point the si register at the string to display
    mov ah,0x0E           ; for int 0x10: write chars in teletype mode

    ForEachChar:          ; begin loop

        lodsb             ; load al with what si points to, increment si
        cmp al,0x00       ; if char is null...
        je EndForEachChar ; .. then break out of the loop
        int 0x10          ; call interrupt 0x10 (BIOS: print char)

    jmp ForEachChar       ; jump back to beginning of loop
    EndForEachChar:       ; end of the loop

    ret                   ; quit the program

    ; data to display
    TextHelloWorld: db 'Hello, world!',0

    times ((0x200) - ($ - $$)) db 0x00

6. Still in the HelloWorldBootable directory, create a new text file named “BuildEnvironmentSetup-FasmQemu.bat”, containing the following text. Substitute the names of the directories containing fasm.exe and qemu.exe in the appropriate places. Don’t put quotes around the directory paths–FASM doesn’t seem to understand them.

set fasmPath=[the directory where fasm is located]
set qemuPath=[the directory where qemu is located]
for %%* in (.) do (set programName=%%~n*)'

7. Still in the HelloWorldBootable directory, create a new text file named “ProgramBuildAndRun-FasmQemu.bat”, containing the following text.

call BuildEnvironmentSetup-FasmQemu.bat

%fasmPath%\fasm.exe %programName%.asm %programName%.img
%qemuPath%\qemu.exe -boot a -fda %programName%.img


8. Double-click the icon for ProgramBuildAndRun-FasmQemu.bat to run it. A console window will appear, FASM will assemble the code in the asm file into a binary img file, and then QEMU will attempt to boot from this binary file. A QEMU window should appear, and the text “Hello, World!” should be visible within it.


  • Obviously, QEMU is only a simulation of a real machine. In order to actually boot an actual machine with this code, you need some way to write it to the physical sectors of a disk. Modern operating systems go out of their way to make that sort of thing difficult, for the very good reason that it’s an almost guaranteed way to accidentally turn an existing filesystem into a useless, smoking wreck. That being said, you could possibly use QEMU itself to write to a (hopefully blank) disk’s sectors directly, by mounting the source and destination disks on the command line you use to call QEMU, and using the BIOS disk read and write interrupt routines to transfer the sectors. For now, this is left as an exercise for the reader. Don’t say I didn’t warn you.
  • Instead of QEMU, you could also boot this program in an alternate virtualization hypervisor, such as VirtualBox. For VirtualBox, create a new machine with “Other/Unknown” operating system, open its settings, click the “Storage” item, click the “Add New Controller” button under the Storage Tree box, and select “Add Floppy Controller” from the menu that appears. Then insert the .img file in the new floppy drive and start the virtual machine.
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

2 Responses to Creating a Bootable Program in x86 Assembly Language

  1. cirosantilli says:

    To work on Ubuntu 14.04 with QEMU and NASM I needed: 1) `mov dl,0x80` instead of 0: that is the first drive. 2) Remove `org 0x7E00`. Redundant given the `times` above, and gives compilation error. 3) Use 0x400 in `times ((0x200) – ($ – $$)) db 0x00`: we are filling until byte 0x400. `$$` means the current section, which is the first byte of this program.
    || Working GAS example:

  2. cirosantilli says:

    How does that `ret` work at the end without a `call`?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s