組合語言寫開機磁區

來源:互聯網
上載者:User

《自己動手寫作業系統》第三章的第一個程式中,作者沒有把可作為開機磁區的程式拿出來,編譯通過,但是在bochs 中執行時,bochs會提示沒有找到啟動盤,然後反組譯碼bin檔案後,看到檔案末尾並沒有啟動盤第510和511位元組的0xaa55標誌,因此要想法將0xaa55標誌寫入啟動盤中。

試了挺多方法,為了節省篇幅,我就把最後使用的方法貼出來吧。這種方法模仿作者在第一章第一個程式中貼出來的程式,即首先計算出之前實打實的代碼的長度,然後接下來(510-長度)的內容填充0,最後兩個位元組寫上0xaa55。完整的程式最後附上,下面分析原理。

times  510-(4+(GDTLen1+3)/4*4+(SegCode16Len+3)/4*4+(SegCode32Len)) db 0dw 0xAA55 

當然,第三章這個程式比第一章的複雜,一是第三章程式中涉及到了分節,因此第一章中程式的 510 -($-$$)就失去了效用,因為$$表示的當前節的節首,因此需要分別統計這三個節的長度。二是因為分節,產生了節首的對齊問題。下面分別闡述這兩個問題的解決方案。

得到每個節的長度,這個問題很簡單,只要在節首和節尾記錄一下即可,如下所示,不再贅述。

[SECTION .gdt]LABEL_GDT:   Descriptor       0,                0, 0           ; 空描述符LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致程式碼片段LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh, DA_DRW     ; 顯存首地址GdtLenequ$ - LABEL_GDT; GDT長度GdtPtrdwGdtLen - 1; GDT界限dd0; GDT基地址SelectorCode32equLABEL_DESC_CODE32- LABEL_GDTSelectorVideoequLABEL_DESC_VIDEO- LABEL_GDTGDTLen1 equ $-LABEL_GDT;END of [SECTION .gdt]

下面討論節首的對齊問題。第一個問題解決之後,我曾想著直接用各個節的長度和來代表程式的長度,結果出錯,還是找不到啟動盤。通過反組譯碼我發現如下兩個問題,一是補充的0的個數總是過多,說明程式的長度我統計少了,二是反組譯碼後程式每個節首的代碼總是與來源程式不同,說明在兩個節之間產生了一些額外的代碼,使反組譯碼器被騙。如下兩段代碼,其中左面代碼是來源程式中16位部分與32位部分交界處的一段,右邊代碼為相同位置的反組譯碼代碼,其中紅色地區的反組譯碼的代碼,是可疑代碼。

 
mov    cr0, eaxjmp    dword SelectorCode32:0   ,                 [SECTION .s32][BITS    32]LABEL_SEG_CODE32:    mov    ax, SelectorVideo    mov    gs, ax                mov    edi, (80 * 11 + 79) * 2    
00007C72  0F22C0            mov cr0,eax00007C75  66EA000000000800  jmp dword 0x8:0x000007C7D  0000              add [bx+si],al00007C7F  0066B8            add [bp-0x48],ah00007C82  1000              adc [bx+si],al00007C84  8EE8              mov gs,ax00007C86  BF7E07            mov di,0x77e

 

其中可疑的是,在反組譯碼後的紅色代碼處,出現了連續的幾個0,因此我馬上想到了是不是為了節首的對齊。為了驗證這種思路,再看一下本程式的第一條指令的反組譯碼指令

00007C00  E92100            jmp word 0x7c24

這條指令要求程式跳轉到0x7c24處,據原始碼,這個地方是16位代碼的首地址。下面貼出來0x7c24附近的反組譯碼代碼,左圖是原反組譯碼代碼,中圖是我調整後的反組譯碼代碼,右圖是原程式中相應部分的代碼。0x7c24是程式的起點了,那麼0x7c24以上部分是什麼呢?還是一群0。分析右圖,其中藍色地區為虛擬碼,也就是說綠色地區是緊接著0x7c24的地區,藍色地區是什嗎?是資料,經計算,這個6 byte的資料應該是23,轉化成十六進位,正好是0x0000000017,如中圖綠色標註部分。好了,中圖中紅和綠之間還夾了兩個位元組,我們更有理由相信這是為了對齊的設定了,因為這個地區沒有代碼,沒有資料,唯一的特點是處於兩個節的相交處,我們離真相只有一步之遙。做如下計算,計算出16代碼區的位元組總數,0x52,發現,0x52不是4的倍數,而0x52+2=0x54是4的倍數,加的這個2正好是中圖中紅色地區和綠色地區之間夾的2個位元組。實驗其他地區,也成立。

真相大白了,NASM在編譯這個程式時是這樣處理的:每個節都是4對齊的。因此如果僅簡單的把所有節的長度加在一起得到程式的長度必然使得求得的長度偏小。我們應該考慮那些為了對齊作出犧牲的地區,所以有了公式:節實際占位元組數=(有效位元組數+3)/4*4,開頭所提公式即為該式應用。

 
00007C1C  17                pop ss00007C1D  0000              add [bx+si],al00007C1F  0000              add [bx+si],al00007C21  0000              add [bx+si],al00007C23  008CC88E          add [si-0x7138],cl00007C27  D88EC08E          fmul dword [bp-0x7140]00007C2B  D0BC0001          sar byte [si+0x100],100007C2F  6631C0            xor eax,eax00007C32  8CC8              mov ax,cs00007C34  66C1E004          shl eax,0x4
00007C1C  17                pop ss00007C1D  0000              add [bx+si],al00007C1F  0000              add [bx+si],al00007C21  0000              add [bx+si],al00007C23  00
00007C24  8CC88E         00007C27  D88EC08E          fmul dword [bp-0x7140]00007C2B  D0BC0001          sar byte [si+0x100],100007C2F  6631C0            xor eax,eax00007C32  8CC8              mov ax,cs00007C34  66C1E004          shl eax,0x4
GdtPtr  dw    GdtLen - 1    ; GDT界限        dd    0        ; GDT基地址SelectorCode32        equ    LABEL_DESC_CODE32    - LABEL_GDT
SelectorVideo        equ    LABEL_DESC_VIDEO    - LABEL_GDT
GDTLen1 equ $-LABEL_GDT[SECTION .s16][BITS    16]LABEL_BEGIN:    mov    ax, cs    mov    ds, ax    mov    es, ax    mov    ss, ax    mov    sp, 0100h    xor    eax, eax    mov    ax, cs    shl    eax, 4

至此,寫開機磁區的一大難題解決了,下面貼出代碼3.1的更新,希望能對同樣困惑的朋友有所協助。

%include"pm.inc"; 常量, 宏, 以及一些說明org07c00hHAHA_begin:jmpLABEL_BEGINQianlen equ  $-HAHA_begin[SECTION .gdt]LABEL_GDT:   Descriptor       0,                0, 0           ; 空描述符LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致程式碼片段LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh, DA_DRW     ; 顯存首地址GdtLenequ$ - LABEL_GDT; GDT長度GdtPtrdwGdtLen - 1; GDT界限dd0; GDT基地址SelectorCode32equLABEL_DESC_CODE32- LABEL_GDTSelectorVideoequLABEL_DESC_VIDEO- LABEL_GDTGDTLen1 equ $-LABEL_GDT[SECTION .s16][BITS16]LABEL_BEGIN:movax, csmovds, axmoves, axmovss, axmovsp, 0100hxoreax, eaxmovax, csshleax, 4addeax, LABEL_SEG_CODE32movword [LABEL_DESC_CODE32 + 2], axshreax, 16movbyte [LABEL_DESC_CODE32 + 4], almovbyte [LABEL_DESC_CODE32 + 7], ahxoreax, eaxmovax, dsshleax, 4addeax, LABEL_GDT; eax <- gdt 基地址movdword [GdtPtr + 2], eax; [GdtPtr + 2] <- gdt 基地址lgdt[GdtPtr]cliinal, 92horal, 00000010bout92h, almoveax, cr0oreax, 1movcr0, eaxjmpdword SelectorCode32:0; 執行這一句會把 SelectorCode32 裝入 cs,; 並跳轉到 Code32Selector:0  處SegCode16Len equ $-LABEL_BEGIN[SECTION .s32][BITS32]LABEL_SEG_CODE32:movax, SelectorVideomovgs, ax; 視頻段選擇子(目的)movedi, (80 * 11 + 79) * 2; 螢幕第 11 行, 第 79 列。movah, 0Ch; 0000: 黑底    1100: 紅字moval, 'A'mov[gs:edi], axjmp$SegCode32Lenequ$ - LABEL_SEG_CODE32; END of [SECTION .s32]times  510-(4+(GDTLen1+3)/4*4+(SegCode16Len+3)/4*4+(SegCode32Len)) db 0dw 0xAA55 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.