x86汇编从实模式到保护模式-程序加载器
生活随笔
收集整理的這篇文章主要介紹了
x86汇编从实模式到保护模式-程序加载器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
調試一天半,復刻成功!!!
;文件名:Program_Loader.asm ;文件說明:硬盤主引導扇區代碼(加載程序) ;創建日期:2021-11-1;用戶程序起始邏輯扇區號 ;段 ;Main: ;設置堆棧 ;計算用戶程序加載的段地址 ;設置程序讀取的上文(先讀取一個扇區,獲取基本信息) ;利用基本信息,計算程序的總扇區數 ;(若剩余扇區數>0)讀取剩余扇區 ;重置段表 ;跳轉至用戶程序入口 ; ; application equ 10 ;用戶程序所在扇區號 section app_load align=16 vstart=0x7c00;設置堆棧指針 mov ax,0 mov ss,ax mov sp,0x0;設置用戶程序加載位置 mov ax,[cs:phy_base] ;低位 mov dx,[cs:phy_base+0x2] ;高位 mov bx,0x10 div bx mov ds,ax ;ds與es指向用戶程序加載位置 ;mov es,ax;讀取一個扇區大小的用戶程序 mov di,0 ;扇區讀取目標地址ds:di mov si,application ;需讀取扇區號 call read_HardDisk_0 ;開始讀取;計算用戶程序大小 mov dx,[0x2] ;用戶程序大小高地址 mov ax,[0x0] ;用戶程序大小低地址 mov bx,512 ;一個扇區大小 div bx ;ax為商,dx為余 cmp dx,0x0 ;ax:所占用完整的扇區數 jnz @1 ;dx為0,則共需讀取ax個扇區(別忘了已經讀取過一個扇區) dec ax ;dx不為0,則共需讀取ax+1個扇區(別忘了已經讀取過一個扇區);判斷用戶程序所占扇區大小 @1: ;若ax為0,則無需再讀取 cmp ax,0 jz re_entrymov cx,ax ;讀取剩余扇區的程序 @2: ;此時di=512,ds=0x10000 inc si ;si為需讀取扇區號 call read_HardDisk_0 ;讀取第si個扇區 loop @2;用戶程序讀取完畢;用戶程序起始地址:0x10000 re_entry: ;重置用戶程序代碼入口 mov dx,[0x8] ;代碼段入口高地址 mov ax,[0x6] ;代碼段入口低地址 call translaion_address ;返回段地址ax mov [0x6],ax ;重寫程序入口段基址mov di, 0xc ;段基址重定位表首地址 mov cx,[0xa] ;需重置段基址數量 re_section: mov dx,[di+0x2] ;代碼段入口高地址 mov ax,[di] ;代碼段入口低地址 call translaion_address ;返回段地址ax mov [di],ax ;重寫程序入口段基址 add di,4 ;下一需重定位段基址 loop re_sectionjmp far [0x4] ;跳轉至用戶程序入口 ;---------------------------------------------------------------------------------- ;硬盤讀取 read_HardDisk_0: ;si為所需扇區號;ds:di為目標地址 push cxmov al,0x1 ;讀取扇區數 mov dx,0x1f2 ;0x01f2端口 out dx,al inc dx;0x01f3端口,0x01f4端口,0x01f5端口,0x01f6端口 ;LBA地址0~7,LBA地址8~15,LBA地址16~23,LBA地址24~27 ;0~27:LBA28邏輯扇區 ;28~31: ;28:[0:主硬盤/1:從硬盤] ;29~31:[101:CHS/111:LBA]mov ax,si out dx,al ;0x01f3端口,LBA地址0~7 inc dxmov al,0x0 out dx,al ;0x01f4端口,LBA地址8~15 inc dxout dx,al ;0x01f5端口,LBA地址16~23 inc dxmov al,0xe0 out dx,al ;0x01f6端口,LBA地址24~27 inc dx ;28~31,模式設置mov al,0x20 out dx,al ;0x01f7端口,向端口寫入0x20(寫命令);等待硬盤數據準備 wait_: in al,dx ;0x01f7端口為狀態寄存器 and al,0x88 ;留下第7位,第4位 cmp al,0x8 ;第7位為0表示不忙,第4位為1表示數據以準備好 jnz wait_mov dx,0x1f0 ;數據傳送端口 mov cx,256;開始讀取硬盤 ;讀取字數 read_: in ax,dx mov [di],ax inc di inc di loop read_pop cxret ;-------------------------------------------------------------------------------------- translaion_address: ;輸入;dx為16位高地址(2B);ax為16位低地址(2B);phy_base=0x10000(4B) add ax,[cs:phy_base] ;低位相加,CF進位 adc dx,[cs:phy_base+0x2] ;高位相加,加上CF進位,由此完成32位加法;此時dx:ax為內存中入口點代碼段起始地址;8086中僅有20位地址線(前20位有效);所以dx:ax僅有20位有效;因為ax有16位有效;于是dx雖有16位,dx僅有最后4位有效;只取20位中高16位作為段地址 shl dx,12 ;dx低4位放于高4位返回 shr ax,4 ;保留ax高12位放于低12位返回 add ax,dx ;返回段地址axret ;---------------------------------------------------------------------------------- phy_base dd 0x10000 ;用戶程序加載位置,16字節對齊 db 510-($-$$) dup(0) ;補充滿一個扇區 db 0x55,0xaa總結
以上是生活随笔為你收集整理的x86汇编从实模式到保护模式-程序加载器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库定义语言常见关键字
- 下一篇: SQL编程where子句与操作符