使用組合語言編寫載入器(載入使用者程式)

2021-09-13 09:01:47 字數 3755 閱讀 7984

在計算機加電之後,計算機首先會讀取硬碟的主引導扇區,做一些必要的初始化工作,但是硬碟的乙個扇區只有512位元組,所以我們要實現更多的功能,就要有使用者程式,我們需要把控制許可權交給使用者程式(作業系統暫且也算一種使用者程式吧)。

在載入使用者程式的過程中,主要分為以下幾個大步驟:

使用者程式頭部:

section header vstart=0                     ;定義使用者程式頭部段 

program_length dd program_end ;程式總長度[0x00]

;使用者程式入口點

code_entry dw start ;偏移位址[0x04]

dd section.code_1.start ;段位址[0x06]

realloc_tbl_len dw (header_end-code_1_segment)/4

;段重定位表項個數[0x0a]

;段重定位表

code_1_segment dd section.code_1.start ;[0x0c]

code_2_segment dd section.code_2.start ;[0x10]

data_1_segment dd section.data_1.start ;[0x14]

data_2_segment dd section.data_2.start ;[0x18]

stack_segment dd section.stack.start ;[0x1c]

header_end:

從硬碟讀取資訊,需要五個步驟:

設定要讀取的扇區數量

這個數值要寫入0x1f2埠,這是乙個8位暫存器,所以可以使用

out dx,al
2.設定要讀取的起始lba扇區號。

這裡使用lba28。28位的扇區號,分給四個埠,0x1f3-0x1f6,從低到高依次儲存,最後乙個埠也就是0x1f6低四位儲存扇區號的最高四位,剩下四位高三位111表示lba模式,最低以為0表示從盤,1表示主盤。

例如,如果其實扇區是100,也就是0x60,那麼設定的**如下:

mov dx,0x1f3

mov al,0x60

out dx,al

inc dx

xor al,al

out dx,al

inc dx

out dx,al

inc dx

mov al,0xe0

out dx,al

3.請求讀寫

次數值寫入0x1f7埠,0x20表示請求讀

mov al,0x20

mov dx,0x1f7

out dx,al

4.等待硬碟空閒

0x1f7這個埠,除了可以請求讀意外,還能表示硬碟的狀態,第7位0表示空閒,1表示繁忙,第3位為1表示準備好進行資料傳輸,所以這裡我們要等待硬碟空閒才可以傳輸資料:

waits:

in al,dx

and al,1000_1000b ;保留第3位和第7位

cmp 0000_1000b ;第7位為0第3位為1才可以進行讀取

jne waits ;不相等就迴圈等待

5.讀資料

從硬碟讀取資料,通過0x1f0埠,這是乙個16位暫存器。硬碟是典型的塊裝置,所以一次必須讀取512位元組,或者它的倍數。比如,我們要讀取乙個扇區的資料,並存放在ds:0開始的記憶體空間:

mov dx,0x1f0

mov cx,256 ;讀取乙個扇區,512位元組,即256字

xor bx,bx

read_word

in ax,dx

mov [bx],ax

add bx,2

loop read_word

6.檢查使用者程式是否讀取完整。

剛才我們只讀取了乙個扇區,即512位元組,我們並不能確定使用者程式是否已經完全讀完,但是我們已經讀取了使用者程式的頭部,這裡我們規定使用者程式頭部的第乙個雙字必須定義使用者程式的長度.所以我們從ds:0的位置讀取兩個字,第乙個字放在ax,第二個字放在dx,這樣dx:ax代表了使用者程式的總長度,用這個數除以512得到商和餘數,可以知道使用者程式的讀取進度,進而來決定是繼續讀取還是跳轉到後邊的步驟(重定位)。

注意:

由於乙個邏輯段最大是64kb,從0x0000-0xffff,但是使用者程式可能超過這個範圍,為了避免這種事情發生,我們每讀乙個扇區,便把段位址加0x20(512),這樣便可以連續存放且不用擔心超過邏輯段大小。

;檢查使用者程式是否讀取完整

xor bx,bx

mov ax,[bx]

mov dx,[bx+2]

mov bx,512

div bx

cmp dx,0

jne cmp_ax

dec ax

cmp_ax:

cmp ax,0

je redirect_entry ;跳轉到重定位

;讀取剩餘扇區

push ds

mov cx,ax

mov si,start_sector ;start_sector是定義的乙個常數,這裡等於100(使用者程式在100扇區開始)

read_rest:

mov ax,ds

add ax,0x20

mov ds,ax

inc si

call read_disk

loop read_rest

pop ds

使用者程式在編寫的時候都是分段的,重定位的目的便是確定每個段的實際段位址。

這裡我們規定使用者程式頭部中定義了每個段的段首位置(彙編位址),轉換成16位的段位址並重新寫入。

;重定位使用者程式

;重定位使用者入口點的段位址

redirect_entry:

mov ax,[0x06] ;讀取頭部入口點位址資訊

mov dx,[0x08]

call calc_seg_base

mov [0x06],ax

;重定位其他段的段位址

mov cx,[0x0a]

mov bx,0x0c

redirect_other_seg:

mov ax,[bx]

mov dx,[bx+2]

call calc_seg_base

mov [bx],ax

add bx,4

loop redirect_other_seg

;過程計算段位址

;已知dx:ax實體地址,求出段位址並存放在ax中返回

calc_seg_base:

push dx

shr ax,4

ror dx,4

and dx,0xf000

or ax,dx

pop dx

ret

通過jmp far 命令進行段間跳轉,這裡是,跳轉到重定位後的入口點位置,存放在ds:0x04處

jmp far [0x04]
至此,我們的載入器就基本完成了,可以用它來載入任何符合我們規定格式的使用者程式(使用者程式頭部)。

用組合語言編寫程式輸出「Hello World 」

方法如下 步驟一 了解組合語言 結構 data segment 資料段,程式設計者可以把資料都放到這個段裡 資料部分.資料格式是 識別符號 db dw 資料。data ends 資料段結束處。edata segment 附加資料段,程式設計者可以把資料都放到這個段裡 附加資料部分.edata end...

在iOS中如何使用組合語言

本文將系統地介紹如何利用xcode在ios裝置上使用組合語言。一 建立彙編原始檔 在你的xcode專案中存放原始檔的目錄下滑鼠 或觸控板 右鍵,選擇new file。然後在左側的ios那欄裡選擇other,在右邊你會看到assembly file,選中它,然後命名,以.s作為字尾。二 編寫彙編 然後...

Debug的使用 《組合語言》學習筆記

說明 括號內的紅色為助記。一 什麼是debug debug是dos windows提供的實模式 8086方式 程式的除錯工具。使用它,可以檢視cpu各種暫存器的內容 記憶體的情況和在機器碼級跟蹤程式的執行。二 常用的debug功能 用debug的 r命令 register 檢視 改變cpu暫存器的內...