[009][x86汇编语言]学习加载程序的编写(c08_mbr.asm)

源程序来源

https://www.jianshu.com/p/72c151606908

加载程序功能

  • 加载程序 知道 用户程序位于 虚拟硬盘的LBA逻辑扇区100 处;
  • 加载程序 知道 虚拟机 内存物理地址0x10000处空闲;
  • 加载程序 要把 用户程序 从虚拟硬盘里取出来,然后放到 虚拟机里空闲的内存空间那里;
  • 加载程序 知道 虚拟机 开机后会读取 虚拟硬盘主引导扇区(LBA模式逻辑扇区号0) 的内容,将其复制到内存 0x0000:0x7c00处开始执行;

(我们)要做的事情

  • 利用工具 nasmide.exe 编译加载程序的源文件.asm,生成一个.bin二进制文件,将.bin文件利用工具 fixvhdwr.exe 写入到虚拟硬盘的主引导扇区(LBA模式逻辑扇区号0)

加载程序:增加注释

        ;
        ;文件名 c08-1.asm
        ;文件说明:硬盘主引导扇区代码(加载程序)
        ;创建日期:9:12 2018/5/23

        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                      ;物理地址0x10000 转换为 段地址0x1000
        mov ds,ax                   
        mov es,ax

        ;以下读取程序的起始部分
        xor di,di                   ;28位起始逻辑扇区号的高12位
        mov si,app_lba_start        ;28位起始逻辑扇区号的低16位
        xor bx,bx                   ; ???
        call read_hard_disk_0
        
        ;以下判断整个用户程序有多大
        mov dx,[2]      ; 32位用户程序长度的高16位
        mov ax,[0]      ; 32位用户程序长度的低16位
        mov bx,512      ; 1个扇区512字节
        div bx
        cmp dx,0        ; dx里存着余数,余数不为0代表没有除尽
        jnz @1
        dec ax
    @1:
        cmp ax,0        ; 小于1个扇区或者长度为512的整数倍时ax = 0
        jz direct
        
        ; 读取剩余的扇区
        push ds         ; 用户程序的开头是基于LBA逻辑扇区号计算出来的段地址
        
        mov cx,ax       ; 循环次数(剩余的扇区数)
    @2: 
        mov ax,ds       
        add ax,0x20     ; 512D = 0x20
        mov ds,ax       ; 得到下一个以512字节为边界的段地址
        
        xor bx,bx       ; 新的一段开始,偏移地址都是从0x0000开始
        inc si          ; 新的LBA逻辑扇区号,最初的是app_lba_start
        call read_hard_disk_0       ; 不重新设置di,是因为di不需要修改,di = 0
        loop @2         ; 循环读,直到读完整个功能程序(即用户程序)
        
        pop ds          ; 恢复数据段基址到用户程序头部段
        
        ;计算入口点代码段基址
    direct:             ; ds 指向用户程序头部段
        mov dx,[0x08]
        mov ax,[0x06]   ; 用户程序 "code_1段"(代码段) 相对于用户程序开头的 偏移量
        call calc_segment_base  ; 结合用户程序目的地址,计算 "code_1段"(代码段) 的 段地址
        mov [0x06],ax   ; 将 "code_1段"(代码段) 的段地址 回写
        
        ; 开始处理段重定位表
        mov cx,[0x0a]   ; 需要重定位的表项数
        mov bx,0x0c     ; 需要重定位表项相对用户程序开头的偏移量
        
    realloc:    
        mov dx,[bx+0x02]    ; 32位表项偏移量,高16位
        mov ax,[bx]         ; 32位表项偏移量,低16位
        call calc_segment_base  ; 结合用户程序目的地址, 计算 表项 的段地址
        mov [bx],ax
        add bx,4            ; 下一个重定位项 (每项占4个字节)
        loop realloc
        
        jmp far [0x04]  ; 跳转到用户程序: code_1段 标号start处开始执行用户程序
                
;-----------------------------------------------------------------
read_hard_disk_0:


            push ax
            push bx
            push cx
            push dx
            ;设置要读取的扇区数为1
            mov dx,0x1f2    ; 0x1f2 
            mov al,1        ; 扇区数   
            out dx,al
            ;设置起始的LBA扇区号
            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
            ; 请求硬盘读
            inc dx          ; 0x1f7 [命令端口]
            mov al,0x20     ; 读命令
            out dx,al
            ;查看状态
    .waits: 
            in al,dx        ; 0x1f7 [状态端口]
            and al,0x88     ; 1000 1000 保留 BSY ... DRQ...
            cmp al,0x08     ; 0x08 硬盘已准备好与主机交换
            jnz .waits
            ; 连续读取数据
            mov cx,256      ; 总共要读取的字数256字=512字节
            mov dx,0x1f0    ; 0x1f0 [数据端口]
    .readw: 
            in ax,dx        ; 在子程序调用前已经清零xor bx,bx
            mov [bx],ax     ; 指定数据段 DS 指向用户程序目标地址的段地址
            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]       ; 用户程序开头的物理地址是0x10000位于标号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

加载程序 需要结合 用户程序 理解的部分 跨越文件 通过内存读取数据

1、用户程序的目的地址 0x1000.png
2、跨越文件 通过内存 读取用户程序的总长度.png
3.用dx ax 2个16位存一个32位的dd.png
4、将ax回写到用户程序.png
5、需要重定位的表项个数.png
6、回填段的基址.png
7、跳转到用户程序标号start处.png
8、jmp指令跳转到 code-1段的标号start处开始执行用户程序.png

代码说明

  • phy_base dd 0x10000 : 用户程序目的地址的物理起始地址 寻址内存
物理地址 0x10000 
使用 【段地址:偏移地址 = 0x1000:0x0000】 来映射
---------------------------------------------------------------------------
完成计算 段地址 的代码片段
 mov ax,[cs:phy_base]
        mov dx,[cs:phy_base+0x02]
        mov bx,16   
        div bx                      ;物理地址0x10000 转换为 段地址0x1000
        mov ds,ax                   
        mov es,ax
  • app_lba_start equ 100 : 用户程序源地址的起始LBA逻辑扇区号 寻址硬盘
28位 LBA 逻辑扇区号 100

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

-------------------------------------------------------------
;以下读取程序的起始部分
        xor di,di                   ;28位起始逻辑扇区号的高12位
        mov si,app_lba_start        ;28位起始逻辑扇区号的低16位

  • 设置起始的LBA扇区号
 ;设置起始的LBA扇区号
            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汇编语言:从实模式到保护模式》 第126页

  • 查看硬盘状态
          ;查看状态
    .waits: 
            in al,dx        ; 0x1f7 [状态端口]
            and al,0x88     ; 1000 1000 保留 BSY ... DRQ...
            cmp al,0x08     ; 0x08 硬盘已准备好与主机交换
            jnz .waits

端口 0x1f7 部分状态位的含义.png

《x86汇编语言:从实模式到保护模式》 第127页

  • 子程序 call read_hard_disk_0
子程序 
    call read_hard_disk_0

参数  
    di:si 是用户程序位于硬盘的源地址的[LBA逻辑扇区号]
    di : 28位起始逻辑扇区号的高12位
    si : 28位起始逻辑扇区号的低16位

    ds:bx 是用户程序将被送往内存的目的地址的[段地址:偏移地址]
    隐藏参数 ds
    bx : 固定初始化为0x0000,因为每一段的偏移地址都是从0x0000开始

疯狂Debug

  • 两个文件,如果按照相同的行数输入相同的代码,编译出来的机器码连同行数都会一模一样的,但是这里虽然机器码相同,行数却不同,预感这里有一个BUG:果然把寄存器DX写成了寄存器AX;


    Debug.png
  • phy_base dd 0x10000, 用的是dd 型数据,双字,4个字节;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容