If you link to this page, your page will be listed in The TODO list under "ASM Examples".

(So we have a reference of pages containing ASM source code.)


All ASM examples in NASM syntax

Included from NasmAllInOne

This page collects the NASM translation of all the AsmExamples given for GAS AT&T syntax. Note that GCC inlined assembly statement will not be converted as they may assume too strong knowledge of structures, global variables, etc.

Note unless stated otherwise, these translation haven't been tested yet. You're welcome to stick a comment if you try them.

From BareBones #loader.s

global _loader           ; making entry point visible to linker
extern _main             ; _main is defined elsewhere

; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0                   ; align loaded modules on page boundaries
MEMINFO     equ  1<<1                   ; provide memory map
FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ    0x1BADB002           ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)        ; checksum required

section .text
align 4
MultiBootHeader:
   dd MAGIC
   dd FLAGS
   dd CHECKSUM

; reserve initial kernel stack space
STACKSIZE equ 0x4000          ; that's 16k.

_loader:
   mov esp, stack+STACKSIZE           ; set up the stack
   push eax                           ; pass Multiboot magic number
   push ebx                           ; pass Multiboot info structure

   call  _main                        ; call kernel proper
               hlt                    ; halt machine should kernel return

section .bss
align 32
stack:
   resb STACKSIZE      ; reserve 16k stack on a quadword boundary

I fixed the above so that it will actually build, but I haven't run it. I had to change "extern _loader" to "global _loader", and I had to rename "ALIGN" to "MODULEALIGN" since "ALIGN" is a nasm keyword.
--BruceJohnston

I tried, this works nicely. Thanks, I'll be using this now.
Why not call this "loader.asm" ? (to distinguish from loader.s for GAS)
This can be assembled with "nasm -f elf loader.asm" (without "-f elf" nasm complains about unsupported external references)

--ZomgTest

Example from BareBonesC++ (loader.s)

Note that this is a replacement for bare bone's loader.s code, but that data should be kept

extern start_ctors, end_ctors, start_dtors, end_dtors
     ; declare ctors/dtors markers as extern (they come from linker.ld)
     ; (or add this^ at the top with other extern/global's)

_loader:
       mov esp, stack+STACKSIZE    ; set up the stack
       push eax                    ; pass Multiboot magic number
       push ebx                    ; pass Multiboot info structure

static_ctors_loop:
       mov ebx, start_ctors
       jmp .test
.body:
       call [ebx]
       add ebx,4
.test:
       cmp ebx, end_ctors
       jb .body

       call _main                 ; call kernel proper

static_destructors_loop:
       mov ebx, start_dtors
       jmp .test
.body:
       call [ebx]
       add ebx,4
.test:
       cmp ebx, end_dtors
       jb .body

       hlt                         ; halt machine should kernel return

Hmmm... the jump labels look funny to me. Can NASM really handle multiple jump labels of the same name?
-- MartinBaute

Actually, yes and no. NASM labels that starts with a dot are shortcuts for "last_non_dotted_symbol.dotted_symbols". In other words, .body is relative to static_..._loop
--PypeClicker

I felt this was lacking {start,end}_{ctors,dtors} declared as extern.
--ZomgTest

Example from InterruptServiceRoutines

; filename : isr_wrapper.asm
extern   _isr_wrapper
align   4

_isr_wrapper:

    pushad
    call    _interrupt_handler
    popad
    iret

All ASM examples in GAS syntax

Included from GasAllInOne

Note The translations provided in this page are there for informative purpose only. You shouldn't expected them to be up-to-date compared to their original versions ... Any report of (un)successful use of this code is welcome.

From BabyStep1

# Note that GAS cannot create flat binaries by itself,
# but needs the help of the linker:
# as -o boot.o boot.asm
# ld boot.o -o boot.bin --oformat binary
# partcopy boot.bin 0 200 -f0

.code16   # unlike NASM, GAS assumes 32 bits from the start
.text

hang:
   jmp hang
.org 510
boot_flag:
   .word 0xAA55

From BabyStep2

Remember that GAS requires LD to create binaries, use LD to rebase the code if necessary (eg. ld --oformat binary --Ttext 0x7C00 -o boot.bin boot.o). Keep in mind that the --Ttext from LD refers to the offset from the start of the segment not the physical 0.

GAS supports local labels in the form of numbers for moving around in functions, there is also an odd way to use them, if the number is before the instruction then you use 1b, if it is after then you use 1f (Presumeably b=backward, f=forward).

# Link as ld --oformat binary --Ttext 0x0 -o Boot.bin Boot.o
.code16
.text

   mov $0x07C0, %ax
   mov %ax, %ds

   mov $msg, %si
1: lodsb
   or %al,%al # zero=end of str
   jz 2f   # get out
   mov $0x0E, %ah
   int $0x10
   jmp 1b

2:
   jmp 2b

msg: .asciz "Welcome to Macintosh\n" # .asciz automatically puts a NULL to terminate the string, use .ascii if you don't want that
   .org 510
   .word 0xAA55
# Link as ld -oformat binary -Ttext 0x7C00 -o Boot.bin Boot.o
.code16
.text

   ljmp $0, $RebasedStart
RebasedStart:
   xor %ax, %ax
   mov %ax, %ds

   mov $msg, %si
1: lodsb
   or %al,%al # zero=end of str
   jz 2f   # get out
   mov $0x0E, %ah
   int $0x10
   jmp 1b

2:
   jmp 2b

msg: .asciz "Welcome to Macintosh\n"
   .org 510
   .word 0xAA55

This example also demonstrates how to create a label to describe functions so that when you come back to them later you can see what it does at a glance without having to read the code. (Clobbers is a term from GCC for registers that contain garbage when it returns)

# Link as ld -oformat binary -Ttext 0x7C00 -o Boot.bin Boot.o
.code16
.text

ljmp $0, $Start
Start:
xor %ax, %ax
mov %ax, %ds

mov $msg, %si
call Print

1:
jmp 1b

# Prints a NULL-terminated string
# INPUT: SI=String
# OUTPUT: None
# CLOBBERS: SI, AX, BX, FLAGS
Print:
        mov $0x0E, %ah
        xor %bx, %bx
1:
        lodsb
        or %al, %al
        jz 2f

        # INT 0x10 VIDEO TELETYPE
        # AH=0xE AL=Character [BH=VideoPage BL=Attribute]
        int $0x10
        jmp 1b
2:
        ret

msg: .asciz "Welcome to Macintosh\n"
.org 510
.word 0xAA55

GAS Macros are similar to NASM's macros

# Link as ld -oformat binary -Ttext 0x7C00 -o Boot.bin Boot.o
.code16
.text

# Syntax is .macro MacroName Param1, Param2, Param3, ...
# Alternative: .macro MacroName Param1 Param2 Param3 ...
# You can also set defaults like .macro DoSomething Int1=3 Int2=6
.macro BIOSPrint StringPointer
   mov $\StringPointer, %si
1: lodsb
   or %al,%al
   jz 2f
   mov $0x0E, %ah
   int $0x10
   jmp 1b
2:
.endm

   ljmp $0, $RebasedStart
RebasedStart:
   xor %ax, %ax
   mov %ax, %ds

   BIOSPrint msg

2:
   jmp 2b

msg: .asciz "Welcome to Macintosh\n"
   .org 510
   .word 0xAA55
main:
1:
   jmp 1b

.include "Other.S"      # The code from these files is assembled as if pasted here
.include "MoreOthers.S"

From BabyStep3

GAS Operates much the same way as NASM in this regard:

.code16
movl $0x12345678, %eax  # the L suffix indicates a 32bit operation (l=long)
.code32
movw $0x1234, %ax  # the W suffix indicates a 16bit operation (w=word), there is also the B suffix indicating an 8bit operation (b=byte)

The suffixes are not always required, for example moves between registers or registers and memory don't require you to add a suffix as the operation size is implied by the size of the register used. Usually you'll only need them in places where you have to use a byte/word/dword directive in the instruction in NASM.

From BabyStep4

ToDo

From BabyStep5

ToDo

From BabyStep7

.code16
.text

ljmp $0, $Start
Start:
xor %ax, %ax
mov %ax, %ds
mov %ax, %ss
mov $0x8200, %sp         # Differs from the original since we hardly need 7KBs of stack

cli                      # Interrupts off, save current DS
push %ds

lgdt (gdtinfo)           # The brackets are just decoration, it works without them but you may find it more legible this way

mov %cr0, %eax           # Enable protected mode
or $1, %al
mov %eax, %cr0

mov $0x8, %ax            # Load selector 1, 32bit flat data
mov %ax, %ds

mov $0x0f01, %ax         # Use the segment to write to the screen
mov %ax, %ds:(0xB8000)

mov %cr0, %eax           # Shut off protected mode
xor $1, %al
mov %eax, %cr0

pop %ds                  # Get the realmode segment back and enable interrupts
sti

1:
jmp 1b

# Description for the CPU to find the GDT
gdtinfo: .word gdtend - gdt - 1
         .long gdt

gdt:     .long 0         # Descriptor 0 is the NULL descriptor
         .long 0
gdtkerneldata:           # 32bit Flat Data, 0-4GB Writable
        .word 0xFFFF
        .word 0
        .byte 0
        .byte 0x92
        .byte 0xCF
        .byte 0
gdtend:

.org 510
.word 0xAA55

From BabyStep8

.code32
# ------------------
dochar:
    call cprint              # print one character
sprint:
    lodsb                    # string char to AL
    or %al, %al
    jnz dochar               # else, we're done
    addb $1, (ypos)          # down one row
    movb $0, (xpos)          # back to left
    ret

cprint:
    mov $0x0F, %ah             # attrib = white on black
    mov %eax, %ecx             # save char/attribute
    movzxb (ypos), %eax
    mov $160, %edx             # 2 bytes (char/attrib)
    mul %edx                   # for 80 columns
    movzxb (xpos), %ebx
    shl $1, %ebx               # times 2 to skip attrib

    mov $0xb8000, %edi         # start of video memory
    add %eax, %edi             # add y offset
    add %ebx, %edi             # add x offset

    mov %ecx, %eax             # restore char/attribute
    movw %ax, %ds:(%edi)
    addb $1, (xpos)            # advance to right

    ret

# ------------------------------------

printreg32:
    mov $outstr32, %edi
    mov (reg32), %eax
    mov $hexstr, %esi
    mov $8, %ecx               # eight nibbles

hexloop:
    rol $4, %eax               # leftmost will
    mov %eax, %ebx             # become rightmost
    and $0x0f, %ebx
    mov (%esi, %ebx), %bl       # index into hexstr
    mov %bl, (%edi)
    inc %edi
    dec %ecx
    jnz hexloop

    mov $outstr32, %esi
    call sprint

    ret

# ------------------------------------

xpos: .byte 0
ypos: .byte 0
hexstr: .ascii "0123456789ABCDEF"
outstr32: .asciz "00000000"    # register value
reg32: .long 0                 # pass values to printreg32

# ------------------------------------

From Help!? I can't get interrupts working

int_handler:
    mov $LINEAR_DATA_SELECTOR, %ax
    mov %ax, %gs
    movl $0x2029203A, %gs:(0xB8000)
    hlt

test1:
    lidt (idtr)
    mov $int_handler, %eax
    movw %ax, (idt+49*8)
    movw $CODE_SELECTOR, (idt+49*8+2)
    movw $0x8E00, (idt+49*8+4)
    shr $16, %eax
    movw %ax, (idt+49*8+6)
    int $49

idtr:
    .word (50*8)-1
    .long LINEAR_ADDRESS(idt)

# Create in the COMMON section (usually part of .bss)
.comm idt, 50*2*4

From How can I tell CPU speed ?

RDTSC:

get_speed:

# First do a cpuid command, with eax=1
mov  $1, %eax
cpuid
test $0x10, %edx        # test bit #4. Do we have TSC ?
jnz  detect_end         # no ?, go to detect_end
# Wait until the timer interrupt has been called.
mov  (irq0_count), %ebx

wait_irq0:

cmp  (irq0_count), %ebx
jz   wait_irq0
rdtsc                   # read time stamp counter
mov  %eax, (tscLoDword)
mov  %edx, (tscHiDword)
add  $2, %ebx           # Set time delay value ticks.
# Remember: so far ebx = [irq0]-1, so the next tick is
# two steps ahead of the current ebx ;)

wait_for_elapsed_ticks:

cmp  (irq0_count), %ebx # Have we hit the delay?
jnz  wait_for_elapsed_ticks
rdtsc
sub (tscLoDword), %eax  # Calculate TSC
sbb (tscHiDword), %edx
# f(total_ticks_per_Second) =  (1 / total_ticks_per_Second) * 1,000,000
# This adjusts for MHz.
# so for this: f(100) = (1/100) * 1,000,000 = 10000
mov $10000, %ebx
div %ebx
# ax contains measured speed in MHz
mov %ax, (mhz)