[009][x86匯編語言]學(xué)習(xí)加載程序的編寫(c08_mbr.asm)

源程序來源

http://www.itdecent.cn/p/72c151606908

加載程序功能

  • 加載程序 知道 用戶程序位于 虛擬硬盤的LBA邏輯扇區(qū)100 處;
  • 加載程序 知道 虛擬機(jī) 內(nèi)存物理地址0x10000處空閑;
  • 加載程序 要把 用戶程序 從虛擬硬盤里取出來,然后放到 虛擬機(jī)里空閑的內(nèi)存空間那里;
  • 加載程序 知道 虛擬機(jī) 開機(jī)后會(huì)讀取 虛擬硬盤主引導(dǎo)扇區(qū)(LBA模式邏輯扇區(qū)號(hào)0) 的內(nèi)容,將其復(fù)制到內(nèi)存 0x0000:0x7c00處開始執(zhí)行;

(我們)要做的事情

  • 利用工具 nasmide.exe 編譯加載程序的源文件.asm,生成一個(gè).bin二進(jìn)制文件,將.bin文件利用工具 fixvhdwr.exe 寫入到虛擬硬盤的主引導(dǎo)扇區(qū)(LBA模式邏輯扇區(qū)號(hào)0)。

加載程序:增加注釋

        ;
        ;文件名 c08-1.asm
        ;文件說明:硬盤主引導(dǎo)扇區(qū)代碼(加載程序)
        ;創(chuàng)建日期:9:12 2018/5/23

        app_lba_start equ 100       ;用戶程序源地址的起始邏輯扇區(qū)號(hào)


SECTION mbr align=16 vstart=0x7c00

        ;設(shè)置棧段和棧指針
        mov ax,0
        mov ss,ax
        mov sp,ax
        
        mov ax,[cs:phy_base]
        mov dx,[cs:phy_base+0x02]
        mov bx,16   
        div bx                      ;物理地址0x10000 轉(zhuǎn)換為 段地址0x1000
        mov ds,ax                   
        mov es,ax

        ;以下讀取程序的起始部分
        xor di,di                   ;28位起始邏輯扇區(qū)號(hào)的高12位
        mov si,app_lba_start        ;28位起始邏輯扇區(qū)號(hào)的低16位
        xor bx,bx                   ; ???
        call read_hard_disk_0
        
        ;以下判斷整個(gè)用戶程序有多大
        mov dx,[2]      ; 32位用戶程序長度的高16位
        mov ax,[0]      ; 32位用戶程序長度的低16位
        mov bx,512      ; 1個(gè)扇區(qū)512字節(jié)
        div bx
        cmp dx,0        ; dx里存著余數(shù),余數(shù)不為0代表沒有除盡
        jnz @1
        dec ax
    @1:
        cmp ax,0        ; 小于1個(gè)扇區(qū)或者長度為512的整數(shù)倍時(shí)ax = 0
        jz direct
        
        ; 讀取剩余的扇區(qū)
        push ds         ; 用戶程序的開頭是基于LBA邏輯扇區(qū)號(hào)計(jì)算出來的段地址
        
        mov cx,ax       ; 循環(huán)次數(shù)(剩余的扇區(qū)數(shù))
    @2: 
        mov ax,ds       
        add ax,0x20     ; 512D = 0x20
        mov ds,ax       ; 得到下一個(gè)以512字節(jié)為邊界的段地址
        
        xor bx,bx       ; 新的一段開始,偏移地址都是從0x0000開始
        inc si          ; 新的LBA邏輯扇區(qū)號(hào),最初的是app_lba_start
        call read_hard_disk_0       ; 不重新設(shè)置di,是因?yàn)閐i不需要修改,di = 0
        loop @2         ; 循環(huán)讀,直到讀完整個(gè)功能程序(即用戶程序)
        
        pop ds          ; 恢復(fù)數(shù)據(jù)段基址到用戶程序頭部段
        
        ;計(jì)算入口點(diǎn)代碼段基址
    direct:             ; ds 指向用戶程序頭部段
        mov dx,[0x08]
        mov ax,[0x06]   ; 用戶程序 "code_1段"(代碼段) 相對(duì)于用戶程序開頭的 偏移量
        call calc_segment_base  ; 結(jié)合用戶程序目的地址,計(jì)算 "code_1段"(代碼段) 的 段地址
        mov [0x06],ax   ; 將 "code_1段"(代碼段) 的段地址 回寫
        
        ; 開始處理段重定位表
        mov cx,[0x0a]   ; 需要重定位的表項(xiàng)數(shù)
        mov bx,0x0c     ; 需要重定位表項(xiàng)相對(duì)用戶程序開頭的偏移量
        
    realloc:    
        mov dx,[bx+0x02]    ; 32位表項(xiàng)偏移量,高16位
        mov ax,[bx]         ; 32位表項(xiàng)偏移量,低16位
        call calc_segment_base  ; 結(jié)合用戶程序目的地址, 計(jì)算 表項(xiàng) 的段地址
        mov [bx],ax
        add bx,4            ; 下一個(gè)重定位項(xiàng) (每項(xiàng)占4個(gè)字節(jié))
        loop realloc
        
        jmp far [0x04]  ; 跳轉(zhuǎn)到用戶程序: code_1段 標(biāo)號(hào)start處開始執(zhí)行用戶程序
                
;-----------------------------------------------------------------
read_hard_disk_0:


            push ax
            push bx
            push cx
            push dx
            ;設(shè)置要讀取的扇區(qū)數(shù)為1
            mov dx,0x1f2    ; 0x1f2 
            mov al,1        ; 扇區(qū)數(shù)   
            out dx,al
            ;設(shè)置起始的LBA扇區(qū)號(hào)
            inc dx          ; 0x1f3
            mov ax,si       
            out dx,al       ; LBA地址7~0

            inc dx          ; 0x1f4
            mov al,ah
            out dx,al       ; LBA地址15~8
            
            inc dx          ;0x1f5
            mov ax,di
            out dx,al       ; LBA地址23~16
            
            inc dx          ; 0x1f6
            mov al,0xe0     ; LAB 主硬盤
            or al,ah
            out dx,al
            ; 請(qǐng)求硬盤讀
            inc dx          ; 0x1f7 [命令端口]
            mov al,0x20     ; 讀命令
            out dx,al
            ;查看狀態(tài)
    .waits: 
            in al,dx        ; 0x1f7 [狀態(tài)端口]
            and al,0x88     ; 1000 1000 保留 BSY ... DRQ...
            cmp al,0x08     ; 0x08 硬盤已準(zhǔn)備好與主機(jī)交換
            jnz .waits
            ; 連續(xù)讀取數(shù)據(jù)
            mov cx,256      ; 總共要讀取的字?jǐn)?shù)256字=512字節(jié)
            mov dx,0x1f0    ; 0x1f0 [數(shù)據(jù)端口]
    .readw: 
            in ax,dx        ; 在子程序調(diào)用前已經(jīng)清零xor bx,bx
            mov [bx],ax     ; 指定數(shù)據(jù)段 DS 指向用戶程序目標(biāo)地址的段地址
            add bx,2        
            loop .readw
            
            pop dx
            pop cx
            pop bx
            pop ax
            
            ret
            
;-----------------------------------------------------------------      
calc_segment_base:          ;計(jì)算16位段地址
                            ;輸入 DX:AX = 32位物理地址
                            ;返回 AX = 16位段基地址
            push dx
            
            add ax,[cs:phy_base]
            adc dx,[cs:phy_base+0x02]       ; 用戶程序開頭的物理地址是0x10000位于標(biāo)號(hào)phy_base處
            shr ax,4
            ror dx,4
            and dx,0xf000
            or ax,dx
            
            pop dx
            
            ret
        
;-----------------------------------------------------------------          
        phy_base dd 0x10000         ;用戶程序目的地址的物理起始地址
        
    times 510-($-$$) db 0
                     db 0x55,0xaa

用戶程序 同 源程序來源

  • c08.asm

加載程序 需要結(jié)合 用戶程序 理解的部分 跨越文件 通過內(nèi)存讀取數(shù)據(jù)

1、用戶程序的目的地址 0x1000.png
2、跨越文件 通過內(nèi)存 讀取用戶程序的總長度.png
3.用dx ax 2個(gè)16位存一個(gè)32位的dd.png
4、將ax回寫到用戶程序.png
5、需要重定位的表項(xiàng)個(gè)數(shù).png
6、回填段的基址.png
7、跳轉(zhuǎn)到用戶程序標(biāo)號(hào)start處.png
8、jmp指令跳轉(zhuǎn)到 code-1段的標(biāo)號(hào)start處開始執(zhí)行用戶程序.png

代碼說明

  • phy_base dd 0x10000 : 用戶程序目的地址的物理起始地址 尋址內(nèi)存
物理地址 0x10000 
使用 【段地址:偏移地址 = 0x1000:0x0000】 來映射
---------------------------------------------------------------------------
完成計(jì)算 段地址 的代碼片段
 mov ax,[cs:phy_base]
        mov dx,[cs:phy_base+0x02]
        mov bx,16   
        div bx                      ;物理地址0x10000 轉(zhuǎn)換為 段地址0x1000
        mov ds,ax                   
        mov es,ax
  • app_lba_start equ 100 : 用戶程序源地址的起始LBA邏輯扇區(qū)號(hào) 尋址硬盤
28位 LBA 邏輯扇區(qū)號(hào) 100

0000   0000 0000   0000 0000   0000 0100
27~24  23~16        15~8       7~0 
----- DI ---------    -------- SI ----------

-------------------------------------------------------------
;以下讀取程序的起始部分
        xor di,di                   ;28位起始邏輯扇區(qū)號(hào)的高12位
        mov si,app_lba_start        ;28位起始邏輯扇區(qū)號(hào)的低16位

  • 設(shè)置起始的LBA扇區(qū)號(hào)
 ;設(shè)置起始的LBA扇區(qū)號(hào)
            inc dx          ; 0x1f3
            mov ax,si       
            out dx,al       ; LBA地址7~0

            inc dx          ; 0x1f4
            mov al,ah
            out dx,al       ; LBA地址15~8
            
            inc dx          ;0x1f5
            mov ax,di
            out dx,al       ; LBA地址23~16
            
            inc dx          ; 0x1f6
            mov al,0xe0     ; LAB 主硬盤
            or al,ah
            out dx,al

端口 0x1f6 的含義.png

《x86匯編語言:從實(shí)模式到保護(hù)模式》 第126頁

  • 查看硬盤狀態(tài)
          ;查看狀態(tài)
    .waits: 
            in al,dx        ; 0x1f7 [狀態(tài)端口]
            and al,0x88     ; 1000 1000 保留 BSY ... DRQ...
            cmp al,0x08     ; 0x08 硬盤已準(zhǔn)備好與主機(jī)交換
            jnz .waits

端口 0x1f7 部分狀態(tài)位的含義.png

《x86匯編語言:從實(shí)模式到保護(hù)模式》 第127頁

  • 子程序 call read_hard_disk_0
子程序 
    call read_hard_disk_0

參數(shù)  
    di:si 是用戶程序位于硬盤的源地址的[LBA邏輯扇區(qū)號(hào)]
    di : 28位起始邏輯扇區(qū)號(hào)的高12位
    si : 28位起始邏輯扇區(qū)號(hào)的低16位

    ds:bx 是用戶程序?qū)⒈凰屯鶅?nèi)存的目的地址的[段地址:偏移地址]
    隱藏參數(shù) ds
    bx : 固定初始化為0x0000,因?yàn)槊恳欢蔚钠频刂范际菑?x0000開始

瘋狂Debug

  • 兩個(gè)文件,如果按照相同的行數(shù)輸入相同的代碼,編譯出來的機(jī)器碼連同行數(shù)都會(huì)一模一樣的,但是這里雖然機(jī)器碼相同,行數(shù)卻不同,預(yù)感這里有一個(gè)BUG:果然把寄存器DX寫成了寄存器AX;


    Debug.png
  • phy_base dd 0x10000, 用的是dd 型數(shù)據(jù),雙字,4個(gè)字節(jié);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容