"Hello, World" in x86 Assembly Language

Here are three versions of "Hello, World" written in x86 assembly language, for the Nasm assembler.

minimal version This is the usual shortest-possible 16-bit version, depending on the DOS Services print-string function (function 9).
single-char output A slight expansion, using DOS Services's print-character function (function 2) as well.
length-delimited string This version relies on function 0x40, "write file or device", to output a string based on its length rather than on a terminating $ (dollar sign).
(Function 0x40 was added in DOS version 2.0, thus is not always available. Anyone still using DOS 1.x is stuck with function 9.)
Linux version Linux provides a kernel service "similar" to DOS Services (int 0x21) and similar to other Unix-like OSes. Function 4 expects a length-delimited string.
Note that Linux is a 32-bit OS, and separates processes into executable ("text") and data sections.

A minimal-size version

; hello-DOS.asm - single-segment, 16-bit "hello world" program
;
; assemble with "nasm -f bin -o hi.com hello-DOS.asm"

    org  0x100        ; .com files always start 256 bytes into the segment

    ; int 21h is going to want...

    mov  dx, msg      ; the address of or message in dx
    mov  ah, 9        ; ah=9 - "print string" sub-function
    int  0x21         ; call dos services

    mov  ah, 0x4c     ; "terminate program" sub-function
    int  0x21         ; call dos services

    msg  db 'Hello, World!', 0x0d, 0x0a, '$'   ; $-terminated message

Individual-character output along with string output

; hello2-DOS.asm - single-segment, 16-bit "hello world" program
;
; This demonstrates single-character output as well as string output
; via DOS services
;
; assemble with "nasm -f bin -o hi.com hello2-DOS.asm"

    org  0x100        ; .com files always start 256 bytes into the segment

    ; int 21h is going to want...

    mov  dx, msg      ; the address of or message in dx
    mov  ah, 9        ; ah=9 - "print string" sub-function
    int  0x21         ; call dos services

    mov  dl, 0x0d     ; put CR into dl
    mov  ah, 2        ; ah=2 - "print character" sub-function
    int  0x21         ; call dos services

    mov  dl, 0x0a     ; put LF into dl
    mov  ah, 2        ; ah=2 - "print character" sub-function
    int  0x21         ; call dos services

    mov  ah, 0x4c     ; "terminate program" sub-function
    int  0x21         ; call dos services

    msg  db 'Hello again, World!$'   ; $-terminated message

DOS2 length-delimited output

; hello3-DOS.asm - single-segment, 16-bit "hello world" program
;
; Use DOS 2.0's service 40 to output a length-delimited string.
;
; assemble with "nasm -f bin -o hi.com hello3-DOS.asm"

    org  0x100          ; .com files always start 256 bytes into the segment

; int 21h needs...
    mov  dx, msg        ; message's address in dx
    mov  cx, len
    mov  bx, 1          ; Device/handle: standard out (screen)
    mov  ah, 0x40       ; ah=0x40 - "Write File or Device"
    int  0x21           ; call dos services

    mov  ah, 0x4c       ; "terminate program" sub-function
    int  0x21           ; call dos services

msg     db 'New hello, World!', 0x0d, 0x0a   ; message
len     equ $ - msg     ;msg length

a Linux-compatible version

;Copyright (c) 1999 Konstantin Boldyshev <konst@linuxassembly.org>
;
;"hello, world" in assembly language for Linux
;
;to build an executable:
;       nasm -f elf hello.asm
;       ld -s -o hello hello.o

section .text
; Export the entry point to the ELF linker or loader.  The conventional
; entry point is "_start". Use "ld -e foo" to override the default.
    global _start

section .data
msg db  'Hello, world!',0xa ;our dear string
len equ $ - msg         ;length of our dear string

section .text

; linker puts the entry point here:
_start:

; Write the string to stdout:

    mov edx,len ;message length
    mov ecx,msg ;message to write
    mov ebx,1   ;file descriptor (stdout)
    mov eax,4   ;system call number (sys_write)
    int 0x80    ;call kernel

; Exit via the kernel:

    mov ebx,0   ;process' exit code
    mov eax,1   ;system call number (sys_exit)
    int 0x80    ;call kernel - this interrupt won't return