请选择 进入手机版 | 继续访问电脑版

4Ameta

 找回密码
 立即注册
搜索
查看: 61|回复: 0

Learn x86 protected mode assembly language-c08.asm

[复制链接]

26

主题

26

帖子

119

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119
发表于 2022-9-12 20:08:50 | 显示全部楼层 |阅读模式
  1.          ;代码清单8-2
  2.          ;文件名:c08.asm
  3.          ;文件说明:用户程序
  4.          ;创建日期:2011-5-5 18:17
  5.          
  6. ;===============================================================================
  7. SECTION header vstart=0                     ;定义用户程序头部段
  8.     program_length  dd program_end          ;程序总长度[0x00]
  9.    
  10.     ;用户程序入口点
  11.     code_entry      dw start                ;偏移地址[0x04]
  12.                     dd section.code_1.start ;段地址[0x06]
  13.    
  14.     realloc_tbl_len dw (header_end-code_1_segment)/4
  15.                                             ;段重定位表项个数[0x0a]
  16.    
  17.     ;段重定位表           
  18.     code_1_segment  dd section.code_1.start ;[0x0c]
  19.     code_2_segment  dd section.code_2.start ;[0x10]
  20.     data_1_segment  dd section.data_1.start ;[0x14]
  21.     data_2_segment  dd section.data_2.start ;[0x18]
  22.     stack_segment   dd section.stack.start  ;[0x1c]
  23.    
  24.     header_end:               
  25.    
  26. ;===============================================================================
  27. SECTION code_1 align=16 vstart=0         ;定义代码段1(16字节对齐)
  28. put_string:                              ;显示串(0结尾)。
  29.                                          ;输入:DS:BX=串地址
  30.          mov cl,[bx]
  31.          or cl,cl                        ;cl=0 ?
  32.          jz .exit                        ;是的,返回主程序
  33.          call put_char
  34.          inc bx                          ;下一个字符
  35.          jmp put_string

  36.    .exit:
  37.          ret

  38. ;-------------------------------------------------------------------------------
  39. put_char:                                ;显示一个字符
  40.                                          ;输入:cl=字符ascii
  41.          push ax
  42.          push bx
  43.          push cx
  44.          push dx
  45.          push ds
  46.          push es

  47.          ;以下取当前光标位置
  48.         mov dx,0x3d4
  49.         mov al,0x0e
  50.         out dx,al
  51.                 mov dx,0x3d5
  52.          in al,dx                        ;高8位
  53.          mov ah,al

  54.          mov dx,0x3d4
  55.          mov al,0x0f
  56.          out dx,al
  57.          mov dx,0x3d5
  58.          in al,dx                        ;低8位
  59.          mov bx,ax                       ;BX=代表光标位置的16位数

  60.          cmp cl,0x0d                     ;回车符?
  61.          jnz .put_0a                     ;不是。看看是不是换行等字符
  62.          mov ax,bx                       ;此句略显多余,但去掉后还得改书,麻烦
  63.          mov bl,80                       
  64.          div bl
  65.          mul bl
  66.          mov bx,ax
  67.          jmp .set_cursor

  68. .put_0a:
  69.          cmp cl,0x0a                     ;换行符?
  70.          jnz .put_other                  ;不是,那就正常显示字符
  71.          add bx,80
  72.          jmp .roll_screen

  73. .put_other:                             ;正常显示字符
  74.          mov ax,0xb800
  75.          mov es,ax
  76.          shl bx,1
  77.          mov [es:bx],cl

  78.          ;以下将光标位置推进一个字符
  79.          shr bx,1
  80.          add bx,1

  81. .roll_screen:
  82.          cmp bx,2000                     ;光标超出屏幕?滚屏
  83.          jl .set_cursor

  84.          mov ax,0xb800
  85.          mov ds,ax
  86.          mov es,ax
  87.          cld
  88.          mov si,0xa0
  89.          mov di,0x00
  90.          mov cx,1920
  91.          rep movsw
  92.          mov bx,3840                     ;清除屏幕最底一行
  93.          mov cx,80
  94. .cls:
  95.          mov word[es:bx],0x0720
  96.          add bx,2
  97.          loop .cls

  98.          mov bx,1920

  99. .set_cursor:
  100.          mov dx,0x3d4
  101.          mov al,0x0e
  102.          out dx,al
  103.          mov dx,0x3d5
  104.          mov al,bh
  105.          out dx,al
  106.          mov dx,0x3d4
  107.          mov al,0x0f
  108.          out dx,al
  109.          mov dx,0x3d5
  110.          mov al,bl
  111.          out dx,al

  112.          pop es
  113.          pop ds
  114.          pop dx
  115.          pop cx
  116.          pop bx
  117.          pop ax

  118.          ret

  119. ;-------------------------------------------------------------------------------
  120.   start:
  121.          ;初始执行时,DS和ES指向用户程序头部段
  122.          mov ax,[stack_segment]           ;设置到用户程序自己的堆栈
  123.          mov ss,ax
  124.          mov sp,stack_end
  125.          
  126.          mov ax,[data_1_segment]          ;设置到用户程序自己的数据段
  127.          mov ds,ax

  128.          mov bx,msg0
  129.          call put_string                  ;显示第一段信息

  130.          push word [es:code_2_segment]
  131.          mov ax,begin
  132.          push ax                          ;可以直接push begin,80386+
  133.          
  134.          retf                             ;转移到代码段2执行
  135.          
  136.   continue:
  137.          mov ax,[es:data_2_segment]       ;段寄存器DS切换到数据段2
  138.          mov ds,ax
  139.          
  140.          mov bx,msg1
  141.          call put_string                  ;显示第二段信息

  142.          jmp $

  143. ;===============================================================================
  144. SECTION code_2 align=16 vstart=0          ;定义代码段2(16字节对齐)

  145.   begin:
  146.          push word [es:code_1_segment]
  147.          mov ax,continue
  148.          push ax                          ;可以直接push continue,80386+
  149.          
  150.          retf                             ;转移到代码段1接着执行
  151.          
  152. ;===============================================================================
  153. SECTION data_1 align=16 vstart=0

  154.     msg0 db '  This is NASM - the famous Netwide Assembler. '
  155.          db 'Back at SourceForge and in intensive development! '
  156.          db 'Get the current versions from http://www.nasm.us/.'
  157.          db 0x0d,0x0a,0x0d,0x0a
  158.          db '  Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a
  159.          db '     xor dx,dx',0x0d,0x0a
  160.          db '     xor ax,ax',0x0d,0x0a
  161.          db '     xor cx,cx',0x0d,0x0a
  162.          db '  @@:',0x0d,0x0a
  163.          db '     inc cx',0x0d,0x0a
  164.          db '     add ax,cx',0x0d,0x0a
  165.          db '     adc dx,0',0x0d,0x0a
  166.          db '     inc cx',0x0d,0x0a
  167.          db '     cmp cx,1000',0x0d,0x0a
  168.          db '     jle @@',0x0d,0x0a
  169.          db '     ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a
  170.          db 0

  171. ;===============================================================================
  172. SECTION data_2 align=16 vstart=0

  173.     msg1 db '  The above contents is written by LeeChung. '
  174.          db '2011-05-06'
  175.          db 0

  176. ;===============================================================================
  177. SECTION stack align=16 vstart=0
  178.            
  179.          resb 256

  180. stack_end:  

  181. ;===============================================================================
  182. SECTION trail align=16
  183. program_end:
复制代码
  1.      1                                           ;代码清单8-2
  2.      2                                           ;文件名:c08.asm
  3.      3                                           ;文件说明:用户程序
  4.      4                                           ;创建日期:2011-5-5 18:17
  5.      5                                          
  6.      6                                  ;===============================================================================
  7.      7                                  SECTION header vstart=0                     ;定义用户程序头部段
  8.      8 00000000 [00000000]                  program_length  dd program_end          ;程序总长度[0x00]
  9.      9                                      
  10.     10                                      ;用户程序入口点
  11.     11 00000004 [A600]                      code_entry      dw start                ;偏移地址[0x04]
  12.     12 00000006 [00000000]                                  dd section.code_1.start ;段地址[0x06]
  13.     13                                      
  14.     14 0000000A 0500                        realloc_tbl_len dw (header_end-code_1_segment)/4
  15.     15                                                                              ;段重定位表项个数[0x0a]
  16.     16                                      
  17.     17                                      ;段重定位表           
  18.     18 0000000C [00000000]                  code_1_segment  dd section.code_1.start ;[0x0c]
  19.     19 00000010 [00000000]                  code_2_segment  dd section.code_2.start ;[0x10]
  20.     20 00000014 [00000000]                  data_1_segment  dd section.data_1.start ;[0x14]
  21.     21 00000018 [00000000]                  data_2_segment  dd section.data_2.start ;[0x18]
  22.     22 0000001C [00000000]                  stack_segment   dd section.stack.start  ;[0x1c]
  23.     23                                      
  24.     24                                      header_end:               
  25.     25                                      
  26.     26                                  ;===============================================================================
  27.     27                                  SECTION code_1 align=16 vstart=0         ;定义代码段1(16字节对齐)
  28.     28                                  put_string:                              ;显示串(0结尾)。
  29.     29                                                                           ;输入:DS:BX=串地址
  30.     30 00000000 8A0F                             mov cl,[bx]
  31.     31 00000002 08C9                             or cl,cl                        ;cl=0 ?
  32.     32 00000004 7407                             jz .exit                        ;是的,返回主程序
  33.     33 00000006 E80500                           call put_char
  34.     34 00000009 43                               inc bx                          ;下一个字符
  35.     35 0000000A E9F3FF                           jmp put_string
  36.     36                                 
  37.     37                                     .exit:
  38.     38 0000000D C3                               ret
  39.     39                                 
  40.     40                                  ;-------------------------------------------------------------------------------
  41.     41                                  put_char:                                ;显示一个字符
  42.     42                                                                           ;输入:cl=字符ascii
  43.     43 0000000E 50                               push ax
  44.     44 0000000F 53                               push bx
  45.     45 00000010 51                               push cx
  46.     46 00000011 52                               push dx
  47.     47 00000012 1E                               push ds
  48.     48 00000013 06                               push es
  49.     49                                 
  50.     50                                           ;以下取当前光标位置
  51.     51 00000014 BAD403                           mov dx,0x3d4
  52.     52 00000017 B00E                             mov al,0x0e
  53.     53 00000019 EE                               out dx,al
  54.     54                                          
  55.     55 0000001A BAD503                           mov dx,0x3d5
  56.     56 0000001D EC                               in al,dx                        ;高8位
  57.     57 0000001E 88C4                             mov ah,al
  58.     58                                 
  59.     59 00000020 BAD403                           mov dx,0x3d4
  60.     60 00000023 B00F                             mov al,0x0f
  61.     61 00000025 EE                               out dx,al
  62.     62 00000026 BAD503                           mov dx,0x3d5
  63.     63 00000029 EC                               in al,dx                        ;低8位
  64.     64 0000002A 89C3                             mov bx,ax                       ;BX=代表光标位置的16位数
  65.     65                                 
  66.     66 0000002C 80F90D                           cmp cl,0x0d                     ;回车符?
  67.     67 0000002F 750D                             jnz .put_0a                     ;不是。看看是不是换行等字符
  68.     68 00000031 89D8                             mov ax,bx                       ;此句略显多余,但去掉后还得改书,麻烦
  69.     69 00000033 B350                             mov bl,80                       
  70.     70 00000035 F6F3                             div bl
  71.     71 00000037 F6E3                             mul bl
  72.     72 00000039 89C3                             mov bx,ax
  73.     73 0000003B E94900                           jmp .set_cursor
  74.     74                                 
  75.     75                                   .put_0a:
  76.     76 0000003E 80F90A                           cmp cl,0x0a                     ;换行符?
  77.     77 00000041 7507                             jnz .put_other                  ;不是,那就正常显示字符
  78.     78 00000043 81C35000                         add bx,80
  79.     79 00000047 E91000                           jmp .roll_screen
  80.     80                                 
  81.     81                                   .put_other:                             ;正常显示字符
  82.     82 0000004A B800B8                           mov ax,0xb800
  83.     83 0000004D 8EC0                             mov es,ax
  84.     84 0000004F D1E3                             shl bx,1
  85.     85 00000051 26880F                           mov [es:bx],cl
  86.     86                                 
  87.     87                                           ;以下将光标位置推进一个字符
  88.     88 00000054 D1EB                             shr bx,1
  89.     89 00000056 81C30100                         add bx,1
  90.     90                                 
  91.     91                                   .roll_screen:
  92.     92 0000005A 81FBD007                         cmp bx,2000                     ;光标超出屏幕?滚屏
  93.     93 0000005E 7C27                             jl .set_cursor
  94.     94                                 
  95.     95 00000060 B800B8                           mov ax,0xb800
  96.     96 00000063 8ED8                             mov ds,ax
  97.     97 00000065 8EC0                             mov es,ax
  98.     98 00000067 FC                               cld
  99.     99 00000068 BEA000                           mov si,0xa0
  100.    100 0000006B BF0000                           mov di,0x00
  101.    101 0000006E B98007                           mov cx,1920
  102.    102 00000071 F3A5                             rep movsw
  103.    103 00000073 BB000F                           mov bx,3840                     ;清除屏幕最底一行
  104.    104 00000076 B95000                           mov cx,80
  105.    105                                   .cls:
  106.    106 00000079 26C7072007                       mov word[es:bx],0x0720
  107.    107 0000007E 81C30200                         add bx,2
  108.    108 00000082 E2F5                             loop .cls
  109.    109                                 
  110.    110 00000084 BB8007                           mov bx,1920
  111.    111                                 
  112.    112                                   .set_cursor:
  113.    113 00000087 BAD403                           mov dx,0x3d4
  114.    114 0000008A B00E                             mov al,0x0e
  115.    115 0000008C EE                               out dx,al
  116.    116 0000008D BAD503                           mov dx,0x3d5
  117.    117 00000090 88F8                             mov al,bh
  118.    118 00000092 EE                               out dx,al
  119.    119 00000093 BAD403                           mov dx,0x3d4
  120.    120 00000096 B00F                             mov al,0x0f
  121.    121 00000098 EE                               out dx,al
  122.    122 00000099 BAD503                           mov dx,0x3d5
  123.    123 0000009C 88D8                             mov al,bl
  124.    124 0000009E EE                               out dx,al
  125.    125                                 
  126.    126 0000009F 07                               pop es
  127.    127 000000A0 1F                               pop ds
  128.    128 000000A1 5A                               pop dx
  129.    129 000000A2 59                               pop cx
  130.    130 000000A3 5B                               pop bx
  131.    131 000000A4 58                               pop ax
  132.    132                                 
  133.    133 000000A5 C3                               ret
  134.    134                                 
  135.    135                                  ;-------------------------------------------------------------------------------
  136.    136                                    start:
  137.    137                                           ;初始执行时,DS和ES指向用户程序头部段
  138.    138 000000A6 A1[1C00]                         mov ax,[stack_segment]           ;设置到用户程序自己的堆栈
  139.    139 000000A9 8ED0                             mov ss,ax
  140.    140 000000AB BC[0001]                         mov sp,stack_end
  141.    141                                          
  142.    142 000000AE A1[1400]                         mov ax,[data_1_segment]          ;设置到用户程序自己的数据段
  143.    143 000000B1 8ED8                             mov ds,ax
  144.    144                                 
  145.    145 000000B3 BB[0000]                         mov bx,msg0
  146.    146 000000B6 E847FF                           call put_string                  ;显示第一段信息
  147.    147                                 
  148.    148 000000B9 26FF36[1000]                     push word [es:code_2_segment]
  149.    149 000000BE B8[0000]                         mov ax,begin
  150.    150 000000C1 50                               push ax                          ;可以直接push begin,80386+
  151.    151                                          
  152.    152 000000C2 CB                               retf                             ;转移到代码段2执行
  153.    153                                          
  154.    154                                    continue:
  155.    155 000000C3 26A1[1800]                       mov ax,[es:data_2_segment]       ;段寄存器DS切换到数据段2
  156.    156 000000C7 8ED8                             mov ds,ax
  157.    157                                          
  158.    158 000000C9 BB[0000]                         mov bx,msg1
  159.    159 000000CC E831FF                           call put_string                  ;显示第二段信息
  160.    160                                 
  161.    161 000000CF E9FDFF                           jmp $
  162.    162                                 
  163.    163                                  ;===============================================================================
  164.    164                                  SECTION code_2 align=16 vstart=0          ;定义代码段2(16字节对齐)
  165.    165                                 
  166.    166                                    begin:
  167.    167 00000000 26FF36[0C00]                     push word [es:code_1_segment]
  168.    168 00000005 B8[C300]                         mov ax,continue
  169.    169 00000008 50                               push ax                          ;可以直接push continue,80386+
  170.    170                                          
  171.    171 00000009 CB                               retf                             ;转移到代码段1接着执行
  172.    172                                          
  173.    173                                  ;===============================================================================
  174.    174                                  SECTION data_1 align=16 vstart=0
  175.    175                                 
  176.    176 00000000 202054686973206973-         msg0 db '  This is NASM - the famous Netwide Assembler. '
  177.    177 00000009 204E41534D202D2074-
  178.    178 00000012 68652066616D6F7573-
  179.    179 0000001B 204E65747769646520-
  180.    180 00000024 417373656D626C6572-
  181.    181 0000002D 2E20               
  182.    182 0000002F 4261636B2061742053-              db 'Back at SourceForge and in intensive development! '
  183.    183 00000038 6F75726365466F7267-
  184.    184 00000041 6520616E6420696E20-
  185.    185 0000004A 696E74656E73697665-
  186.    186 00000053 20646576656C6F706D-
  187.    187 0000005C 656E742120         
  188.    188 00000061 476574207468652063-              db 'Get the current versions from http://www.nasm.us/.'
  189.    189 0000006A 757272656E74207665-
  190.    190 00000073 7273696F6E73206672-
  191.    191 0000007C 6F6D20687474703A2F-
  192.    192 00000085 2F7777772E6E61736D-
  193.    193 0000008E 2E75732F2E         
  194.    194 00000093 0D0A0D0A                         db 0x0d,0x0a,0x0d,0x0a
  195.    195 00000097 20204578616D706C65-              db '  Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a
  196.    196 000000A0 20636F646520666F72-
  197.    197 000000A9 2063616C63756C6174-
  198.    198 000000B2 6520312B322B2E2E2E-
  199.    199 000000BB 2B313030303A0D0A0D-
  200.    200 000000C4 0A                 
  201.    201 000000C5 2020202020786F7220-              db '     xor dx,dx',0x0d,0x0a
  202.    202 000000CE 64782C64780D0A     
  203.    203 000000D5 2020202020786F7220-              db '     xor ax,ax',0x0d,0x0a
  204.    204 000000DE 61782C61780D0A     
  205.    205 000000E5 2020202020786F7220-              db '     xor cx,cx',0x0d,0x0a
  206.    206 000000EE 63782C63780D0A     
  207.    207 000000F5 202040403A0D0A                   db '  @@:',0x0d,0x0a
  208.    208 000000FC 2020202020696E6320-              db '     inc cx',0x0d,0x0a
  209.    209 00000105 63780D0A           
  210.    210 00000109 202020202061646420-              db '     add ax,cx',0x0d,0x0a
  211.    211 00000112 61782C63780D0A     
  212.    212 00000119 202020202061646320-              db '     adc dx,0',0x0d,0x0a
  213.    213 00000122 64782C300D0A      
  214.    214 00000128 2020202020696E6320-              db '     inc cx',0x0d,0x0a
  215.    215 00000131 63780D0A           
  216.    216 00000135 2020202020636D7020-              db '     cmp cx,1000',0x0d,0x0a
  217.    217 0000013E 63782C313030300D0A
  218.    218 00000147 20202020206A6C6520-              db '     jle @@',0x0d,0x0a
  219.    219 00000150 40400D0A           
  220.    220 00000154 20202020202E2E2E20-              db '     ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a
  221.    221 0000015D 2E2E2E28536F6D6520-
  222.    222 00000166 6F7468657220636F64-
  223.    223 0000016F 6573290D0A0D0A     
  224.    224 00000176 00                               db 0
  225.    225                                 
  226.    226                                  ;===============================================================================
  227.    227                                  SECTION data_2 align=16 vstart=0
  228.    228                                 
  229.    229 00000000 20205468652061626F-         msg1 db '  The above contents is written by LeeChung. '
  230.    230 00000009 766520636F6E74656E-
  231.    231 00000012 747320697320777269-
  232.    232 0000001B 7474656E206279204C-
  233.    233 00000024 65654368756E672E20
  234.    234 0000002D 323031312D30352D30-              db '2011-05-06'
  235.    235 00000036 36                 
  236.    236 00000037 00                               db 0
  237.    237                                 
  238.    238                                  ;===============================================================================
  239.    239                                  SECTION stack align=16 vstart=0
  240.    240                                             
  241.    241 00000000 <res 00000100>                   resb 256
  242.    242          ******************       warning: uninitialized space declared in stack section: zeroing
  243.    243                                 
  244.    244                                  stack_end:  
  245.    245                                 
  246.    246                                  ;===============================================================================
  247.    247                                  SECTION trail align=16
  248.    248                                  program_end:
复制代码


  1.          ;代码清单8-1
  2.          ;文件名:c08_mbr.asm
  3.          ;文件说明:硬盘主引导扇区代码(加载程序)
  4.          ;创建日期:2011-5-5 18:17
  5.          
  6.          app_lba_start equ 100           ;声明常数(用户程序起始逻辑扇区号)
  7.                                          ;常数的声明不会占用汇编地址
  8.                                     
  9. SECTION mbr align=16 vstart=0x7c00                                    

  10.          ;设置堆栈段和栈指针
  11.          mov ax,0      
  12.          mov ss,ax
  13.          mov sp,ax
  14.       
  15.          mov ax,[cs:phy_base]            ;计算用于加载用户程序的逻辑段地址
  16.          mov dx,[cs:phy_base+0x02]
  17.          mov bx,16        
  18.          div bx            
  19.          mov ds,ax                       ;令DS和ES指向该段以进行操作
  20.          mov es,ax                        
  21.    
  22.          ;以下读取程序的起始部分
  23.          xor di,di
  24.          mov si,app_lba_start            ;程序在硬盘上的起始逻辑扇区号
  25.          xor bx,bx                       ;加载到DS:0x0000处
  26.          call read_hard_disk_0
  27.       
  28.          ;以下判断整个程序有多大
  29.          mov dx,[2]                      ;曾经把dx写成了ds,花了二十分钟排错
  30.          mov ax,[0]
  31.          mov bx,512                      ;512字节每扇区
  32.          div bx
  33.          cmp dx,0
  34.          jnz @1                          ;未除尽,因此结果比实际扇区数少1
  35.          dec ax                          ;已经读了一个扇区,扇区总数减1
  36.    @1:
  37.          cmp ax,0                        ;考虑实际长度小于等于512个字节的情况
  38.          jz direct
  39.          
  40.          ;读取剩余的扇区
  41.          push ds                         ;以下要用到并改变DS寄存器

  42.          mov cx,ax                       ;循环次数(剩余扇区数)
  43.    @2:
  44.          mov ax,ds
  45.          add ax,0x20                     ;得到下一个以512字节为边界的段地址
  46.          mov ds,ax  
  47.                               
  48.          xor bx,bx                       ;每次读时,偏移地址始终为0x0000
  49.          inc si                          ;下一个逻辑扇区
  50.          call read_hard_disk_0
  51.          loop @2                         ;循环读,直到读完整个功能程序

  52.          pop ds                          ;恢复数据段基址到用户程序头部段
  53.       
  54.          ;计算入口点代码段基址
  55.    direct:
  56.          mov dx,[0x08]
  57.          mov ax,[0x06]
  58.          call calc_segment_base
  59.          mov [0x06],ax                   ;回填修正后的入口点代码段基址
  60.       
  61.          ;开始处理段重定位表
  62.          mov cx,[0x0a]                   ;需要重定位的项目数量
  63.          mov bx,0x0c                     ;重定位表首地址
  64.          
  65. realloc:
  66.          mov dx,[bx+0x02]                ;32位地址的高16位
  67.          mov ax,[bx]
  68.          call calc_segment_base
  69.          mov [bx],ax                     ;回填段的基址
  70.          add bx,4                        ;下一个重定位项(每项占4个字节)
  71.          loop realloc
  72.       
  73.          jmp far [0x04]                  ;转移到用户程序  

  74. ;-------------------------------------------------------------------------------
  75. read_hard_disk_0:                        ;从硬盘读取一个逻辑扇区
  76.                                          ;输入:DI:SI=起始逻辑扇区号
  77.                                          ;      DS:BX=目标缓冲区地址
  78.          push ax
  79.          push bx
  80.          push cx
  81.          push dx
  82.       
  83.          mov dx,0x1f2
  84.          mov al,1
  85.          out dx,al                       ;读取的扇区数

  86.          inc dx                          ;0x1f3
  87.          mov ax,si
  88.          out dx,al                       ;LBA地址7~0

  89.          inc dx                          ;0x1f4
  90.          mov al,ah
  91.          out dx,al                       ;LBA地址15~8

  92.          inc dx                          ;0x1f5
  93.          mov ax,di
  94.          out dx,al                       ;LBA地址23~16

  95.          inc dx                          ;0x1f6
  96.          mov al,0xe0                     ;LBA28模式,主盘
  97.          or al,ah                        ;LBA地址27~24
  98.          out dx,al

  99.          inc dx                          ;0x1f7
  100.          mov al,0x20                     ;读命令
  101.          out dx,al

  102.   .waits:
  103.          in al,dx
  104.          and al,0x88
  105.          cmp al,0x08
  106.          jnz .waits                      ;不忙,且硬盘已准备好数据传输

  107.          mov cx,256                      ;总共要读取的字数
  108.          mov dx,0x1f0
  109.   .readw:
  110.          in ax,dx
  111.          mov [bx],ax
  112.          add bx,2
  113.          loop .readw

  114.          pop dx
  115.          pop cx
  116.          pop bx
  117.          pop ax
  118.       
  119.          ret

  120. ;-------------------------------------------------------------------------------
  121. calc_segment_base:                       ;计算16位段地址
  122.                                          ;输入:DX:AX=32位物理地址
  123.                                          ;返回:AX=16位段基地址
  124.          push dx                          
  125.          
  126.          add ax,[cs:phy_base]
  127.          adc dx,[cs:phy_base+0x02]
  128.          shr ax,4
  129.          ror dx,4
  130.          and dx,0xf000
  131.          or ax,dx
  132.          
  133.          pop dx
  134.          
  135.          ret

  136. ;-------------------------------------------------------------------------------
  137.          phy_base dd 0x10000             ;用户程序被加载的物理起始地址
  138.          
  139. times 510-($-$$) db 0
  140.                   db 0x55,0xaa
复制代码



  1.      1                                           ;代码清单8-1
  2.      2                                           ;文件名:c08_mbr.asm
  3.      3                                           ;文件说明:硬盘主引导扇区代码(加载程序)
  4.      4                                           ;创建日期:2011-5-5 18:17
  5.      5                                          
  6.      6                                           app_lba_start equ 100           ;声明常数(用户程序起始逻辑扇区号)
  7.      7                                                                           ;常数的声明不会占用汇编地址
  8.      8                                                                     
  9.      9                                  SECTION mbr align=16 vstart=0x7c00                                    
  10.     10                                 
  11.     11                                           ;设置堆栈段和栈指针
  12.     12 00000000 B80000                           mov ax,0      
  13.     13 00000003 8ED0                             mov ss,ax
  14.     14 00000005 89C4                             mov sp,ax
  15.     15                                       
  16.     16 00000007 2EA1[CA00]                       mov ax,[cs:phy_base]            ;计算用于加载用户程序的逻辑段地址
  17.     17 0000000B 2E8B16[CC00]                     mov dx,[cs:phy_base+0x02]
  18.     18 00000010 BB1000                           mov bx,16        
  19.     19 00000013 F7F3                             div bx            
  20.     20 00000015 8ED8                             mov ds,ax                       ;令DS和ES指向该段以进行操作
  21.     21 00000017 8EC0                             mov es,ax                        
  22.     22                                      
  23.     23                                           ;以下读取程序的起始部分
  24.     24 00000019 31FF                             xor di,di
  25.     25 0000001B BE6400                           mov si,app_lba_start            ;程序在硬盘上的起始逻辑扇区号
  26.     26 0000001E 31DB                             xor bx,bx                       ;加载到DS:0x0000处
  27.     27 00000020 E85300                           call read_hard_disk_0
  28.     28                                       
  29.     29                                           ;以下判断整个程序有多大
  30.     30 00000023 8B160200                         mov dx,[2]                      ;曾经把dx写成了ds,花了二十分钟排错
  31.     31 00000027 A10000                           mov ax,[0]
  32.     32 0000002A BB0002                           mov bx,512                      ;512字节每扇区
  33.     33 0000002D F7F3                             div bx
  34.     34 0000002F 81FA0000                         cmp dx,0
  35.     35 00000033 7501                             jnz @1                          ;未除尽,因此结果比实际扇区数少1
  36.     36 00000035 48                               dec ax                          ;已经读了一个扇区,扇区总数减1
  37.     37                                     @1:
  38.     38 00000036 3D0000                           cmp ax,0                        ;考虑实际长度小于等于512个字节的情况
  39.     39 00000039 7413                             jz direct
  40.     40                                          
  41.     41                                           ;读取剩余的扇区
  42.     42 0000003B 1E                               push ds                         ;以下要用到并改变DS寄存器
  43.     43                                 
  44.     44 0000003C 89C1                             mov cx,ax                       ;循环次数(剩余扇区数)
  45.     45                                     @2:
  46.     46 0000003E 8CD8                             mov ax,ds
  47.     47 00000040 052000                           add ax,0x20                     ;得到下一个以512字节为边界的段地址
  48.     48 00000043 8ED8                             mov ds,ax  
  49.     49                                                               
  50.     50 00000045 31DB                             xor bx,bx                       ;每次读时,偏移地址始终为0x0000
  51.     51 00000047 46                               inc si                          ;下一个逻辑扇区
  52.     52 00000048 E82B00                           call read_hard_disk_0
  53.     53 0000004B E2F1                             loop @2                         ;循环读,直到读完整个功能程序
  54.     54                                 
  55.     55 0000004D 1F                               pop ds                          ;恢复数据段基址到用户程序头部段
  56.     56                                       
  57.     57                                           ;计算入口点代码段基址
  58.     58                                     direct:
  59.     59 0000004E 8B160800                         mov dx,[0x08]
  60.     60 00000052 A10600                           mov ax,[0x06]
  61.     61 00000055 E85900                           call calc_segment_base
  62.     62 00000058 A30600                           mov [0x06],ax                   ;回填修正后的入口点代码段基址
  63.     63                                       
  64.     64                                           ;开始处理段重定位表
  65.     65 0000005B 8B0E0A00                         mov cx,[0x0a]                   ;需要重定位的项目数量
  66.     66 0000005F BB0C00                           mov bx,0x0c                     ;重定位表首地址
  67.     67                                            
  68.     68                                   realloc:
  69.     69 00000062 8B5702                           mov dx,[bx+0x02]                ;32位地址的高16位
  70.     70 00000065 8B07                             mov ax,[bx]
  71.     71 00000067 E84700                           call calc_segment_base
  72.     72 0000006A 8907                             mov [bx],ax                     ;回填段的基址
  73.     73 0000006C 81C30400                         add bx,4                        ;下一个重定位项(每项占4个字节)
  74.     74 00000070 E2F0                             loop realloc
  75.     75                                       
  76.     76 00000072 FF2E0400                         jmp far [0x04]                  ;转移到用户程序  
  77.     77                                   
  78.     78                                  ;-------------------------------------------------------------------------------
  79.     79                                  read_hard_disk_0:                        ;从硬盘读取一个逻辑扇区
  80.     80                                                                           ;输入:DI:SI=起始逻辑扇区号
  81.     81                                                                           ;      DS:BX=目标缓冲区地址
  82.     82 00000076 50                               push ax
  83.     83 00000077 53                               push bx
  84.     84 00000078 51                               push cx
  85.     85 00000079 52                               push dx
  86.     86                                       
  87.     87 0000007A BAF201                           mov dx,0x1f2
  88.     88 0000007D B001                             mov al,1
  89.     89 0000007F EE                               out dx,al                       ;读取的扇区数
  90.     90                                 
  91.     91 00000080 42                               inc dx                          ;0x1f3
  92.     92 00000081 89F0                             mov ax,si
  93.     93 00000083 EE                               out dx,al                       ;LBA地址7~0
  94.     94                                 
  95.     95 00000084 42                               inc dx                          ;0x1f4
  96.     96 00000085 88E0                             mov al,ah
  97.     97 00000087 EE                               out dx,al                       ;LBA地址15~8
  98.     98                                 
  99.     99 00000088 42                               inc dx                          ;0x1f5
  100.    100 00000089 89F8                             mov ax,di
  101.    101 0000008B EE                               out dx,al                       ;LBA地址23~16
  102.    102                                 
  103.    103 0000008C 42                               inc dx                          ;0x1f6
  104.    104 0000008D B0E0                             mov al,0xe0                     ;LBA28模式,主盘
  105.    105 0000008F 08E0                             or al,ah                        ;LBA地址27~24
  106.    106 00000091 EE                               out dx,al
  107.    107                                 
  108.    108 00000092 42                               inc dx                          ;0x1f7
  109.    109 00000093 B020                             mov al,0x20                     ;读命令
  110.    110 00000095 EE                               out dx,al
  111.    111                                 
  112.    112                                    .waits:
  113.    113 00000096 EC                               in al,dx
  114.    114 00000097 2488                             and al,0x88
  115.    115 00000099 3C08                             cmp al,0x08
  116.    116 0000009B 75F9                             jnz .waits                      ;不忙,且硬盘已准备好数据传输
  117.    117                                 
  118.    118 0000009D B90001                           mov cx,256                      ;总共要读取的字数
  119.    119 000000A0 BAF001                           mov dx,0x1f0
  120.    120                                    .readw:
  121.    121 000000A3 ED                               in ax,dx
  122.    122 000000A4 8907                             mov [bx],ax
  123.    123 000000A6 81C30200                         add bx,2
  124.    124 000000AA E2F7                             loop .readw
  125.    125                                 
  126.    126 000000AC 5A                               pop dx
  127.    127 000000AD 59                               pop cx
  128.    128 000000AE 5B                               pop bx
  129.    129 000000AF 58                               pop ax
  130.    130                                       
  131.    131 000000B0 C3                               ret
  132.    132                                 
  133.    133                                  ;-------------------------------------------------------------------------------
  134.    134                                  calc_segment_base:                       ;计算16位段地址
  135.    135                                                                           ;输入:DX:AX=32位物理地址
  136.    136                                                                           ;返回:AX=16位段基地址
  137.    137 000000B1 52                               push dx                          
  138.    138                                          
  139.    139 000000B2 2E0306[CA00]                     add ax,[cs:phy_base]
  140.    140 000000B7 2E1316[CC00]                     adc dx,[cs:phy_base+0x02]
  141.    141 000000BC C1E804                           shr ax,4
  142.    142 000000BF C1CA04                           ror dx,4
  143.    143 000000C2 81E200F0                         and dx,0xf000
  144.    144 000000C6 09D0                             or ax,dx
  145.    145                                          
  146.    146 000000C8 5A                               pop dx
  147.    147                                          
  148.    148 000000C9 C3                               ret
  149.    149                                 
  150.    150                                  ;-------------------------------------------------------------------------------
  151.    151 000000CA 00000100                         phy_base dd 0x10000             ;用户程序被加载的物理起始地址
  152.    152                                          
  153.    153 000000CE 00<rept>                 times 510-($-$$) db 0
  154.    154 000001FE 55AA                                      db 0x55,0xaa

复制代码
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|4ameta

GMT+8, 2022-10-3 01:08 , Processed in 0.047480 second(s), 29 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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