乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      80386ASM程序設(shè)計(jì)基礎(chǔ)(八)

       壞壞 2006-12-09
      80386實(shí)模式下編程
       80386在實(shí)模式下是一個(gè)更快的8086,它不但可以進(jìn)行32位操作,而且還可以進(jìn)32位尋址,并且還可以使用80386的擴(kuò)展指令。不過(guò),由于是在實(shí)模下,尋址的最大空間為1M。在一個(gè)段內(nèi),段的最大長(zhǎng)度不超過(guò)64K,否則就會(huì)發(fā)生異常。
       在8086下定義一個(gè)段的完整格式是:
       段名 [定位類(lèi)型]  [組合類(lèi)型]  [‘類(lèi)別’]
       80386下定義一個(gè)段的完整格式是:
       段名 [定位類(lèi)型]  [組合類(lèi)型]  [‘類(lèi)別’] [屬性類(lèi)型]
       說(shuō)明:屬性類(lèi)型有兩種:USE32和USE16,USE32表示32位段,USE16表示16位段。如果你在程序中用到偽指令.386,那么默認(rèn)的屬性類(lèi)型就是USE32(32位段),如果沒(méi)有用偽指令指定CPU的類(lèi)型,那么默認(rèn)的屬性類(lèi)型就是USE16,在實(shí)方式下只能使用16位段,即用USE16。
       eg:
          CSEG PARA PUBLIC USE32;定義一個(gè)32位的段
            AA DW ?

            BB DD ?
            CC DB ?
            DD DW ?
            EE DW 0,0,0.....
          CSEG ENDS
       由于在80386中用到了66H操作前綴和67H地址前綴,因此盡管在實(shí)式模式下,只要設(shè)定的CPU類(lèi)型是80386,仍然可以進(jìn)行32位操作,可以進(jìn)行32位尋址,66H,67H這兩個(gè)前綴無(wú)需程序員在程序中書(shū)寫(xiě),匯編程序會(huì)自動(dòng)加上的。只要在程序中對(duì)32位操作數(shù)進(jìn)行訪問(wèn),或進(jìn)行32位尋址,那么就會(huì)加上操作數(shù)前綴66H和地址前綴67H。相反,如果在32位段中對(duì)16位或8位的訪問(wèn),匯編程序中也會(huì)加上這兩個(gè)前綴。
          下面將給出一個(gè)例子程序,演示一下在80386的實(shí)模式下編程的方法與技巧(這是從網(wǎng)上down的一個(gè)程序,不是我寫(xiě)的,但我會(huì)作詳細(xì)的解剖,并與8086下的程序設(shè)計(jì)作出比較):
          用十進(jìn)制,十六進(jìn)制,二進(jìn)制三種形式顯示雙字存儲(chǔ)單元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   
       剖析:
         先來(lái)看主程序框架,下面就是MAIN PROC:
         |------------------MAIN PROC-------------------------------|
         |.386;定義處理器的類(lèi)型為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)用子過(guò)程todec                             |
         |   call newline;調(diào)用子過(guò)程newline進(jìn)行回車(chē)換行             |
         |   mov eax,fs:[1234h];                                    |
         |   call tohex;調(diào)用子過(guò)程tohex                             |
         |   mov al,‘H‘                                             |
         |   call echo;顯示字符H                                    |
         |   call newline;                                          |
         |   mov eax,fs:[1234H]                                     |
         |   call tobin;調(diào)用子過(guò)程tobin                             |
         |   mov al,‘B‘                                             |
         |   call echo                                               

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

         b.子過(guò)程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                                                  |
         |------------------------------------------------------------|  
         分析:該子過(guò)程的功能是將f000:1234雙字單元的內(nèi)容以16進(jìn)制數(shù)顯示出來(lái),首先來(lái)考慮一下將一個(gè)數(shù)以16進(jìn)制數(shù)表示出來(lái)的算法,事實(shí)上在匯編語(yǔ)言中操作數(shù)一直都是以十六進(jìn)制表示的。因此,在這個(gè)子過(guò)程中不可以像上一個(gè)子過(guò)程一樣,通過(guò)不斷的除法取模得到結(jié)果。事實(shí)上,我們只需要將32位操作,以每半個(gè)字節(jié)(四位)的內(nèi)容顯示出來(lái)就可以了,有了這一編程思想,就很容易看懂上面的子過(guò)程。當(dāng)然你們會(huì)問(wèn),為什么要每次只顯示半個(gè)字節(jié)而不顯示一個(gè)字節(jié)呢?呵呵,十六進(jìn)制的十六個(gè)數(shù)是從0000-1111,不就是半個(gè)字節(jié)了。所以要循環(huán)8次才可以顯示出32位的EAX,所以這里用ror指令來(lái)不斷循環(huán)移位,每次右移4位放到dl的低4位中。這8個(gè)半字節(jié)分別放在[ebp-1]至[ebp-8]的存儲(chǔ)單元中。不過(guò),存儲(chǔ)的順序是由低位到高位,如果就這樣顯示結(jié)果肯定顯示反了。標(biāo)號(hào)hex2,hex3的主要功能是用來(lái)判斷f000:1234雙字單元的內(nèi)容是否為0,如果為0,只需要將最后結(jié)果顯示一個(gè)0即可,否則就顯示出8位內(nèi)容。下面是每條指令的功能:
         b1.countb=8;偽指令定義一局部變量countb,其值為8
         b2.enter countb,0;建立堆棧框架指令
         b3.movzx ebp,bp;對(duì)bp進(jìn)行零擴(kuò)展
         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個(gè)半字節(jié)的內(nèi)容逐一送到[ebp-1]至[ebp-8]的內(nèi)存單元中
         b9.ror edx,4;對(duì)edx進(jìn)行循環(huán)右移,每次移動(dòng)4位
         b10.loop hex1
         b11.mov cx,countb
         b12.xor ebx,ebx;ebx清0
         b13.cmp byte ptr [ebp-countb+ebx],0;下面的語(yǔ)句主要用來(lái)判斷源操作數(shù)f000:1234的內(nèi)容是否為0,如果是0,就在屏幕上只顯示一個(gè)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.子過(guò)程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                                                  
         |---------------------------------------|
         分析:將一個(gè)數(shù)用二進(jìn)制數(shù)顯示出來(lái),只需要用ROL指令就可以了。這里作者寫(xiě)的程序就是這個(gè)思路,在標(biāo)號(hào)bin1中主要判斷f000:1234單元的內(nèi)容是否為0,如果為0,那么只需要在屏幕上顯示一個(gè)0就可以了。否則的話,就用ROL指令對(duì)源操作數(shù)移位32位,從最高位31位到最低位逐一顯示出來(lái),程序設(shè)計(jì)思路很簡(jiǎn)單,沒(méi)有什么復(fù)雜的算法,下面看每一條指令的含義:
         c1.push eax;eax入棧
         c2.push ecx;ecx入棧
         c3.push edx;edx入棧
         c4.bsr edx,eax;對(duì)eax進(jìn)行掃描,并把第一個(gè)為1的位號(hào)送給edx
         c5.jnz bin1;如果eax不為0,就跳到c7去執(zhí)行
         c6.xor dx,dx;如果eax為0,就將dx清0
         c7.mov cl,31;從c7到c12主要用來(lái)設(shè)置計(jì)數(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主要用來(lái)顯示二進(jìn)制數(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ù)的篇幅里將主要介紹保護(hù)式下的段頁(yè)管理機(jī)制及及如何在保護(hù)模下編程。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶(hù) 評(píng)論公約

        類(lèi)似文章 更多