1

I just started messing around with assembly language and I tried to print the number 9 on console. Here is what I wrote:

global _main

section .data

    digit equ 9

section .bss

section .text

    _main:

        mov edx, 1  
        mov ecx, digit
        add ecx, 48
        mov ebx, 1
        mov eax, 4  
        int 21h     

    ret

I know I can do it using extern _printf but I want try it with interrupts. I thought 21h is a windows interrupt. So, what interrupt code should I use?

David Hoelzer
  • 15,862
  • 4
  • 48
  • 67
  • `int 21h` isn't the Windows interrupt, its the MS-DOS one. Otherwise the format of your code looks like a Linux system call. What operating system are you trying to run this on? – Ross Ridge Jun 10 '15 at 18:24
  • `Int 21h` is MSDOS, `Int 80h` is 32-bit-Linux, `syscall` is 64-bit-Linux, in Windows you call the oparting system with names like `WriteFile`. Please show the commands to build the executable file. – rkhb Jun 10 '15 at 18:25
  • @RossRidge I am trying to run this on windows –  Jun 10 '15 at 18:30
  • @rkhb `nasm -f elf test.asm` and `gcc test.o -o test` –  Jun 10 '15 at 18:31
  • @rkhb Yes I have MinGW installed –  Jun 10 '15 at 18:45
  • 1
    If you want to go the route of building your own bootsector so that you can get raw access to the machine, you can make use of BIOS calls or raw memory access. `INT 21h` is, as pointed out, an MSDOS call. If you write to 0xb8000 (`MOV AX, 0xb800 MOV DS, AX MOV AX, 0 MOV [DS:AX], 'A') you can write directly to the text screen memory. Using BIOS interrupts you can use `INT 10h` with a value of 0x0a in `AH`, the character to write in `AL`, a zero in `BH` and a 1 in `CX` to print a character at the current cursor position. – David Hoelzer Jun 10 '15 at 19:09
  • @DavidHoelzer That's exactly what I am trying to achieve, can you post a clear example? –  Jun 10 '15 at 22:16
  • Related GAS hello world question: http://stackoverflow.com/questions/32508919/how-to-produce-a-minimal-bios-hello-world-boot-sector-with-gcc-that-works-from-a and a repository with examples: https://github.com/cirosantilli/x86-bare-metal-examples – Ciro Santilli OurBigBook.com Sep 11 '15 at 09:09

1 Answers1

3

Here's an example from a course that I teach. This is a raw bootsector that you can compile directly as an object file and use as a bootable floppy or USB image in something like Qemu, VirtualBox, VMWare, Bochs or a real machine.

This makes use of the real mode BIOS interrupt 16 (0x10) for character output. I think this is what you're trying to get at with your question. :)

;
;   x86 real mode boot sector template
;   David Hoelzer, 2011 - Assembly Bootcamp
;
;   x86 architecture systems all support MBR style boot sectors.  An
;   MBR boot sector must be 512 bytes in length and have machine
;   language code originating at 0000:7c00.  Additionally, it must
;   have the signature "0x55aa" as the final word in the sector or it
;   is not a valid boot sector.


; This is a basic Hello World example.  Here we will uses BIOS interrupt
; 0x10 which can be used for all manner of screen output.  This version uses
; the write-string function, which is int 0x10, ah = 13h:
;
;   BIOS Write String: INT 10h
;       AH = 13h    Function number
;       AL -        Bit 0 - Update cursor position after writing?
;                   Bit 1 - String contains attributes?
;       BH          Video page number       
;       BL          Attributes to apply to string for text only strings
;       CX          Number of characters to print
;       DH          Row to start printing at (0,0 is top left corner)
;       DL          Column to start printing at
;       [ES:BP]     Far pointer to string to print

org 0x7c00      ; BIOS will load the MBR to this location 
                ; and then jump here to continue execution


                mov ax, cs          ; Where are we now?  
                                    ; Could be 0000:7c00 or
                                    ; 07c0:0000 or some other
                                    ; combo.
                mov ds, ax          ; Our data is here too.
                mov es, ax          ; ES:BP is the pointer
                                    ; to the string.  ES should
                                    ; match DS and CS.
                mov bp, message     ; Offset of our message
                mov bh, 0           ; Video page 0
                mov bl, 00001111b   ; Attributes:  Bright white foreground
                                    ; on a black background, no flashing
                mov cx, [length]    ; String length
                mov al, 1           ; Bit zero is on: Update position
                                    ; Bit one is off: No attributes in string
                mov ah, 0x13        ; Function number
                mov dx, 0           ; Row,Column = 0,0
                int 0x10            ; Call the function

                jmp $

message     db      "Hello, World!"
length      db      (length - message)
                            ; As stated above, the boot sector must 
times   510-($-$$) db 0     ; Create padding to fill out to 510 bytes
dw      0xaa55              ; Magic number in the trailer of a boot sector
                            ; We write it as 0xaa55 because we're little
                            ; endian and it will be reversed to the required
                            ; 0x55 0xaa
David Hoelzer
  • 15,862
  • 4
  • 48
  • 67
  • Yes that's what I was trying to do. I have one problem though. I used it with a bootable usb in vmware and it worked, but when I tried to boot it on the real machine it didn't print anything it just continue booting windows. –  Jun 12 '15 at 10:38
  • If that's the case you either put it in a USB 3.0 slot or have a machine that only supports EFI boot. Try it out in a VM as a floppy image to prove that it functions. For a real machine, try a USB 2.0 slot and make sure you can do MBR boot. – David Hoelzer Jun 12 '15 at 11:02
  • I am sure I put it in a USB 2.0 slot, but I am not sure if I MBR boot it. Is there any way to determine if EFI or MBR boot being used? –  Jun 12 '15 at 11:56
  • I think there's a problem when I make the usb bootable. When I try to access it (after I make it bootable), I get the following error: H:\ is not accessible. The volume does not contain a recognized file system. Please make sure that all required file system drivers are loaded and that the volume is not corrupted. –  Jun 12 '15 at 12:55
  • If you are using `dd` to copy the compiled code onto the boot sector of the stick this is completely expected. Just like the virtual floppy or virtual hard drive, you are simply writing raw data that will be read in as a boot sector. The template code that I provided you does not make any attempt to create a valid boot sector. You will not be able to read any files off of it in an OS because there are no "files". There is only the raw data. (Sounds sort of Karmic. :) – David Hoelzer Jun 12 '15 at 13:49
  • No I don't use dd, I just save the bin file as iso and use it to make a bootable usb. Is it possible, data don't be written on the first sector, so bios can't load them? If yes, how can I write on the first sector of the usb? –  Jun 12 '15 at 14:30
  • That's entirely possible. I typically build this kind of code on a Unix system like Linux or OS X and write the data to the raw device so that I know for sure where it is and that there hasn't been any attempt to "translate" it. – David Hoelzer Jun 12 '15 at 14:32
  • Okay, it worked. I just made the bootable usb using the .bin file without saving it first as a .iso. –  Jun 12 '15 at 15:07
  • Great. If you don't mind upvoting the answer I'd appreciate it. :) – David Hoelzer Jun 12 '15 at 15:09
  • I will :) One last thing, since the bootloader is only 512bytes and obviously I can't do many things in there, how can I call another file from inside the bootloader to start executing? –  Jun 12 '15 at 15:20
  • You typically do what is called Chain Loading. You use BIOS interrupts to load the next couple of sectors into RAM at a location of your choice and jump to it. – David Hoelzer Jun 12 '15 at 15:21
  • @DavidHoelzer : Shouldn't `mov es, dx` be `mov es, ax` (I am guessing it is a typo). The code might luckily work if booting from floppy disk A (since _DX_ will likely(by luck) contain 0x0000) but not from another drive. This error would cause the wrong segment value to be set for _ES:BP_ *int 0x10/ah=0x13* which in turn would cause a memory location not containing our message to display. – Michael Petch Dec 06 '15 at 08:53
  • Yes Michael. Thanks for the catch. – David Hoelzer Dec 06 '15 at 14:35
  • Not a problem @DavidHoelzer . I actually noticed it while I was typing up another comment regarding the notes in the comment `Could be 0000:7c00 or 07c0:0000 or some other combo.` - unfortunately your code wouldn't work if the BIOS did a far jump (or equivalent) to 07c0:0000 . I'll post a followup comment about this when I find my draft. – Michael Petch Dec 06 '15 at 16:41
  • Simple fix. Change `mov ax, cs` to `xor ax, ax` – Michael Petch Dec 06 '15 at 16:50
  • Michael- Rather than posting 15 comments why don't you just post an answer. – David Hoelzer Dec 07 '15 at 01:02
  • Because you already have an answer that is _accepted_ which only needs one minor change. I'd probably be less inclined to comment about these things on unaccepted answers. – Michael Petch Dec 08 '15 at 05:27