鱼C论坛

 找回密码
 立即注册
查看: 2691|回复: 0

[学习笔记] X86汇编语言-从实模式到保护模式—笔记(10)

[复制链接]
发表于 2017-11-2 21:15:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 兰陵月 于 2017-12-5 21:55 编辑

第9章  中断和动态时钟显示

例程理解学习


加载程序源代码
  1.          ;代码清单8-1
  2.          ;文件名:c08_mbr.asm
  3.          ;文件说明:硬盘主引导扇区代码(加载程序)
  4.          ;创建日期:2011-5-5 18:17

  5.          app_lba_start equ 100           ;声明常数(用户程序起始逻辑扇区号)
  6.                                          ;常数的声明不会占用汇编地址

  7. SECTION mbr align=16 vstart=0x7c00

  8.          ;设置堆栈段和栈指针
  9.          mov ax,0
  10.          mov ss,ax
  11.          mov sp,ax

  12.          mov ax,[cs:phy_base]            ;计算用于加载用户程序的逻辑段地址
  13.          mov dx,[cs:phy_base+0x02]
  14.          mov bx,16
  15.          div bx
  16.          mov ds,ax                       ;令DS和ES指向该段以进行操作
  17.          mov es,ax

  18.          ;以下读取程序的起始部分
  19.          xor di,di                                                 ;程序在硬盘上的起始逻辑扇区号---高16位,只有低12位有效,所以高4位必须为0(作为参数传递)
  20.          mov si,app_lba_start            ;程序在硬盘上的起始逻辑扇区号---低16位(作为参数传递)
  21.          xor bx,bx                       ;加载到DS:0x0000处
  22.          call read_hard_disk_0

  23.          ;以下判断整个程序有多大
  24.          mov dx,[2]                      ;曾经把dx写成了ds,花了二十分钟排错
  25.          mov ax,[0]
  26.          mov bx,512                      ;512字节每扇区
  27.          div bx
  28.          cmp dx,0
  29.          jnz @1                          ;未除尽,因此结果比实际扇区数少1
  30.          dec ax                          ;已经读了一个扇区,扇区总数减1
  31.    @1:
  32.          cmp ax,0                        ;考虑实际长度小于等于512个字节的情况
  33.          jz direct

  34.          ;读取剩余的扇区
  35.          push ds                         ;以下要用到并改变DS寄存器

  36.          mov cx,ax                       ;循环次数(剩余扇区数)
  37.    @2:
  38.          mov ax,ds
  39.          add ax,0x20                     ;得到下一个以512字节为边界的段地址
  40.          mov ds,ax

  41.          xor bx,bx                       ;每次读时,偏移地址始终为0x0000
  42.          inc si                          ;下一个逻辑扇区
  43.          call read_hard_disk_0
  44.          loop @2                         ;循环读,直到读完整个功能程序

  45.          pop ds                          ;恢复数据段基址到用户程序头部段

  46.          ;计算入口点代码段基址
  47.    direct:
  48.          mov dx,[0x08]
  49.          mov ax,[0x06]
  50.          call calc_segment_base
  51.          mov [0x06],ax                   ;回填修正后的入口点代码段基址

  52.          ;开始处理段重定位表
  53.          mov cx,[0x0a]                   ;需要重定位的项目数量
  54.          mov bx,0x0c                     ;重定位表首地址

  55. realloc:
  56.          mov dx,[bx+0x02]                ;32位地址的高16位
  57.          mov ax,[bx]
  58.          call calc_segment_base
  59.          mov [bx],ax                     ;回填段的基址
  60.          add bx,4                        ;下一个重定位项(每项占4个字节)
  61.          loop realloc

  62.          jmp far [0x04]                  ;转移到用户程序

  63. ;-------------------------------------------------------------------------------
  64. read_hard_disk_0:                        ;从硬盘读取一个逻辑扇区
  65.                                          ;输入:DI:SI=起始逻辑扇区号
  66.                                          ;      DS:BX=目标缓冲区地址
  67.          push ax
  68.          push bx
  69.          push cx
  70.          push dx

  71.          mov dx,0x1f2                                         ;0x1f2,写入的内容为要读取的扇区数
  72.          mov al,1                                                 ;读取1个扇区
  73.          out dx,al                       ;读取的扇区数

  74.          inc dx                          ;0x1f3
  75.          mov ax,si                                                 ;当前si的值为100D
  76.          out dx,al                       ;LBA地址7~0

  77.          inc dx                          ;0x1f4
  78.          mov al,ah
  79.          out dx,al                       ;LBA地址15~8

  80.          inc dx                          ;0x1f5
  81.          mov ax,di                                                 ;当前di的值为0
  82.          out dx,al                       ;LBA地址23~16

  83.          inc dx                          ;0x1f6
  84.          mov al,0xe0                     ;LBA28模式,主盘
  85.          or al,ah                        ;LBA地址27~24
  86.          out dx,al

  87.          inc dx                          ;0x1f7
  88.          mov al,0x20                     ;读命令
  89.          out dx,al

  90.   .waits:
  91.          in al,dx
  92.          and al,0x88
  93.          cmp al,0x08
  94.          jnz .waits                      ;不忙,且硬盘已准备好数据传输

  95.          mov cx,256                      ;总共要读取的字数
  96.          mov dx,0x1f0
  97.   .readw:
  98.          in ax,dx
  99.          mov [bx],ax
  100.          add bx,2
  101.          loop .readw

  102.          pop dx
  103.          pop cx
  104.          pop bx
  105.          pop ax

  106.          ret

  107. ;-------------------------------------------------------------------------------
  108. calc_segment_base:                       ;计算16位段地址
  109.                                          ;输入:DX:AX=32位物理地址
  110.                                          ;返回:AX=16位段基地址
  111.          push dx

  112.          add ax,[cs:phy_base]
  113.          adc dx,[cs:phy_base+0x02]
  114.          shr ax,4
  115.          ror dx,4
  116.          and dx,0xf000
  117.          or ax,dx

  118.          pop dx

  119.          ret

  120. ;-------------------------------------------------------------------------------
  121.          phy_base dd 0x10000             ;用户程序被加载的物理起始地址

  122. times 510-($-$) db 0
  123.                   db 0x55,0xaa
复制代码

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 05:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表