<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                本文是《x86匯編語言:從實模式到保護模式》(電子工業出版社)的讀書實驗筆記。 這篇文章我們先不分析代碼,而是說一下在Bochs環境下如何看到實驗結果。 1. 需要的源碼文件 第一個文件是加載程序 ~~~ ;代碼清單8-1 ;文件名:c08_mbr.asm ;文件說明:硬盤主引導扇區代碼(加載程序) ;創建日期:2011-5-5 18:17 app_lba_start equ 100 ;聲明常數(用戶程序起始邏輯扇區號) ;常數的聲明不會占用匯編地址 SECTION mbr align=16 vstart=0x7c00 ;設置堆棧段和棧指針 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 mov ds,ax ;令DS和ES指向該段以進行操作 mov es,ax ;以下讀取程序的起始部分 xor di,di mov si,app_lba_start ;程序在硬盤上的起始邏輯扇區號 (扇區號為28位,存放在di:si) xor bx,bx ;加載到DS:0x0000處 call read_hard_disk_0 ;以下判斷整個程序有多大 mov dx,[2] ;曾經把dx寫成了ds,花了二十分鐘排錯 mov ax,[0] mov bx,512 ;512字節每扇區 div bx cmp dx,0 jnz @1 ;未除盡,因此結果比實際扇區數少1 dec ax ;已經讀了一個扇區,扇區總數減1 @1: cmp ax,0 ;考慮實際長度小于等于512個字節的情況 jz direct ;讀取剩余的扇區 push ds ;以下要用到并改變DS寄存器 mov cx,ax ;循環次數(剩余扇區數) @2: mov ax,ds add ax,0x20 ;得到下一個以512字節為邊界的段地址 mov ds,ax xor bx,bx ;每次讀時,偏移地址始終為0x0000 inc si ;下一個邏輯扇區 call read_hard_disk_0 loop @2 ;循環讀,直到讀完整個功能程序 pop ds ;恢復數據段基址到用戶程序頭部段 ;====================================================================================== ;計算入口點代碼段基址 direct: mov dx,[0x08] mov ax,[0x06] call calc_segment_base mov [0x06],ax ;回填修正后的入口點代碼段基址 ;開始處理段重定位表 mov cx,[0x0a] ;需要重定位的項目數量 mov bx,0x0c ;重定位表首地址 realloc: mov dx,[bx+0x02] ;32位地址的高16位 mov ax,[bx] call calc_segment_base mov [bx],ax ;回填段的基址 add bx,4 ;下一個重定位項(每項占4個字節) loop realloc jmp far [0x04] ;轉移到用戶程序 ;------------------------------------------------------------------------------- read_hard_disk_0: ;從硬盤讀取一個邏輯扇區 ;輸入:DI:SI=起始邏輯扇區號 ; DS:BX=目標緩沖區地址 push ax push bx push cx push dx mov dx,0x1f2 mov al,1 out dx,al ;讀取的扇區數 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 ;LBA28模式,主盤 or al,ah ;LBA地址27~24 out dx,al inc dx ;0x1f7 mov al,0x20 ;讀命令 out dx,al .waits: in al,dx and al,0x88 cmp al,0x08 jnz .waits ;不忙,且硬盤已準備好數據傳輸 mov cx,256 ;總共要讀取的字數 mov dx,0x1f0 .readw: in ax,dx mov [bx],ax add bx,2 loop .readw pop dx pop cx pop bx pop ax ret ;------------------------------------------------------------------------------- calc_segment_base: ;計算16位段地址 ;輸入:DX:AX=32位物理地址 ;返回:AX=16位段基地址 push dx add ax,[cs:phy_base] adc dx,[cs:phy_base+0x02] 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 ~~~ 需要說明的是: 書上假設是從硬盤啟動,本文假設從軟盤啟動 第二個文件是用戶程序 ~~~ ;代碼清單8-2 ;文件名:c08.asm ;文件說明:用戶程序 ;創建日期:2011-5-5 18:17 ;=============================================================================== 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: ;=============================================================================== SECTION code_1 align=16 vstart=0 ;定義代碼段1(16字節對齊) put_string: ;顯示串(0結尾)。 ;輸入:DS:BX=串地址 mov cl,[bx] or cl,cl ;cl=0 ? jz .exit ;是的,返回主程序 call put_char inc bx ;下一個字符 jmp put_string .exit: ret ;------------------------------------------------------------------------------- put_char: ;顯示一個字符 ;輸入:cl=字符ascii push ax push bx push cx push dx push ds push es ;以下取當前光標位置 mov dx,0x3d4 mov al,0x0e out dx,al mov dx,0x3d5 in al,dx ;高8位 mov ah,al mov dx,0x3d4 mov al,0x0f out dx,al mov dx,0x3d5 in al,dx ;低8位 mov bx,ax ;BX=代表光標位置的16位數 cmp cl,0x0d ;回車符? jnz .put_0a ;不是。看看是不是換行等字符 mov ax,bx ;此句略顯多余,但去掉后還得改書,麻煩 mov bl,80 div bl mul bl mov bx,ax jmp .set_cursor .put_0a: cmp cl,0x0a ;換行符? jnz .put_other ;不是,那就正常顯示字符 add bx,80 jmp .roll_screen .put_other: ;正常顯示字符 mov ax,0xb800 mov es,ax shl bx,1 mov [es:bx],cl ;以下將光標位置推進一個字符 shr bx,1 add bx,1 .roll_screen: cmp bx,2000 ;光標超出屏幕?滾屏 jl .set_cursor mov ax,0xb800 mov ds,ax mov es,ax cld mov si,0xa0 mov di,0x00 mov cx,1920 rep movsw mov bx,3840 ;清除屏幕最底一行 mov cx,80 .cls: mov word[es:bx],0x0720 ; space add bx,2 loop .cls mov bx,1920 .set_cursor: mov dx,0x3d4 mov al,0x0e out dx,al mov dx,0x3d5 mov al,bh out dx,al mov dx,0x3d4 mov al,0x0f out dx,al mov dx,0x3d5 mov al,bl out dx,al pop es pop ds pop dx pop cx pop bx pop ax ret ;---------------------------------- 用戶程序入口 -------------------------------------------- start: ;初始執行時,DS和ES指向用戶程序頭部段 mov ax,[stack_segment] ;設置到用戶程序自己的堆棧 mov ss,ax mov sp,stack_end mov ax,[data_1_segment] ;設置到用戶程序自己的數據段 mov ds,ax mov bx,msg0 call put_string ;顯示第一段信息 push word [es:code_2_segment] mov ax,begin push ax ;可以直接push begin,80386+ retf ;轉移到代碼段2執行 continue: mov ax,[es:data_2_segment] ;段寄存器DS切換到數據段2 mov ds,ax mov bx,msg1 call put_string ;顯示第二段信息 jmp $ ;=============================================================================== SECTION code_2 align=16 vstart=0 ;定義代碼段2(16字節對齊) begin: push word [es:code_1_segment] mov ax,continue push ax ;可以直接push continue,80386+ retf ;轉移到代碼段1接著執行 ;=============================================================================== SECTION data_1 align=16 vstart=0 msg0 db ' This is NASM - the famous Netwide Assembler. ' db 'Back at SourceForge and in intensive development! ' db 'Get the current versions from http://www.nasm.us/.' db 0x0d,0x0a,0x0d,0x0a db ' Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a db ' xor dx,dx',0x0d,0x0a db ' xor ax,ax',0x0d,0x0a db ' xor cx,cx',0x0d,0x0a db ' @@:',0x0d,0x0a db ' inc cx',0x0d,0x0a db ' add ax,cx',0x0d,0x0a db ' adc dx,0',0x0d,0x0a db ' inc cx',0x0d,0x0a db ' cmp cx,1000',0x0d,0x0a db ' jle @@',0x0d,0x0a db ' ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a db 0 ;=============================================================================== SECTION data_2 align=16 vstart=0 msg1 db ' The above contents is written by LeeChung. ' db '2011-05-06' db 0 ;=============================================================================== SECTION stack align=16 vstart=0 resb 256 stack_end: ;=============================================================================== SECTION trail align=16 program_end: ~~~ 2.利用源碼生成.bin文件 nasm -f bin c08_mbr.asm -o c08mbr.bin nasm -f bin c08.asm -o c08usr.bin 這時候會提示: c08.asm:203: warning: uninitialized space declared in stack section: zeroing “這句話的意思是,c08.asm源程序的第203行聲明了未初始化的空間。”本實驗的棧空間可以不初始化,所以不用管這個警告。 3.把c08mbr.bin寫入啟動軟盤文件 dd if=c08mbr.bin of=a.img 4.制作一個空的硬盤 因為根據源碼,我們知道用戶程序在硬盤上,所以我們要制作一個硬盤鏡像文件——利用工具bximage 在命令行輸入 bximage,其他操作如圖所示 ![利用bximage制作硬盤映像文件](https://box.kancloud.cn/2016-02-29_56d3a8f513574.jpg "") ![](https://box.kancloud.cn/2016-02-29_56d3a8f52fe8a.jpg "") 注意到最下面的提示了嗎? “The following line should appear in your bochsrc: ata0-master: type=disk, path=”c.img”, mode=flat, cylinders=2, heads=16, spt=63” 由于我們啟動Bochs的時候沒有用默認的配置文件,所以我們需要在自己的配置文件中添加這一行 ~~~ ata0-master: type=disk, path="c.img", mode=flat, cylinders=2, heads=16, spt=63 ~~~ 需要注意的是,我們這張硬盤有2016個扇區(每個扇區大小是512字節) 5.把用戶程序c08usr.bin寫入硬盤鏡像 `dd if=c08usr.bin of=c.img bs=512 seek=100 conv=notrunk` 注意:notrunc的含義是,如果目標文件(這里就是c.img)比來源文件大,不截斷目標文件多出來的那部分內容。 比如c.img已經有1024字節了,而c08usr.bin假設只有512字節,如果seek=0,那么不加conv=notrunc,c.img就會變成512字節。 【dd命令說明】 if=輸入文件 of=輸出文件 ibs = n_bytes 一次讀取n_bytes字節,即讀入緩沖區的字節數。 obs = n_bytes 一次寫入n_bytes字節,即寫 入緩沖區的字節數。 bs = n_bytes 同時設置讀/寫緩沖區的字節數(等于設置ibs和obs)。 count=n_blocks:僅拷貝 n_blocks 個塊,塊大小等于 ibs 指定的字節數 conv=sync:把每個輸入記錄的大小都調到ibs的大小(不足的話用Null填充)。 skip=xxx指在備份時對if 后面的部分也就是原文件跳過多少塊再開始備份(block size由ibs指定 ) seek=xxx指在備份時對of 后面的部分也就是目標文件跳過多少塊再開始寫(block size由obs指定 ) 6.啟動Bochs,查看結果 ![](https://box.kancloud.cn/2016-02-29_56d3a8f541019.jpg "") 我們可以看到,應用程序成功地被加載器加載了。 關于本文的源碼,我們下次再說明。 Goodbye
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看