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)