Starting Out with FASM

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
thegamefreak0134
Posts: 14
Joined: Thu Jan 08, 2009 1:54 am

Starting Out with FASM

Post by thegamefreak0134 »

Hello all, here I am again with something that I can't quite figure out.

I'm starting my barebones kernel over again, in an attempt to get things working right with a proper toolchain. I'm attempting to build the "bare bones" tutorial version of the kernel just to get everything working before I start porting old code over. Trouble is, I can't seem to find any proper documentation on the FASM assembler syntax, and/or I'm not sure how to perform the conversion from the given NASM and GAS syntax files. I understand what the files are supposed to do, but I don't understand how to represent those files in FASM syntax.

Could someone point me toward a resource that would help me understand how to actually port this code over? The main reason I ask is that, although I personally have nothing against any particular assembler, all the folks here who have provided help so far have done so using FASM code, and I feel that it is the standard that should be used. I'd like to get my kernel's loader compiling with FASM and linking in with my C code, but I can't even tell from the documentation if FASM supports that kind of operation. Can someone shed some light on the subject? Thanks.

A very confused beginner,
-Nick
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: Starting Out with FASM

Post by Dex »

Fasm and nasm are very much alike with just small differancs
Example, here the bootload bootprog written in nasm

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                          ;;
;;          "BootProg" Loader v 1.2 by Alexei A. Frounze (c) 2000           ;;
;;                                                                          ;;
;;                                                                          ;;
;;                            Contact Information:                          ;;
;;                            ~~~~~~~~~~~~~~~~~~~~                          ;;
;; E-Mail:   [email protected]                                                ;;
;; Homepage: http://alexfru.chat.ru                                         ;;
;; Mirror:   http://members.xoom.com/alexfru                                ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                  Thanks:                                 ;;
;;                                  ~~~~~~~                                 ;;
;;      Thanks Thomas Kjoernes (aka NowhereMan) for his excelent idea       ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                 Features:                                ;;
;;                                 ~~~~~~~~~                                ;;
;; - FAT12 supported                                                        ;;
;;                                                                          ;;
;; - Loads particular COM or EXE file placed to the root directory of a disk;;
;;   ("ProgramName" variable holds name of a file to be loaded)             ;;
;;                                                                          ;;
;; - Provides simple information about errors occured during load process   ;;
;;   ("RE" message stands for "Read Error",                                 ;;
;;    "NF" message stands for "file Not Found")                             ;;
;;                                                                          ;;
;;                                                                          ;;
;;                             Known Limitations:                           ;;
;;                             ~~~~~~~~~~~~~~~~~~                           ;;
;; - Works only on the 1st MBR partition which must be a PRI DOS partition  ;;
;;   with FAT12 (File System ID: 1)                                         ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                Known Bugs:                               ;;
;;                                ~~~~~~~~~~~                               ;;
;; - All bugs are fixed as far as I know. The boot sector tested on the     ;;
;;   following types of diskettes: 360KB 5"25, 1.2MB 5"25, 1.44MB 3"5.      ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                Memory Map:                               ;;
;;                                ~~~~~~~~~~~                               ;;
;;                 ������������Ŀ                               ;;
;;                  Interrupt Vector Table  0000                          ;;
;;                 ������������Ĵ                               ;;
;;                      BIOS Data Area      0040                          ;;
;;                 ������������Ĵ                               ;;
;;                  PrtScr Status / Unused  0050                          ;;
;;                 ������������Ĵ                               ;;
;;                    Image Load Address    0060                          ;;
;;                 ������������Ĵ                               ;;
;;                     Available Memory     nnnn                          ;;
;;                 ������������Ĵ                               ;;
;;                      2KB Boot Stack      A000 - 512 - 2KB              ;;
;;                 ������������Ĵ                               ;;
;;                        Boot Sector       A000 - 512                    ;;
;;                 ������������Ĵ                               ;;
;;                                            A000                          ;;
;;                                                                          ;;
;;                                                                          ;;
;;                   Boot Image Startup (register values):                  ;;
;;                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                  ;;
;;  dl = boot drive number                                                  ;;
;;  cs:ip = program entry point                                             ;;
;;  ss:sp = program stack (don't confuse with boot sector's stack)          ;;
;;  COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h        ;;
;;  EXE program defaults: ds = es = 50h, other stuff depends on EXE header  ;;
;;                                                                          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

[BITS 16]

?                       equ     0
ImageLoadSeg            equ     60h

[SECTION .text]
[ORG 0]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        jmp     short   start
        nop
bsOemName               DB      "BootProg"      ; 0x03

;;;;;;;;;;;;;;;;;;;;;
;; BPB starts here ;;
;;;;;;;;;;;;;;;;;;;;;

bpbBytesPerSector       DW      ?               ; 0x0B
bpbSectorsPerCluster    DB      ?               ; 0x0D
bpbReservedSectors      DW      ?               ; 0x0E
bpbNumberOfFATs         DB      ?               ; 0x10
bpbRootEntries          DW      ?               ; 0x11
bpbTotalSectors         DW      ?               ; 0x13
bpbMedia                DB      ?               ; 0x15
bpbSectorsPerFAT        DW      ?               ; 0x16
bpbSectorsPerTrack      DW      ?               ; 0x18
bpbHeadsPerCylinder     DW      ?               ; 0x1A
bpbHiddenSectors        DD      ?               ; 0x1C
bpbTotalSectorsBig      DD      ?               ; 0x20

;;;;;;;;;;;;;;;;;;;
;; BPB ends here ;;
;;;;;;;;;;;;;;;;;;;

bsDriveNumber           DB      ?               ; 0x24
bsUnused                DB      ?               ; 0x25
bsExtBootSignature      DB      ?               ; 0x26
bsSerialNumber          DD      ?               ; 0x27
bsVolumeLabel           DB      "NO NAME    "   ; 0x2B
bsFileSystem            DB      "FAT12   "      ; 0x36

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector code starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

start:
        cld

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; How much RAM is there? ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        int     12h             ; get conventional memory size (in KBs)
        shl     ax, 6           ; and convert it to paragraphs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for the boot sector and the stack ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        sub     ax, 512 / 16    ; reserve 512 bytes for the boot sector code
        mov     es, ax          ; es:0 -> top - 512

        sub     ax, 2048 / 16   ; reserve 2048 bytes for the stack
        mov     ss, ax          ; ss:0 -> top - 512 - 2048
        mov     sp, 2048        ; 2048 bytes for the stack

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Copy ourself to top of memory ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     cx, 256
        mov     si, 7C00h
        xor     di, di
        mov     ds, di
        rep     movsw

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Jump to relocated code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        push    es
        push    word main
        retf

main:
        push    cs
        pop     ds

        mov     [bsDriveNumber], dl     ; store boot drive number

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for a FAT12 image (6KB max) and load it whole ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     ax, [bpbBytesPerSector]
        shr     ax, 4                   ; ax = sector size in paragraphs
        mov     cx, [bpbSectorsPerFAT]  ; cx = FAT size in sectors
        mul     cx                      ; ax = FAT size in paragraphs

        mov     di, ss
        sub     di, ax
        mov     es, di
        xor     bx, bx                  ; es:bx -> buffer for the FAT

        mov     ax, [bpbHiddenSectors]
        mov     dx, [bpbHiddenSectors+2]
        add     ax, [bpbReservedSectors]
        adc     dx, bx                  ; dx:ax = LBA

        call    ReadSector

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for a root directory and load it whole ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     bx, ax
        mov     di, dx                  ; save LBA to di:bx

        mov     ax, 32
        mov     si, [bpbRootEntries]
        mul     si
        div     word [bpbBytesPerSector]
        mov     cx, ax                  ; cx = root directory size in sectors

        mov     al, [bpbNumberOfFATs]
        cbw
        mul     word [bpbSectorsPerFAT]
        add     ax, bx
        adc     dx, di                  ; dx:ax = LBA

        push    es                      ; push FAT segment (2nd parameter)

        push    word ImageLoadSeg
        pop     es
        xor     bx, bx                  ; es:bx -> buffer for root directory

        call    ReadSector

        add     ax, cx
        adc     dx, bx                  ; adjust LBA for cluster data

        push    dx
        push    ax                      ; push LBA for data (1st parameter)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Look for a COM/EXE program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     di, bx                  ; es:di -> root entries array
        mov     dx, si                  ; dx = number of root entries
        mov     si, ProgramName         ; ds:si -> program name

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Looks for a file with particular name ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  DS:SI -> file name (11 chars) ;;
;;         ES:DI -> root directory array ;;
;;         DX = number of root entries   ;;
;; Output: SI = cluster number           ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FindName:
        mov     cx, 11
FindNameCycle:
        cmp     byte [es:di], ch
        je      FindNameFailed          ; end of root directory
        pusha
        repe    cmpsb
        popa
        je      FindNameFound
        add     di, 32
        dec     dx
        jnz     FindNameCycle           ; next root entry
FindNameFailed:
        jmp     ErrFind
FindNameFound:
        mov     si, [es:di+1Ah]         ; si = cluster no.

;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Load entire a program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadNextCluster:
        call    ReadCluster
        cmp     si, 0FF8h
        jc      ReadNextCluster         ; if not End Of File

;;;;;;;;;;;;;;;;;;;
;; Type checking ;;
;;;;;;;;;;;;;;;;;;;

        cli                             ; for stack adjustments

        mov     ax, ImageLoadSeg
        mov     es, ax

        cmp     word [es:0], 5A4Dh      ; "MZ" signature?
        je      RelocateEXE             ; yes, it's an EXE program

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Setup and Run COM program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     ax, es
        sub     ax, 10h                 ; "org 100h" stuff :)
        mov     es, ax
        mov     ds, ax
        mov     ss, ax
        xor     sp, sp
        push    es
        push    word 100h
        jmp     Run

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Relocate, setup and run EXE program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RelocateEXE:
        mov     ds, ax

        add     ax, [ds:08h]            ; ax = image base
        mov     cx, [ds:06h]            ; cx = reloc items
        mov     bx, [ds:18h]            ; bx = reloc table pointer

        jcxz    RelocationDone

ReloCycle:
        mov     di, [ds:bx]             ; di = item ofs
        mov     dx, [ds:bx+2]           ; dx = item seg (rel)
        add     dx, ax                  ; dx = item seg (abs)

        push    ds
        mov     ds, dx                  ; ds = dx
        add     [ds:di], ax             ; fixup
        pop     ds

        add     bx, 4                   ; point to next entry
        loop    ReloCycle

RelocationDone:

        mov     bx, ax
        add     bx, [ds:0Eh]
        mov     ss, bx                  ; ss for EXE
        mov     sp, [ds:10h]            ; sp for EXE

        add     ax, [ds:16h]            ; cs
        push    ax
        push    word [ds:14h]           ; ip
Run:
        mov     dl, [cs:bsDriveNumber]  ; let program know boot drive
        sti
        retf

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a FAT12 cluster      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Inout:  ES:BX -> buffer    ;;
;;         SI = cluster no    ;;
;; Output: SI = next cluster  ;;
;;         ES:BX -> next addr ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadCluster:
        mov     bp, sp

        lea     ax, [si-2]
        xor     ch, ch
        mov     cl, [bpbSectorsPerCluster]
                ; cx = sector count
        mul     cx

        add     ax, [ss:bp+1*2]
        adc     dx, [ss:bp+2*2]
                ; dx:ax = LBA

        call    ReadSector

        mov     ax, [bpbBytesPerSector]
        shr     ax, 4                   ; ax = paragraphs per sector
        mul     cx                      ; ax = paragraphs read

        mov     cx, es
        add     cx, ax
        mov     es, cx                  ; es:bx updated

        mov     ax, 3
        mul     si
        shr     ax, 1
        xchg    ax, si                  ; si = cluster * 3 / 2

        push    ds
        mov     ds, [ss:bp+3*2]         ; ds = FAT segment
        mov     si, [ds:si]             ; si = next cluster
        pop     ds

        jnc     ReadClusterEven

        shr     si, 4

ReadClusterEven:
        and     si, 0FFFh               ; mask cluster value
ReadClusterDone:
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a sector using BIOS Int 13h fn 2 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  DX:AX = LBA                    ;;
;;         CX    = sector count           ;;
;;         ES:BX -> buffer address        ;;
;; Output: CF = 1 if error                ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadSector:
        pusha

ReadSectorNext:
        mov     di, 5                   ; attempts to read

ReadSectorRetry:
        pusha

        div     word [bpbSectorsPerTrack]
                ; ax = LBA / SPT
                ; dx = LBA % SPT         = sector - 1

        mov     cx, dx
        inc     cx
                ; cx = sector no.

        xor     dx, dx
        div     word [bpbHeadsPerCylinder]
                ; ax = (LBA / SPT) / HPC = cylinder
                ; dx = (LBA / SPT) % HPC = head

        mov     ch, al
                ; ch = LSB 0...7 of cylinder no.
        shl     ah, 6
        or      cl, ah
                ; cl = MSB 8...9 of cylinder no. + sector no.

        mov     dh, dl
                ; dh = head no.

        mov     dl, [bsDriveNumber]
                ; dl = drive no.

        mov     ax, 201h
                                        ; al = sector count
                                        ; ah = 2 = read function no.

        int     13h                     ; read sectors
        jnc     ReadSectorDone          ; CF = 0 if no error

        xor     ah, ah                  ; ah = 0 = reset function
        int     13h                     ; reset drive

        popa
        dec     di
        jnz     ReadSectorRetry         ; extra attempt
        jmp     short ErrRead

ReadSectorDone:
        popa
        dec     cx
        jz      ReadSectorDone2         ; last sector

        add     bx, [bpbBytesPerSector] ; adjust offset for next sector
        add     ax, 1
        adc     dx, 0                   ; adjust LBA for next sector
        jmp     short ReadSectorNext

ReadSectorDone2:
        popa
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Error Messaging Code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

ErrRead:
        mov     si, MsgErrRead
        jmp     short Error
ErrFind:
        mov     si, MsgErrFind
Error:
        mov     ah, 0Eh
        mov     bx, 7

        lodsb
        int     10h                     ; 1st char
        lodsb
        int     10h                     ; 2nd char

        jmp     short $                 ; hang

;;;;;;;;;;;;;;;;;;;;;;
;; String constants ;;
;;;;;;;;;;;;;;;;;;;;;;

MsgErrRead      db      "RE"
MsgErrFind      db      "NF"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fill free space with zeroes ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                times (512-13-($-$$)) db 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Name of a program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ProgramName     db      "STARTUP BIN"   ; name and extension must be padded
                                        ; with spaces (11 bytes total)

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End of the sector ID ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

                dw      0AA55h

Here it is converted to fasm

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                          ;;
;;          "BootProg" Loader v 1.2 by Alexei A. Frounze (c) 2000           ;;
;;                                                                          ;;
;;                                                                          ;;
;;                            Contact Information:                          ;;
;;                            ~~~~~~~~~~~~~~~~~~~~                          ;;
;; E-Mail:   [email protected]                                                ;;
;; Homepage: http://alexfru.chat.ru                                         ;;
;; Mirror:   http://members.xoom.com/alexfru                                ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                  Thanks:                                 ;;
;;                                  ~~~~~~~                                 ;;
;;      Thanks Thomas Kjoernes (aka NowhereMan) for his excelent idea       ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                 Features:                                ;;
;;                                 ~~~~~~~~~                                ;;
;; - FAT12 supported                                                        ;;
;;                                                                          ;;
;; - Loads particular COM or EXE file placed to the root directory of a disk;;
;;   ("ProgramName" variable holds name of a file to be loaded)             ;;
;;                                                                          ;;
;; - Provides simple information about errors occured during load process   ;;
;;   ("RE" message stands for "Read Error",                                 ;;
;;    "NF" message stands for "file Not Found")                             ;;
;;                                                                          ;;
;;                                                                          ;;
;;                             Known Limitations:                           ;;
;;                             ~~~~~~~~~~~~~~~~~~                           ;;
;; - Works only on the 1st MBR partition which must be a PRI DOS partition  ;;
;;   with FAT12 (File System ID: 1)                                         ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                Known Bugs:                               ;;
;;                                ~~~~~~~~~~~                               ;;
;; - All bugs are fixed as far as I know. The boot sector tested on the     ;;
;;   following types of diskettes: 360KB 5"25, 1.2MB 5"25, 1.44MB 3"5.      ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                Memory Map:                               ;;
;;                                ~~~~~~~~~~~                               ;;
;;                 ������������Ŀ                               ;;
;;                  Interrupt Vector Table  0000                          ;;
;;                 ������������Ĵ                               ;;
;;                      BIOS Data Area      0040                          ;;
;;                 ������������Ĵ                               ;;
;;                  PrtScr Status / Unused  0050                          ;;
;;                 ������������Ĵ                               ;;
;;                    Image Load Address    0060                          ;;
;;                 ������������Ĵ                               ;;
;;                     Available Memory     nnnn                          ;;
;;                 ������������Ĵ                               ;;
;;                      2KB Boot Stack      A000 - 512 - 2KB              ;;
;;                 ������������Ĵ                               ;;
;;                        Boot Sector       A000 - 512                    ;;
;;                 ������������Ĵ                               ;;
;;                                            A000                          ;;
;;                                                                          ;;
;;                                                                          ;;
;;                   Boot Image Startup (register values):                  ;;
;;                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                  ;;
;;  dl = boot drive number                                                  ;;
;;  cs:ip = program entry point                                             ;;
;;  ss:sp = program stack (don't confuse with boot sector's stack)          ;;
;;  COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h        ;;
;;  EXE program defaults: ds = es = 50h, other stuff depends on EXE header  ;;
;;                                                                          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

use16

?			equ	0
ImageLoadSeg		equ	60h


ORG 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	jmp		start
	nop
bsOemName		DB	"BootProg"	; 0x03

;;;;;;;;;;;;;;;;;;;;;
;; BPB starts here ;;
;;;;;;;;;;;;;;;;;;;;;

bpbBytesPerSector	DW	?		; 0x0B
bpbSectorsPerCluster	DB	?		; 0x0D
bpbReservedSectors	DW	?		; 0x0E
bpbNumberOfFATs 	DB	?		; 0x10
bpbRootEntries		DW	?		; 0x11
bpbTotalSectors 	DW	?		; 0x13
bpbMedia		DB	?		; 0x15
bpbSectorsPerFAT	DW	?		; 0x16
bpbSectorsPerTrack	DW	?		; 0x18
bpbHeadsPerCylinder	DW	?		; 0x1A
bpbHiddenSectors	DD	?		; 0x1C
bpbTotalSectorsBig	DD	?		; 0x20

;;;;;;;;;;;;;;;;;;;
;; BPB ends here ;;
;;;;;;;;;;;;;;;;;;;

bsDriveNumber		DB	?		; 0x24
bsUnused		DB	?		; 0x25
bsExtBootSignature	DB	?		; 0x26
bsSerialNumber		DD	?		; 0x27
bsVolumeLabel		DB	"NO NAME    "	; 0x2B
bsFileSystem		DB	"FAT12   "	; 0x36

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector code starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

start:
	cld

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; How much RAM is there? ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	int	12h		; get conventional memory size (in KBs)
	shl	ax, 6		; and convert it to paragraphs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for the boot sector and the stack ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	sub	ax, 512 / 16	; reserve 512 bytes for the boot sector code
	mov	es, ax		; es:0 -> top - 512

	sub	ax, 2048 / 16	; reserve 2048 bytes for the stack
	mov	ss, ax		; ss:0 -> top - 512 - 2048
	mov	sp, 2048	; 2048 bytes for the stack

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Copy ourself to top of memory ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	mov	cx, 256
	mov	si, 7C00h
	xor	di, di
	mov	ds, di
	rep	movsw

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Jump to relocated code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	push	es
	push	word main
	retf

main:
	push	cs
	pop	ds

	mov	[bsDriveNumber], dl	; store boot drive number

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for a FAT12 image (6KB max) and load it whole ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	mov	ax, [bpbBytesPerSector]
	shr	ax, 4			; ax = sector size in paragraphs
	mov	cx, [bpbSectorsPerFAT]	; cx = FAT size in sectors
	mul	cx			; ax = FAT size in paragraphs

	mov	di, ss
	sub	di, ax
	mov	es, di
	xor	bx, bx			; es:bx -> buffer for the FAT

	mov	eax, [bpbHiddenSectors]
	mov	edx, [bpbHiddenSectors+2]
	add	ax, [bpbReservedSectors]
	adc	dx, bx			; dx:ax = LBA

	call	ReadSector

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for a root directory and load it whole ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	mov	bx, ax
	mov	di, dx			; save LBA to di:bx

	mov	ax, 32
	mov	si, [bpbRootEntries]
	mul	si
	div	word [bpbBytesPerSector]
	mov	cx, ax			; cx = root directory size in sectors

	mov	al, [bpbNumberOfFATs]
	cbw
	mul	word [bpbSectorsPerFAT]
	add	ax, bx
	adc	dx, di			; dx:ax = LBA

	push	es			; push FAT segment (2nd parameter)

	push	word ImageLoadSeg
	pop	es
	xor	bx, bx			; es:bx -> buffer for root directory

	call	ReadSector

	add	ax, cx
	adc	dx, bx			; adjust LBA for cluster data

	push	dx
	push	ax			; push LBA for data (1st parameter)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Look for a COM/EXE program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	mov	di, bx			; es:di -> root entries array
	mov	dx, si			; dx = number of root entries
	mov	si, ProgramName 	; ds:si -> program name

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Looks for a file with particular name ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  DS:SI -> file name (11 chars) ;;
;;         ES:DI -> root directory array ;;
;;         DX = number of root entries   ;;
;; Output: SI = cluster number           ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FindName:
	mov	cx, 11
FindNameCycle:
	cmp	byte [es:di], ch
	je	FindNameFailed		; end of root directory
	pusha
	repe	cmpsb
	popa
	je	FindNameFound
	add	di, 32
	dec	dx
	jnz	FindNameCycle		; next root entry
FindNameFailed:
	jmp	ErrFind
FindNameFound:
	mov	si, [es:di+1Ah] 	; si = cluster no.

;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Load entire a program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadNextCluster:
	call	ReadCluster
	cmp	si, 0FF8h
	jc	ReadNextCluster 	; if not End Of File

;;;;;;;;;;;;;;;;;;;
;; Type checking ;;
;;;;;;;;;;;;;;;;;;;

	cli				; for stack adjustments
	mov	ax, ImageLoadSeg
	mov	es, ax
	cmp	word [es:0], 5A4Dh	; "MZ" signature?
	je	RelocateEXE		; yes, it's an EXE program

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Setup and Run COM program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	mov	ax, es
	sub	ax, 10h 		; "org 100h" stuff :)
	mov	es, ax
	mov	ds, ax
	mov	ss, ax
	xor	sp, sp
	push	es
	push	word 100h
	jmp	Run

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Relocate, setup and run EXE program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RelocateEXE:
	mov	ds, ax
	add	ax, [ds:08h]		; ax = image base
	mov	cx, [ds:06h]		; cx = reloc items
	mov	bx, [ds:18h]		; bx = reloc table pointer
	jcxz	RelocationDone
ReloCycle:
	mov	di, [ds:bx]		; di = item ofs
	mov	dx, [ds:bx+2]		; dx = item seg (rel)
	add	dx, ax			; dx = item seg (abs)
	push	ds
	mov	ds, dx			; ds = dx
	add	[ds:di], ax		; fixup
	pop	ds
	add	bx, 4			; point to next entry
	loop	ReloCycle
RelocationDone:
	mov	bx, ax
	add	bx, [ds:0Eh]
	mov	ss, bx			; ss for EXE
	mov	sp, [ds:10h]		; sp for EXE
	add	ax, [ds:16h]		; cs
	push	ax
	push	word [ds:14h]		; ip
Run:
	mov	dl, [cs:bsDriveNumber]	; let program know boot drive
	
	sti
	retf

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a FAT12 cluster      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Inout:  ES:BX -> buffer    ;;
;;         SI = cluster no    ;;
;; Output: SI = next cluster  ;;
;;         ES:BX -> next addr ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadCluster:
	mov	bp, sp
	lea	ax, [si-2]
	xor	ch, ch
	mov	cl, [bpbSectorsPerCluster]
		; cx = sector count
	mul	cx
	add	ax, [ss:bp+1*2]
	adc	dx, [ss:bp+2*2]
		; dx:ax = LBA
	call	ReadSector
	mov	ax, [bpbBytesPerSector]
	shr	ax, 4			; ax = paragraphs per sector
	mul	cx			; ax = paragraphs read
	mov	cx, es
	add	cx, ax
	mov	es, cx			; es:bx updated
	mov	ax, 3
	mul	si
	shr	ax, 1
	xchg	ax, si			; si = cluster * 3 / 2
	push	ds
	mov	ds, [ss:bp+3*2] 	; ds = FAT segment
	mov	si, [ds:si]		; si = next cluster
	pop	ds
	jnc	ReadClusterEven
	shr	si, 4
ReadClusterEven:
	and	si, 0FFFh		; mask cluster value
ReadClusterDone:
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a sector using BIOS Int 13h fn 2 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  DX:AX = LBA                    ;;
;;         CX    = sector count           ;;
;;         ES:BX -> buffer address        ;;
;; Output: CF = 1 if error                ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadSector:
	pusha

ReadSectorNext:
	mov	di, 5			; attempts to read
ReadSectorRetry:
	pusha
	div	word [bpbSectorsPerTrack]
		; ax = LBA / SPT
		; dx = LBA % SPT         = sector - 1
	mov	cx, dx
	inc	cx
		; cx = sector no.
	xor	dx, dx
	div	word [bpbHeadsPerCylinder]
		; ax = (LBA / SPT) / HPC = cylinder
		; dx = (LBA / SPT) % HPC = head
	mov	ch, al
		; ch = LSB 0...7 of cylinder no.
	shl	ah, 6
	or	cl, ah
		; cl = MSB 8...9 of cylinder no. + sector no.
	mov	dh, dl
		; dh = head no.
	mov	dl, [bsDriveNumber]
		; dl = drive no.
	mov	ax, 201h
		; al = sector count
		; ah = 2 = read function no.

	int	13h			; read sectors
	jnc	ReadSectorDone		; CF = 0 if no error
	xor	ah, ah			; ah = 0 = reset function
	int	13h			; reset drive
	popa
	dec	di
	jnz	ReadSectorRetry 	; extra attempt
	jmp	ErrRead

ReadSectorDone:
	popa
	dec	cx
	jz	ReadSectorDone2 	; last sector
	add	bx, [bpbBytesPerSector] ; adjust offset for next sector
	add	ax, 1
	adc	dx, 0			; adjust LBA for next sector
	jmp	ReadSectorNext

ReadSectorDone2:
	popa
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Error Messaging Code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

ErrRead:
	mov	si, MsgErrRead
	jmp	Error
ErrFind:
	mov	si, MsgErrFind
Error:
	mov	ah, 0Eh
	mov	bx, 7

	lodsb
	int	10h			; 1st char
	lodsb
	int	10h			; 2nd char

	jmp	 $			; hang

;;;;;;;;;;;;;;;;;;;;;;
;; String constants ;;
;;;;;;;;;;;;;;;;;;;;;;

MsgErrRead	db	"RE"
MsgErrFind	db	"NF"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Name of a program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ProgramName	db	"KERNEL32EXE"	; name and extension must be padded
					; with spaces (11 bytes total)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fill free space with zeroes ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

times 510- ($-0)  db 0	

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End of the sector ID ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

dw 0xaa55

	      

frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Re: Starting Out with FASM

Post by frank »

Post the stuff you are having trouble with and I'm sure someone will be able to help you out with it. Other than that, the official manual from the website should have everything you need.
thegamefreak0134
Posts: 14
Joined: Thu Jan 08, 2009 1:54 am

Re: Starting Out with FASM

Post by thegamefreak0134 »

Thanks to this example, I think I can port over most of my NASM format code. However, and I searched the official docs for this too, how do I link it with C code? Namely, how do I call C functions from assembly using FASM syntax, and how to I expose assembly routines so that C can call assembly functions if needed? I would do this in NASM using global and extern respectively, but I can't seem to find the equivalent statements for FASM.

Also, I noticed that the FASM example that you gave (which is amazing, btw, thanks a bunch for that) doesn't specify the sections. Is that because it's a pure assembly program and the sections aren't technically needed? If so, how do I specify those sections (and do I even need to) for linking with a C (gcc) program using ld?

Forgive my inexperience here. I understand assembly on the x86 for the most part, I'm just not as familiar with the link step as I need to be. This project will end up getting me *very* used to the link step, especially when I start needing to load .elf programs with the kernel. ^_^

Thanks
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Re: Starting Out with FASM

Post by Dex »

For combining C and ASM your best to ask in the fasm forum, as i am a 100% only programmer, but theres Clib examples in the fasm source code its self, also you can use something like this, in fasm

Code: Select all

section '.text' executable align 16
It all depend on the output format you want.
Sorry can not help with C, but remember not only is fasm the best assembler for OS Dev, (it was made in the first place to write a OS), but also its the esiest to port, once your OS can load and save files, along with base print function etc, it will take less than half a hour.
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Re: Starting Out with FASM

Post by frank »

This part may be different for you depending on your toolchain. To link an assembly file with LD you should the following at the beginning of the assembly file. Then do tell fasm to output the file as a .o file. Then just add the new file to the list for LD. Again this part may vary depending on your toolchain.

Code: Select all

FORMAT ELF
Calling a C Function from Assembly
Assembly file

Code: Select all

extrn symbol_name

;then
jmp symbol_name or
call symbol_name
It also works for data.

Calling an Assembly function from C
Assembly file

Code: Select all

public symbol_name
symbol_name:
    ret
C File

Code: Select all

// example function prototype
void func( int num ); or
extern void func( int num );

then call with func( 5 );
thegamefreak0134
Posts: 14
Joined: Thu Jan 08, 2009 1:54 am

Re: Starting Out with FASM

Post by thegamefreak0134 »

frank wrote:

Code: Select all

FORMAT ELF
Calling a C Function from Assembly
Assembly file

Code: Select all

extrn symbol_name

;then
jmp symbol_name or
call symbol_name
It also works for data.
#-o

I was using "extern" but the FASM syntax is "extrn". Darn my proper spelling habit, it's going to kick me a few times on this road.

Well, I made an "oh duh" while I was doing all of this: I realized that the assembly bit isn't even necessary in the Bare Bones tutorial, which I was basing my skeleton on. Basically, all the assembly bit does is pass in the multiboot header and set up a stack. Trouble is, GRUB will already happily do this for you if you compile to ELF format instead, and since the tutorial uses GRUB I can't fathom why it would be so redundant. I see its point, really I do, since it makes the code truly multi-boot compliant, but in the end I'm planning on ditching GRUB and writing my own bootloader anyway, which defeats the purpose really. So at this point, I'm tucking it away on the backburner in case I decide that I need it later.

That said, it's still extremely useful to now be able to link against FASM-generated code, now I can ditch NASM for good. You're all been a great help and I'm happy to report that I have nothing more to ask on this front for now. Thanks again!

-Nick
Post Reply