国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
80386ASM程序設(shè)計基礎(chǔ)(八)
80386實模式下編程
 80386在實模式下是一個更快的8086,它不但可以進行32位操作,而且還可以進32位尋址,并且還可以使用80386的擴展指令。不過,由于是在實模下,尋址的最大空間為1M。在一個段內(nèi),段的最大長度不超過64K,否則就會發(fā)生異常。
 在8086下定義一個段的完整格式是:
 段名 [定位類型]  [組合類型]  [‘類別’]
 80386下定義一個段的完整格式是:
 段名 [定位類型]  [組合類型]  [‘類別’] [屬性類型]
 說明:屬性類型有兩種:USE32和USE16,USE32表示32位段,USE16表示16位段。如果你在程序中用到偽指令.386,那么默認的屬性類型就是USE32(32位段),如果沒有用偽指令指定CPU的類型,那么默認的屬性類型就是USE16,在實方式下只能使用16位段,即用USE16。
 eg:
    CSEG PARA PUBLIC USE32;定義一個32位的段
      AA DW ?

      BB DD ?
      CC DB ?
      DD DW ?
      EE DW 0,0,0.....
    CSEG ENDS
 由于在80386中用到了66H操作前綴和67H地址前綴,因此盡管在實式模式下,只要設(shè)定的CPU類型是80386,仍然可以進行32位操作,可以進行32位尋址,66H,67H這兩個前綴無需程序員在程序中書寫,匯編程序會自動加上的。只要在程序中對32位操作數(shù)進行訪問,或進行32位尋址,那么就會加上操作數(shù)前綴66H和地址前綴67H。相反,如果在32位段中對16位或8位的訪問,匯編程序中也會加上這兩個前綴。
    下面將給出一個例子程序,演示一下在80386的實模式下編程的方法與技巧(這是從網(wǎng)上down的一個程序,不是我寫的,但我會作詳細的解剖,并與8086下的程序設(shè)計作出比較):
    用十進制,十六進制,二進制三種形式顯示雙字存儲單元F000:1234中的內(nèi)容
   |------------------MAIN PROC------------|
   | .386                                  |
   | code segment para public ‘code‘ use16 |
   |   assume cs:code                      |
   | begin:                                |
   |   mov ax,0f000h                       |
   |   mov fs,ax                           |
   |   mov eax,fs:[1234H]                  |
   |   call todec                          |
   |   call newline                        |
   |   call tohex                          |
   |   mov al,‘H‘                          |
   |   call echo                           |
   |   call newline                        |
   |   call tobin                          |
   |   mov al,‘B‘                          |
   |   call echo                           |
   |   call newline                        |
   |   mov ah,4ch                          |
   |   int 21h                             |
   |---------------------------------------|  
    ;sub-function todec
    todec proc near
       pushad
       mov ebx,10
       xor cx,cx
     dec1:
       xor edx,edx
       div ebx
       push dx
       inc cx
       or eax,eax
       jnz dec1
     dec2:
       pop ax
       call toasc
       call echo
       loop dec2
       popad
       ret
   todec endp
  
   ;sub-function tobin
   tobin proc near
      push eax
      push ecx
      push edx
      bsr edx,eax
      jnz bin1
      xor dx,dx
    bin1:
      mov cl,31
      sub cl,dl
      shl eax,cl
      mov cx,dx
      inc cx
      mov edx,eax
    bin2:
      rol edx,1
      mov al,‘0‘
      adc al,0
      call echo
      loop bin2
      pop  edx
      pop  ecx
      pop  eax
      ret
   tobin endp

   ;sub-function tohex
   tohex proc near
     countb=8
     enter countb,0
     movzx ebp,bp
     mov   ecx,countb
     mov   edx,eax
   hex1:
     mov al,dl
     and al,0fh
     mov [ebp-countb+ecx-1],al
     ror edx,4
     loop hex1
     mov cx,countb
     xor ebx,ebx
   hex2:
     cmp byte ptr [ebp-countb+ebx],0
     jnz hex3
     inc ebx
     loop hex2
     dec ebx
     mov cx,1
  hex3:
     mov al,[ebp-countb+ebx]
     inc ebx
     call toasc
     call echo
     loop hex3
     leave
     ret
  tohex endp
 
 ;sub-function toasc
 toasc proc near
     and al,0fh
     cmp al,‘0‘
     cmp al,‘9‘
     seta dl
     movzx dx,dl
     imul dx,7
     add al,dl
 toasc1:ret
 toasc endp

 ;sub-function newline
  newline proc near
    push dx
    push ax
    mov dl,0dh
    mov ah,2
    int 21
    mov dl,0ah
    int 21
    pop ax
    pop dx
    ret
  newline endp

  echo proc near
    push ax
    push dx
    mov dl,al
    mov ah,2
    int 21h
    pop dx
    pop ax
  echo endp   
 剖析:
   先來看主程序框架,下面就是MAIN PROC:
   |------------------MAIN PROC-------------------------------|
   |.386;定義處理器的類型為386表示可以使用所有80386指令       |
   | code segment para public ‘code‘ use16                    |
   |   assume cs:code                                         |
   | begin:                                                   |
   |   mov ax,0f000h                                          |
   |   mov fs,ax;將f000h裝入段寄存器fs                        |
   |   mov eax,fs:[1234H];將1234H內(nèi)存單元中的雙字送給寄存器EAX|
   |   call todec;調(diào)用子過程todec                             |
   |   call newline;調(diào)用子過程newline進行回車換行             |
   |   mov eax,fs:[1234h];                                    |
   |   call tohex;調(diào)用子過程tohex                             |
   |   mov al,‘H‘                                             |
   |   call echo;顯示字符H                                    |
   |   call newline;                                          |
   |   mov eax,fs:[1234H]                                     |
   |   call tobin;調(diào)用子過程tobin                             |
   |   mov al,‘B‘                                             |
   |   call echo                                               

  
   |   call newline                                           |
   |   mov ah,4ch                                             |
   |   int 21h                                                |
   |----------------------------------------------------------|
   主程序中的內(nèi)容一目了然,很簡單。和8086下唯一不同的是就是要用偽指令定義CPU的類型,并且段寄存器的定義多了一個屬性類型USE16,再就是32位操作,使用80386的指令,其它的和8086下沒有什么區(qū)別。
   重點是要分析幾個過程,從網(wǎng)上down下來時,過程newline和toasc沒有實現(xiàn)代碼,因為這很簡單,所以上述toasc,newline,echo的過程體是由我寫進去的,這兩個過程體代碼不多而且非常簡單,就不作介紹了。重點介紹todec,tobin,tohex。
   a.子過程todec,這個子過程的主要功能是將f000:1234雙字單元的內(nèi)容用十進制顯示,下面就來看每一行代碼:   
   |-----------------------------------------------------------|
   |todec proc near                                            |
   |   pushad                                                  |
   |   mov ebx,10                                              |
   |   xor cx,cx                                               |
   |  dec1:                                                    |
   |   xor edx,edx                                             |
   |   div ebx                                                 |
   |   push dx                                                 |
   |   inc cx                                                  |
   |   or eax,eax                                              |
   |   jnz dec1                                                |
   |  dec2:                                                    |
   |   pop ax                                                  |
   |   call toasc                                              |
   |   call echo                                               |
   |   loop dec2                                               |
   |   popad                                                   |
   |   ret                                                     |
   |todec endp                                                 |
   |-----------------------------------------------------------|
   分析:將一個數(shù)用十進制數(shù)來表示,要它對它進行除以10的運算,得到商和余數(shù)。再將商除以10,如此循環(huán)直到商為0為止,在這個過程中得到的一系列的模(余數(shù))就是十進制數(shù)系列。在主程序中,已經(jīng)將f000:1234雙字單元的內(nèi)容放到EAX寄存器中,由于后來要用十六進制數(shù),二進制數(shù)顯示,所以EAX寄存器的內(nèi)容不允許改變,因此在子過程的一開始,要將EAX的內(nèi)容先入棧,所以子過程的一開始就用PUSHAD將8個32位通用寄存器的內(nèi)容全部入棧。在標號dec1不斷地進行除以10運算,將所得到的余數(shù)全部入棧,同時用cx進行計數(shù)。在標號dec2中,逐個彈出在標號dec1中得到的余數(shù),然后分別將它們顯示出來,這樣就可以將該存儲單元中的內(nèi)容用十進數(shù)表示,下面解釋每一條指令的功能:
   a1.pushad;將8個32位通用寄存器全部入棧
   a2.xor cx,cx;cx清0
   a3.mov ebx,10;10=>ebx
   a4.xor edx,edx;edx清0
   a5.div ebx;edx存放高32位,不過是0,EAX中存放低32位,即ffff:[1234]雙字的內(nèi)容;除法得到的商放在EAX,余數(shù)放在EDX 
   a6.push dx;將edx的低16位dx入棧
   a7.inc cx;cx+1=>cx
   a8.or eax,eax;對eax進行或操作,主要是用來判斷eax是否為0,即判斷商是否為0,從而判斷是否應(yīng)該結(jié)束標號為dec1的循環(huán)。
   a9.jnz dec1
   a10.pop ax;將放在堆棧中的余數(shù)逐個彈出到ax中
   a11.call toasc;顯示ax的內(nèi)容
   a12.call echo
   a13.loop dec2;將所有的余數(shù)顯示完畢
   a14.popad;8個32位通用寄存器全部出棧
   a15.ret

   b.子過程tohex
    PUSH BP
    SP=>BP
    SP<=SP-CNT1
   |------------------------------------------------------------|
   |tohex proc near                                             |
   |  countb=8                                                  |
   |  enter countb,0                                            |
   |  movzx ebp,bp                                              |
   |  mov   ecx,countb                                          |
   |  mov   edx,eax                                             |
   |hex1:                                                       |
   |  mov al,dl                                                 |
   |  and al,0fh                                                |
   |  mov [ebp-countb+ecx-1],al                                 |
   |  ror edx,4                                                 |
   |  loop hex1                                                 |
   |  mov cx,countb                                             |
   |  xor ebx,ebx                                               |
   |hex2:                                                       |
   |  cmp byte ptr [ebp-countb+ebx],0                           |
   |  jnz hex3                                                  |
   |  inc ebx                                                   |
   |  loop hex2                                                 |
   |  dec ebx                                                   |
   |  mov cx,1                                                  |
   |hex3:                                                       |
   |  mov al,[ebp-countb+ebx]                                   |
   |  inc ebx                                                   |
   |  call toasc                                                |
   |  call echo                                                 |
   |  loop hex3                                                 |
   |  leave                                                     |
   |  ret                                                       |
   |tohex endp                                                  |
   |------------------------------------------------------------|  
   分析:該子過程的功能是將f000:1234雙字單元的內(nèi)容以16進制數(shù)顯示出來,首先來考慮一下將一個數(shù)以16進制數(shù)表示出來的算法,事實上在匯編語言中操作數(shù)一直都是以十六進制表示的。因此,在這個子過程中不可以像上一個子過程一樣,通過不斷的除法取模得到結(jié)果。事實上,我們只需要將32位操作,以每半個字節(jié)(四位)的內(nèi)容顯示出來就可以了,有了這一編程思想,就很容易看懂上面的子過程。當(dāng)然你們會問,為什么要每次只顯示半個字節(jié)而不顯示一個字節(jié)呢?呵呵,十六進制的十六個數(shù)是從0000-1111,不就是半個字節(jié)了。所以要循環(huán)8次才可以顯示出32位的EAX,所以這里用ror指令來不斷循環(huán)移位,每次右移4位放到dl的低4位中。這8個半字節(jié)分別放在[ebp-1]至[ebp-8]的存儲單元中。不過,存儲的順序是由低位到高位,如果就這樣顯示結(jié)果肯定顯示反了。標號hex2,hex3的主要功能是用來判斷f000:1234雙字單元的內(nèi)容是否為0,如果為0,只需要將最后結(jié)果顯示一個0即可,否則就顯示出8位內(nèi)容。下面是每條指令的功能:
   b1.countb=8;偽指令定義一局部變量countb,其值為8
   b2.enter countb,0;建立堆??蚣苤噶?br>   b3.movzx ebp,bp;對bp進行零擴展
   b4.mov   ecx,countb;8=>ecx
   b5.mov   edx,eax;將eax=>edx
   b6.mov al,dl
   b7.and al,0fh;取低4位
   b8.mov [ebp-countb+ecx-1],al;將8個半字節(jié)的內(nèi)容逐一送到[ebp-1]至[ebp-8]的內(nèi)存單元中
   b9.ror edx,4;對edx進行循環(huán)右移,每次移動4位
   b10.loop hex1
   b11.mov cx,countb
   b12.xor ebx,ebx;ebx清0
   b13.cmp byte ptr [ebp-countb+ebx],0;下面的語句主要用來判斷源操作數(shù)f000:1234的內(nèi)容是否為0,如果是0,就在屏幕上只顯示一個0
   b14.jnz hex3
   b15.inc ebx
   b16.loop hex2
   b17.dec ebx
   b18.mov cx,1
   b19.mov al,[ebp-countb+ebx];逐一顯示[ebp-8]到[ebp-1]的內(nèi)容。
   b20.inc ebx
   b21.call toasc
   b22.call echo
   b23.loop hex3
   b24.leave;釋放堆??蚣?br>   b25.ret
    
   c.子過程tobin
   |---------------------------------------|
   |tobin proc near                        |
   |   push eax                            |
   |   push ecx                            |
   |   push edx                            |
   |   bsr edx,eax                         |
   |   jnz bin1                            |
   |   xor dx,dx                           |
   |bin1:                                  |
   |   mov cl,31                           |
   |   sub cl,dl                           |
   |   shl eax,cl                          |

   |   mov cx,dx                           |
   |   inc cx                                                   
   |   mov edx,eax                         |
   |bin2:                                                       

   |   rol edx,1                                                
   |   mov al,‘0‘                                               
   |   adc al,0                                                 
   |   call echo                                                
   |   loop bin2                                                
   |   pop  edx                            |
   |   pop  ecx                                                 
   |   pop  eax                                                 
   |   ret                                                      
   |tobin endp                                                  
   |---------------------------------------|
   分析:將一個數(shù)用二進制數(shù)顯示出來,只需要用ROL指令就可以了。這里作者寫的程序就是這個思路,在標號bin1中主要判斷f000:1234單元的內(nèi)容是否為0,如果為0,那么只需要在屏幕上顯示一個0就可以了。否則的話,就用ROL指令對源操作數(shù)移位32位,從最高位31位到最低位逐一顯示出來,程序設(shè)計思路很簡單,沒有什么復(fù)雜的算法,下面看每一條指令的含義:
   c1.push eax;eax入棧
   c2.push ecx;ecx入棧
   c3.push edx;edx入棧
   c4.bsr edx,eax;對eax進行掃描,并把第一個為1的位號送給edx
   c5.jnz bin1;如果eax不為0,就跳到c7去執(zhí)行
   c6.xor dx,dx;如果eax為0,就將dx清0
   c7.mov cl,31;從c7到c12主要用來設(shè)置計數(shù)器cx,如果eax=0,那么就設(shè)置cx=1,如果eax不等于0,那么就設(shè)置ecx=32
   c8.sub cl,dl
   c9.shl eax,cl
   c10.mov cx,dx
   c11.inc cx
   c12.mov edx,eax
   c13.rol edx,1;從c13到c15主要用來顯示二進制數(shù)據(jù),順序是從最高位31位到最低位0位
   c14.mov al,‘0‘
   c15.adc al,0
   c16.call echo
   c17.loop bin2
   c18.pop  edx;edx出棧
   c19.pop  ecx;ecx出棧
   c20.pop  eax;eax出棧
   c21.ret
   在后續(xù)的篇幅里將主要介紹保護式下的段頁管理機制及及如何在保護模下編程。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
匯編語言的準備知識
IDA簡易教程
軟件脫殼、破重啟驗證、追碼、制作內(nèi)存注冊機
qq反匯編日志
Kernel panic 信息分析方法(轉(zhuǎn)自高人)
去除天狼星視頻加密系統(tǒng)的各種限制
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服