1

I'm trying to call the BIOS 10h interrupt function 0Eh (teletype output) to print a string on real mode (testing with QEMU). In NASM I have no problem, program prints string correctly:

bits 16                             ; Use 16 bit code
section .text

boot:
    xor ax, ax                      ; Clear AX register
    mov ds, ax                      ; Clear DS register
    mov es, ax                      ; Clear ES register
    mov ss, ax                      ; Clear SS register
    mov si, hello                   ; Set SI to string
    mov ah, 0x0E                    ; Set function
.loop:
    lodsb                           ; Store character into AL
    or al, al                       ; Check for NULL end
    jz halt                         ; On NULL end
    int 0x10                        ; Call 10h interrupt
    jmp .loop                       ; Continue with next character
halt:
    cli
    hlt

hello: db "Hello, World!", 0

times 510 - ($-$$) db 0
dw 0xAA55

I produce the floppy image with the following orders:

nasm -f elf64 boot.asm -o boot.o
ld -Ttext 0x7c00 boot.o -o boot.out
objcopy -O binary -j .text boot.out boot.bin
dd if=/dev/zero of=floppy.img bs=1024 count=720
dd if=boot.bin of=floppy.img conv=notrunc

But in FASMemphasized text doesn't prints the string correctly:

format elf64
use16
section '.text'
org 0x0

boot:
    cld                             ; Clear direction flag
    xor ax, ax                      ; Clear AX register
    mov ds, ax                      ; Clear DS register
    mov es, ax                      ; Clear ES register
    mov ss, ax                      ; Clear SS register
    mov si, hello                   ; Set SI to string
    mov ah, 0x0E                    ; Set function
puts:
    lodsb                           ; Store character into AL
    or al, al                       ; Check for NULL end
    jz halt                         ; On NULL end
    int 0x10                        ; Call 10h interrupt
    jmp puts                        ; Continue with next character
halt:
    cli
    hlt

hello: db "Hello, World!", 0

times 510 - ($-$$) db 0
dw 0xAA55

And to produce the floppy image:

fasm boot.asm boot.o
ld -Ttext 0x7c00 boot.o -o boot.out
objcopy -O binary -j .text boot.out boot.bin
dd if=/dev/zero of=floppy.img bs=1024 count=720
dd if=boot.bin of=floppy.img conv=notrunc

What I'm missing?

Michael Petch
  • 42,023
  • 8
  • 87
  • 158
  • 3
    Use `org 0x7c00` in your FASM code and remove the `-Ttext=0x7c00` from the linker command – Michael Petch Jun 10 '18 at 20:53
  • 3
    The `-Ttext=0x7c00` doesn't do anything with FASM generated ELF objects because FASM unlike NASM doesn't output relocation entries and thus LD doesn't have any addresses to fix up. Telling FASM to use `org 0x7c00` instead of `org 0x0` gets FASM to output the right addresses to begin with. – Michael Petch Jun 10 '18 at 21:06
  • 3
    If you set SS you should be setting SP as well so that SS:SP point to an area of memory where it won't interfere with the operation of your code. – Michael Petch Jun 10 '18 at 21:12
  • Thanks for your answer! – Bruno Mondelo Jun 11 '18 at 07:57

1 Answers1

1

FASM can directly generate binary and executable files. In fact using FASM with object files and linker is needed only if you want to use the code together with some high level language.

Actually this property of FASM, together with its highly portability makes FASM the favorite assembler of the OS developers.

Also, BIOS will set the segment registers to 0 and will set SP to some reasonable value, so you don't need to set them at all.

Here is your code, stripped from the not needed parts and with proper directives (boot.asm):

        format binary as "bin"
        use16
        org     7c00h

boot:
        cld                     ; Clear direction flag

        mov     si, hello       ; Set SI to string
        mov     ah, 0x0E        ; Set function
puts:
        lodsb                   ; Store character into AL
        or      al, al          ; Check for NULL end
        jz      halt            ; On NULL end
        int     0x10            ; Call 10h interrupt
        jmp     puts            ; Continue with next character
halt:
        cli
        hlt

hello   db "Hello, World!", 0   ; don't use ":" for the data definitions.

        times 510 - ($-$$) db 0
        dw 0xAA55

After compilation you will get directly a properly compiled binary file: boot.bin;

Here are the minimal commands in order to run your boot sector:

$fasm boot.asm
$qemu-system-x86_64 -drive format=raw,media=disk,if=floppy,file=./boot.bin

Notice that you can feed the binary file directly to the qemu emulator without creating special floppy.img file.

johnfound
  • 6,751
  • 2
  • 25
  • 53
  • [Displaying characters with DOS or BIOS](https://stackoverflow.com/q/44747002) points out that int 0x10 / AH = 0xE takes more parameters, including BH/BL for page number and color if graphics mode. http://www.ctyme.com/intr/rb-0106.htm. So it's a good idea to `mov bx,0007h`. – Peter Cordes Mar 04 '21 at 11:34
  • Also, [`or al, al` is an old bad idiom](https://stackoverflow.com/questions/33721204/test-whether-a-register-is-zero-with-cmp-reg-0-vs-or-reg-reg/33724806#33724806). Use `test al,al` to set FLAGS according to a register value. – Peter Cordes Mar 04 '21 at 11:36
  • This is missing setup of DS. The BIOS won't necessarily have DS=ES=0 so you should `xor ax,ax` / `mov ds, ax`, like in [How to make the kernel for my bootloader?](https://stackoverflow.com/q/33603842). (`lodsb` uses DS:SI so you can leave ES unset for this specific program.) – Peter Cordes Mar 04 '21 at 11:41