第3章-語言程序設計_第1頁
第3章-語言程序設計_第2頁
第3章-語言程序設計_第3頁
第3章-語言程序設計_第4頁
第3章-語言程序設計_第5頁
已閱讀5頁,還剩174頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第4章

匯編語言程序設計4.1分支程序結構4.2循環程序結構 4.3子程序結構4.4Windows應用程序編程4.5與C++語言的混合編程2教學重點三種結構程序設計①順序結構②分支結構③循環結構

知識點4.1匯編語言的格式4.2語句行的構成4.3指示性語句4.4指令語句4.5匯編語言程序設計及舉例匯編是把匯編語言程序翻譯成機器語言描述的目標程序的過程。匯編程序是完成匯編任務的程序。用匯編語言編寫的程序。2.匯編程序連接程序的主要功能是把多個目標文件及庫文件連接在一起形成可執行文件。3.連接程序

1.匯編語言源程序匯編語言源程序匯編目標程序連接可執行程序從匯編語言源程序到可執行程序的生成過程如圖所示。4.1匯編語言源程序格式下面是一個示范性的完整的匯編語言源程序。;lt301b.asm(文件名)stack segmentstack ;定義堆棧段

dw512dup(?) ;堆棧段有512字(1024字節)空間stack ends ;堆棧段結束data segment ;定義數據段string db’Hello,Everybody!’,0dh,0ah,’$’data endscode segment’code’ ;定義代碼段

assumecs:code,ds:data,ss:stackstart: movax,data ;建立DS段地址

movds,ax movdx,offsetstring movah,9 int21h movax,4c00h int21h ;利用功能調用返回DOScode ends ;代碼段結束

endstart;匯編結束匯編語言源程序格式完整的匯編語言源程序由若干個段組成源程序中段的數目可以根據實際需要而定,但其中必不可少的是代碼段每個段由若干個語句行構成匯編語言源程序格式NAME1SEGMENT

語句語句NAME1ENDSNAME2SEGMENT

語句

語句NAME2ENDSEND<標號>.........匯編語言源程序語句行的格式匯編語言源程序中的每個語句行可以由四項組成,格式如下:若操作數項有多個操作數,則操作數之間使用逗號分隔各部分之間至少用一個空格作為間隔[名字]操作碼[操作數][;注釋]帶方括號的項是可選項名字項名字項是指一個標號、變量、段名或過程名等。操作碼項操作碼項是一個操作碼的助記符,它可以是指令、偽指令或宏指令名。操作數項操作數項提供為執行所要求的操作而需要的信息。操作數項可以是常數、寄存器、標號、變量或由表達式組成。注釋項注釋項用來說明程序或語句的功能。";"為識別注釋項的開始。";"也可以從一行的第一個字符開始,此時整行都是注釋,常用來說明下面一段程序的功能。

在調試程序過程中可適當使用“;”4.2語句行的構成4.2.1標記1、IBM宏匯編的字符集(1)字母大寫字母小寫字母(2)數字0、1……9(3)特殊字符圖4-12、界符圖4-2語句中有了界符,可以不用分隔符。3、常量常量是指匯編時已經有確定數值的量它又分成多種形式:(1)十進制常量(2)十六進制常量(3)二進制常量(4)八進制常量(5)字符串常量用單引號或雙引號括起來的單個字符或多個字符,其數值是每個字符對應的ASCII碼的值例如:'d''AB''Hello,Everybody!'字符串常量標識符(Identifier)一般最多由31個字母、數字及規定的特殊符號(如_、$、?、@)組成,不能以數字開頭。一個程序中,每個標識符的定義是唯一的,還不能是匯編語言采用的保留字4、標識符由程序員自由建立的、有特定意義的字符序列。5、保留字保留字(ReservedWord)是匯編程序已經利用的標識符,主要有:指令語句助記符——例如:MOV、ADD偽指令語句助記符——例如:DB、EQU操作符——例如:OFFSET、PTR寄存器名——例如:AX、CS第3章IBM宏匯編中的保留字見P86表4-16、注釋以“;”打頭。4.2.2符號1、寄存器一種標識符,要符合標識符的組成規則。2、變量存放在存儲單元中的操作數是變量。在程序中出現的是存儲單元地址的符號。變量名變量名是數據存儲單元偏移地址的符號表示命名規則:

遵守標識符的命名規則變量的屬性變量具有以下三種屬性:①段值名字對應存儲單元的段地址②偏移值名字對應存儲單元的偏移地址③類型變量名的類型可以是BYTE(字節)、WORD(字)和DWORD(雙字)等變量的定義變量一般在除代碼段以外的其他段定義。變量需定義才能被引用變量用數據定義語句DB、DD等定義3、標號標號是指令存儲單元偏移地址的符號表示命名規則:

遵守標識符的命名規則標號的屬性標號具有以下三種屬性:①段值標號對應存儲單元的段地址②偏移值標號對應存儲單元的偏移地址③類型標號類型可以是NEAR(近)和FAR(遠),分別表示段內或段間標號的定義和引用標號在代碼段定義和引用LOOP1:MOVAL,[SI]...JMPLOOP1標號定義標號引用變量和標號的區別不同:標號對應的存儲單元中存放的是指令,后面跟冒號;變量對應的存儲單元中存放的是數據,后面不跟冒號。相同:都是存儲單元的符號地址。4、數利用一個標識符表達的一個數值常數若使用有意義的符號名來表示,可以提高程序的可讀性,同時更具有通用性符號常量實例符號定義

DosWriteChar=2 CarriageReturn=13符號應用(右邊程序段等價左側的符號形式)

movah,DosWriteChar;movah,2 movdl,CarriageReturn;movdl,135、其他符號指示性語句(偽指令)的操作碼、宏指令等

匯編語言大小寫不敏感4.2.3表達式后面介紹4.2.4語句匯編語言源程序中的語句有兩種:指令語句和指示性語句(偽指令)。指令語句——使CPU產生動作、并在程序執行時才處理的語句,就是第3章學習的指令偽指令(Directive)——不產生CPU動作、在程序執行前由匯編程序處理的說明性語句,例如,數據說明、變量定義等等兩種語句的格式標號:

指令語句助記符操作數,操作數;注釋名字偽指令助記符參數,參數,…

;注釋指令語句格式:偽指令格式:兩種語句在格式上的主要區別4.3指示性語句(偽指令語句)符號定義語句數據定義語句段定義語句過程定義語句結束語句4.3.1符號定義語句EQU=PURGE1、等值語句EQU語句格式:符號名EQU表達式功能:給符號名定義一個值,或定義為別的符號名,甚至可以定義為一條可執行的指令。如:ABCEQU220XYZEQUABCCOUNTEQUCXCBDEQUADDEQU語句在未解除之前,不能重新定義。如:ABCEQU220ABCEQU330錯誤!2、解除語句PURGE功能:用來解除已用EQU語句定義的符號,解除后的符號可以重新定義。如:PURGEABCABCEQU330PURGE的格式為:PURGE符號1,符號2,...,符號n3、等號語句=語句格式:符號名=表達式功能:與EQU語句類似,但是能對符號進行重新定義。如:EMP=6EMP=7EMP=EMP+14.3.2數據定義語句格式:[變量名]偽操作符操作數1,操作數2,...[;注釋]功能:定義一個變量的類型,給存儲器賦初值,或者僅僅給變量分配存儲單元,而不賦予特定的值。變量名可以沒有。這種情況,匯編程序將直接為操作數分配空間,無符號地址。設置變量名是為了方便存取它指示的存儲單元匯編程序將把所定義的數據按先后次序連續分配存儲空間,所起的名字也只代表第一個字節單元的偏移地址。常用偽操作符DB(DefineByte)定義字節DW(DefineWord)定義字DD(DefineDoubleWord)定義雙字DQ(DefineQuadword)定義四個字DT(DefineTenbyte)定義十個字節操作數可以是常數、表達式、字符串或重復操作符DUP,不能是寄存器名.例1DATASEGMENTDATA_BYTEDB10,4,10H,?DATA_WORDDW100,100H,-5DATA_DWDD3*20,0FFFDHDATA_ASCDB‘AB’DATA_WORD1DW‘AB’DATAENDS說明:(1)操作數?,不放入任何數,僅保留存儲空間.(2)操作數在內存中所占的字節數與偽操作符所定義的字節數一致.(3)操作數在匯編后以補碼形式存放.(4)只有用DB定義時,才允許字符串的長度超過2個字節。DATA_BYTE0AH04H10H---64HDATA_WORD00H00H01HFBHFFHDATA_DW3CH00H00H00HFDH00HFFH00HDATA_ASC41H42H42H0000H0001H0002H0013H000AH0003H0004H0005H0006H0007H0008H0009H000BH000CH000DH000EH000FH0010H0011H0012H0014H41H0015HDATA_WORD1例2DATASEGMENTADWMBUFDWBUF-A

EMPEQU220

MDB2DUP(1),2DUP(2,2DUP(1,2))DDDBUFDATAENDS說明:(1)操作數為變量時,則存放其地址。若用DW定義,則存放其偏移地址;若用DD定義,則存放其偏移地址和段地址,第一個字為偏移地址,第二個字為段地址.(2)重復操作符DUP可以嵌套.重復操作符DUP的格式:nDUP(初值[,初值…])括號中為重復的內容,n為重復的次數。A04H00H02H00H01HBUF01H02H01H02H01HM02H02H00HDATA低8位0000H0001H0002H0013H000AH0003H0004H0005HDDATA高8位0006H0007H0008H0009H000BH000CH000DH000EH000FH0010H0011H0012H01H02H01H02H02H用DW或DD偽操作可以把變量或標號的偏移地址(DW)或偏移地址和段地址(DD)存入存儲器。用DD偽操作存入地址時,第一個字為偏移地址,第二個字為段地址。定位偽指令ORG語句格式:ORG常數表達式功能:使下一個字節地址為成為常數表達式的值。如:DSEGSEGMENTORG10VECT1DW47A5HORG20VECT2DW0C596HDSEGENDS說明:變量VECT1的偏移地址為10,即0AH,VECT2的偏移地址為20,即14H.4.3.3段定義語句語句格式:

段名SEGMENT...段名ENDS功能:定義了一個以SEGMENT偽指令開始,以ENDS偽指令結束,以段名命名的存儲段。假定偽指令語句格式:

ASSUME段寄存器名:段名,段寄存器名:段名,...其中,段寄存器名必須是CS,DS,ES,SS中的一個,而段名必須是由SEGMENT定義的段中的段名。功能:設定段寄存器與段之間的關系。ASSUME語句寫在代碼段的一開始ASSUME語句只是指定某個段由哪一個段寄存器尋址,它并不能把段地址裝入段寄存器中,所以在代碼段的開始,還必須把段地址裝入相應的段寄存器中。可以用MOV指令實現。但是代碼段不須這樣做。DATASEGMENTDATAENDSEXTRASEGMENTEXTRAENDSSTACKSEGMETSTACKENDS

............CODESEGMENTASSUMECS:CODE,DS:DATA,ES:EXTRA,SS:STACK...START:MOVAX,DATAMOVDS,AXMOVAX,EXTRAMOVES,AXMOVAX,STACK

MOVSS,AXCODEENDSENDSTART......段名也就是段地址4.3.4過程定義語句過程又稱為子程序,是完成特定功能的一段程序(1)過程定義偽操作功能:定義了一個以PROC偽指令開始,以ENDP偽指令結束,以過程名命名的過程。格式:過程名procfar/near...過程名endp過程名過程名是子程序入口的符號地址(規定與標號相同,但后面不跟冒號)。(2)調用程序與子程序不在同一個代碼段中,用far屬性-----NEAR,FAR(1)若調用程序與子程序在同一個代碼段中,用near注意:過程中若不沒有注明屬性,則匯編程序將它默認為NEAR。(2)過程的調用與返回以后介紹。4.3.5結束語句功能:標志著整個源程序的結束,它告訴匯編程序,沒有更多的指令要匯編了。語句格式:END<程序第一條指令的標號>結束程序,返回DOS的方法一分為三個步驟(1)將程序開始啟動運行的過程定義為一個FAR過程.(2)在代碼段的開始處安放以下三條指令,為程序結束運行,正確返回DOS做好準備:

PUSHDSMOVAX,0PUSHAX(3)在程序結束返回DOS處安放一條RET指令結束程序,返回DOS的方法二調用DOS的4CH系統功能返回的方法在程序結束后插入以下語句:MOVAH,4CHINT21H4.4指令語句留給大家自己看。4.5匯編語言程序設計及舉例4.5.1直線程序設計例1計算(V-(X*Y+Z-540))/X其中X、Y、Z、V均為16位帶符號數,已分別裝入X、Y、Z、V單元中,要求計算結果的商存入R單元,余數存入W單元。59DATASEGMENXDW1234HRDW?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATABEGIN:MOVAX,DATAMOVDS,AxYDW3456HZDW5678HVDW7834HWDW?60MOVAX,X;被乘數存入AXIMULY;X*YMOVCX,AX;乘積的低位字存入CXMOVBX,DX;乘積的高位字存入BXMOVAX,Z;加數Z存入AXCWD;把Z擴展成雙字ADDCX,AX;乘積的低位字與Z的低位字相加ADCBX,DX;乘積與Z的高位字和低位的進位相加SUBCX,540;(X*Y+Z)的低位字減去540SBBBX,0;(X*Y+Z)的高位字減去低位的借位61MOVAX,V;被減數V存入AXCWD;把V擴展成雙字SUBAX,CX;V的低位字與(X*Y+Z-540)的低位字相減SBBDX,BX;V的高位字與(X*Y+Z-540)的高位字相減IDIVX;(V-(X*Y+Z-540))/XMOVR,AXMOVW,DXMOVAH,4CHINT21HCODEENDSENDBEGIN4.1分支程序結構改變程序執行順序、形成分支、循環、調用等程序結構是很常見的程序設計問題高級語言采用IF等語句表達條件,并根據條件是否成立轉向不同的程序分支匯編語言需要首先利用比較CMP、測試TEST、加減運算、邏輯運算等影響狀態標志的指令形成條件然后利用條件轉移指令判斷由標志表達的條件,并根據標志狀態控制程序轉移到不同的程序段4.1.1無條件轉移指令程序代碼在代碼段CS:指明代碼段在主存中的段基地址EIP:給出將要執行指令的偏移地址程序順序執行,處理器自動增量EIP程序控制轉移,EIP隨之改變程序轉移到另外的代碼段,EIP和CS都改變控制轉移類指令:改變EIP(有些也改變CS),即改變程序執行順序(實現程序控制轉移)的指令本章學習控制轉移類指令1.轉移范圍段內轉移在當前代碼段范圍內的程序轉移不需更改CS,只要改變EIP(偏移地址)近轉移(Near):32位近轉移NEAR32,16位近轉移NEAR16短轉移(Short):轉移范圍在127~-128字節段間轉移從當前代碼段跳轉到另一個代碼段需要更改CS(段地址)和EIP(偏移地址)遠轉移(Far):48位遠轉移FAR32,32位遠轉移FAR162.指令尋址方式相對尋址方式提供目標地址相對于當前指令指針EIP的位移量目標地址(轉移后的EIP)=當前EIP+位移量相對尋址都是段內轉移,最常用、最靈活直接尋址方式直接提供目標地址目標地址(轉移后的CS和EIP)=指令操作數間接尋址方式指示寄存器或存儲單元目標地址來自寄存器或存儲單元、間接獲得寄存器間接尋址:用寄存器保存目標地址存儲器間接尋址:用存儲單元保存目標地址目標地址=目的地址=轉移地址3.JMP指令無條件轉移:程序無條件改變執行順序JMP指令相當于高級語言的goto語句

JMPlabel ;程序轉向label標號指定的地址

;段內相對尋址,段間直接尋址

JMPreg32/reg16 ;程序轉向寄存器指定的地址

;寄存器間接尋址

JMPmem32/mem16 ;程序轉向存儲單元指定的地址

;存儲器間接尋址JMP指令的4種類型1.段內轉移、相對尋址標號指明目標地址,指令代碼包含位移量2.段內轉移、間接尋址通用寄存器或主存單元包含目標指令偏移地址3.段間轉移、直接尋址標號包含目標指令的段地址和偏移地址4.段間轉移、間接尋址32位段用3字存儲單元包含目標地址16位段用雙字存儲單元包含目標地址MASM會根據存儲模式等信息自動識別〔例4-1〕無條件轉移程序-1

;數據段00000000 00000000nvar dword?

;代碼段00000000 EB01 jmplabl1 ;相對尋址00000002 90

nop00000003 E900000001labl1: jmpnearptrlabl2 ;相對近轉移00000008 90

nop00000009 B800000011Rlabl2: moveax,offsetlabl3

〔例4-1〕無條件轉移程序-20000000E FFE0

jmpeax ;寄存器間接尋址00000010 90

nop00000011 B800000022Rlabl3: moveax,offsetlabl400000016 A300000000R

movnvar,eax0000001B FF2500000000R

jmpnvar ;存儲器間接尋址00000021 90

noplabl4:

movebx,offsetnvarjmpnearptr[ebx];數據的寄存器間接尋址數據的存儲器直接尋址4.1.2條件轉移指令根據指定的條件確定程序是否發生轉移

Jcclabel ;條件滿足,發生轉移;否則,順序執行下條指令LABEL表示目標地址,采用段內相對尋址32位IA-32處理器:達到32位的全偏移量16位80x86處理器:-128~+127間的短轉移條件轉移指令不影響標志,但要利用標志cc表示利用標志判斷的條件,16種、兩類單個標志狀態作為條件兩數大小關系作為條件轉移條件cc:單個標志狀態JZ/JE

ZF=1 JumpifZero/EqualJNZ/JNE

ZF=0 JumpifNotZero/NotEqualJS

SF=1 JumpifSignJNS

SF=0 JumpifNotSignJP/JPE

PF=1 JumpifParity/ParityEvenJNP/JPO

PF=0 JumpifNotParity/ParityOddJO

OF=1 JumpifOverflowJNO

OF=0 JumpifNotOverflowJC

CF=1 JumpifCarryJNC

CF=0 JumpifNotCarry多個助記符方便記憶轉移條件cc:兩數大小關系JB/JNAE

CF=1 JumpifBelow/NotAboveorEqualJNB/JAE

CF=0 JumpifNotBelow/AboveorEqualJBE/JNA

CF=1或ZF=1 JumpifBelow/NotAboveJNBE/JA

CF=0且ZF=0 JumpifNotBeloworEqual/AboveJL/JNGE

SF≠OF JumpifLess/NotGreaterorEqualJNL/JGE

SF=OF JumpifNotLess/GreaterorEqualJLE/JNG

ZF≠OF或ZF=1 JumpifLessorEqual/NotGreaterJNLE/JG

SF=OF且ZF=0 JumpifNotLessorEqual/Greater1.單個標志狀態作為條件的條件轉移指令JZ(JE)和JNZ(JNE):利用零位標志ZF判斷結果是零(相等)還是非零(不等)JS和JNS:利用符號標志SF判斷結果是負還是正JO和JNO:利用溢出標志OF判斷結果是溢出還是沒有溢出JP(JPE)和JNP(JPO):利用奇偶標志PF判斷結果低字節“1”的個數是偶數還是奇數JC和JNC:利用進位標志CF判斷結果是有進位(為1)還是無進位(為0)〔例4-2〕個數折半程序-1

moveax,885 ;假設一個數據

shreax,1 ;數據右移進行折半

jncgoeven ;余數為0,即CF=0條件成立,轉移

addeax,1 ;否則余數為1,即CF=1,進行加1操作goeven: calldispuid ;顯示結果

443運行結果〔例4-2〕個數折半程序-2

moveax,886 ;假設一個數據

shreax,1 ;數據右移進行折半

jcgoodd ;余數為1,即CF=1條件成立,轉移到分支體,進行加1操作

jmpgoeven ;余數為0,即CF=0,不需要處理,轉移到顯示!goodd: addeax,1 ;進行加1操作goeven: calldispuid ;顯示結果jncgoeven何不合二為一?〔例4-2〕個數折半程序-3

moveax,887 ;假設一個數據

shreax,1 ;數據右移進行折半

adceax,0 ;余數=CF=1,進行加1操作 ;余數=CF=0,沒有加1

calldispuid ;顯示結果

moveax,888 ;假設一個數據

addeax,1 ;個數加1

rcreax,1 ;數據右移進行折半

calldispuid ;顯示結果改進算法消除分支〔例4-3〕位測試程序—說明例如:進行打印前,要測試打印機狀態。假設測試數據已經進入了EAX,其中D1位為0表示打印機沒有處于聯機打印的正常狀態,D1 位為1表示可以進行打印。編程測試EAX,若D1=0,顯示“NoReady!”,若D1=1,顯示“ReadytoGo!”〔例4-3〕位測試程序-1

;數據段no_msg byte'NotReady!',0yes_msg byte'ReadytoGo!',0 ;代碼段

moveax,56h ;假設一個數據

testeax,02h ;測試D1位(D1=1,其他位為0)

jznom ;D1=0條件成立,轉移

moveax,offsetyes_msg ;D1=1,顯示準備好

jmpdone ;跳轉過另一個分支體!nom: moveax,offsetno_msg ;顯示沒有準備好done: calldispmsg〔例4-3〕位測試程序-2

;數據段no_msg byte'NotReady!',0yes_msg byte'ReadytoGo!',0 ;代碼段

moveax,56h ;假設一個數據

testeax,02h ;測試D1位(D1=1,其他位為0)

jnzyesm ;D1=1條件成立,轉移

moveax,offsetno_msg ;D1=0,顯示沒有準備好

jmpdone ;跳轉過另一個分支體!yesm: moveax,offsetyes_msg ;顯示準備好done: calldispmsg〔例4-4〕奇校驗程序---說明數據通信時,為了可靠常要進行校驗。最常用的方法就是奇偶校驗。如果使包含校驗位在內的數據中“1”的個數恒為奇數,就是奇校驗;恒為偶數,就為偶校驗。題目要求:編程從鍵盤輸入一個字符,編程為其最高位加上奇校驗。〔例4-4〕奇校驗程序

callreadc ;鍵盤輸入,AL=返回值

calldispcrlf ;回車換行(用于分隔)

calldispbb ;以二進制形式顯示數據

calldispcrlf ;回車換行(用于分隔)

andal,7fh ;最高位置“0”、其他位不變

;同時標志PF反映“1”的個數

jnpnext ;個數為奇數,不需處理,轉移

oral,80h ;個數為偶數,最高位置“1”、其他位不變next: calldispbb ;顯示含校驗位的數據2.兩數大小關系作為條件的條件轉移指令無符號數用高(Above)、低(Below)低于(不高于等于):JB(JNAE)不低于(高于等于):JNB(JAE)低于等于(不高于):JBE(JNA)不低于等于(高于):JNBE(JA)有符號數用大(Greater)、小(Less)小于(不大于等于):JL(JNGE)不小于(大于等于):JNL(JGE)小于等于(不大于):JLE(JNG)不小于等于(大于):JNLE(JG)〔例4-5〕數據比較程序-1

;數據段in_msg1 byte'Enteranumber:',0in_msg2 byte'Enteranothernumber:',0out_msg1 byte'Twonumbersareequal:',0out_msg2 byte'Thelessnumberis:',0out_msg3 byte13,10,'Thegreaternumberis:',0

;代碼段

moveax,offsetin_msg1 ;提示輸入

calldispmsg callreadsid ;輸入第一個數據

movebx,eax ;保存到EBX

moveax,offsetin_msg2 ;提示輸入

calldispmsg callreadsid ;輸入第二個數據

movecx,eax ;保存到ECX〔例4-5〕數據比較程序-2

cmpebx,ecx ;二個數據進行比較

jnenequal ;兩數不相等,轉移

moveax,offsetout_msg1

calldispmsg ;顯示兩數相等

moveax,ebx calldispsid ;顯示相等的數據

jmpdone ;轉移到結束nequal: jlfirst ;EBX較小,不需要交換,轉移

xchgebx,ecx ;EBX保存較小數,ECX保存較大數〔例4-5〕數據比較程序-3first: moveax,offsetout_msg2 ;顯示較小數

calldispmsg moveax,ebx ;較小數在EBX中

calldispsid moveax,offsetout_msg3 ;顯示較大數

calldispmsg

moveax,ecx ;較大數在ECX中

calldispsiddone:4.1.3單分支結構只有一個分支的程序類似高級語言的IF-THEN語句結構注意采用正確的條件轉移指令當條件滿足(成立),發生轉移,跳過分支體條件不滿足,順序向下執行分支體條件轉移指令與高級語言的IF語句正好相反IF語句是條件成立,執行分支體〔例4-6〕求絕對值程序

;代碼段

callreadsid ;輸入一個有符號數,從EAX返回值

cmpeax,0 ;比較EAX與0

jgenonneg ;條件滿足:AX≥0,轉移

negeax ;條件不滿足:AX<0,為負數

;需求補得正值nonneg: calldispuid ;分支結束,顯示結果示意圖單分支結構的流程圖返回〔例4-7〕字母判斷程序

callreadc ;輸入一個字符,從AL返回值

cmpal,'A’ ;與大寫字母A比較

jbdone ;比大寫字母A小,不是大寫字母,轉移

cmpal,'Z’ ;與大寫字母Z比較

jadone ;比大寫字母Z大,不是大寫字母,轉移

oral,20h ;轉換為小寫

calldispcrlf ;回車換行

calldispc ;顯示小寫字母done:

4.1.4雙分支結構雙分支程序結構有兩個分支,條件為真執行一個分支;條件為假,執行另一個分支相當于高級語言的IF-THEN-ELSE語句順序執行的分支體1最后一定要有一條JMP指令跳過分支體2JMP指令必不可少,實現結束前一個分支回到共同的出口作用雙分支結構有時可以改變為單分支結構事先執行其中一個分支(選擇出現概率較高的分支)〔例4-8〕顯示數據最高位程序-1

;數據段dvar dword0bd630422h ;假設一個數據

;代碼段

movebx,dvar shlebx,1 ;EBX最高位移入CF標志

jcone ;CF=1,即最高位為1,轉移

moval,'0' ;CF=0,即最高位為0:AL←'0'

jmptwo ;一定要跳過另一個分支one: moval,'1' ;AL←'1'two: calldispc ;顯示

示意圖雙分支結構雙分支結構的流程圖返回〔例4-8〕顯示數據最高位程序-2

movebx,dvar moval,'0' ;假設最高位為0:AL←'0'

shlebx,1 ;EBX最高位移入CF標志

jnctwo ;CF=0,即最高位為0,轉移

moval,'1' ;CF=1,即最高位為1,AL←'1'two: calldispc ;顯示單分支結構〔例4-9〕有符號數運算溢出程序

;數據段dvar1 dword1234567890 ;假設兩個數據dvar2 dword-999999999dvar3 dword?okmsg byte'Correct!',0 ;正確信息errmsg byte'ERROR!Overflow!',0 ;錯誤信息

;代碼段

moveax,dvar1 subeax,dvar2 ;求差

joerror ;有溢出,轉移

movdvar3,eax ;無溢出,保存差值

moveax,offsetokmsg ;顯示正確

jmpdisperror: moveax,offseterrmsg ;顯示錯誤disp: calldispmsg

4.2循環程序結構三個部分組成:循環初始——為開始循環準備必要的條件,如循環次數、循環體需要的初始值等;循環體——重復執行的程序代碼,其中包括對循環條件的修改等;循環控制——判斷循環條件是否成立,決定是否繼續循環“先判斷、后循環”的循環程序結構對應高級語言的WHILE語句“先循環、后判斷”的循環程序結構對應高級語言的DO語句示意圖循環程序結構的流程圖返回4.2.1循環指令

LOOPlabel;ECX←ECX-1;若ECX≠0,循環到LABEL;否則,順序執行

JECXZlabel;ECX=0,轉移;否則順序執行目標地址采用相對短轉移實地址存儲模型使用CX作為計數器DECECXJNZlabelCMPECX,0JZlabel〔例4-10〕數組求和程序;數據段Arraydword136,-138,133,130,-161Sumdword?〔例4-10〕數組求和程序

movecx,lengthofarray ;ECX=數組元素個數

xoreax,eax ;求和初值為0

movebx,eax ;數組指針為0again: addeax,array[ebx*(typearray)] ;求和

incebx ;指向下一個數組元素

loopagain movsum,eax ;保存結果

calldispsid ;顯示結果循環體循環控制循環初始4.2.2計數控制循環通過次數控制循環利用LOOP指令屬于計數控制常見是“先循環、后判斷”循環結構計數可以減量進行,即減到0結束計數可以增量進行,即達到規定值結束循環程序結構的關鍵是如何控制循環〔例4-11〕簡單加密解密程序-1

;數據段key byte234bufnum =255buffer bytebufnum+1dup(0) ;定義鍵盤輸入需要的緩沖區msg1 byte'Entermessage:',0msg2 byte'Encryptedmessage:',0msg3 byte13,10,'Originalmessage:',0 ;代碼段

moveax,offsetmsg1 ;提示輸入字符串

calldispmsg moveax,offsetbuffer ;設置入口參數EAX

callreadmsg ;調用輸入字符串子程序

pusheax ;字符個數保存進入堆棧〔例4-11〕簡單加密解密程序-2

movecx,eax ;ECX=實際輸入的字符個數,作為循環的次數

xorebx,ebx ;EBX指向輸入字符

moval,key ;AL=加密關鍵字encrypt: xorbuffer[ebx],al ;異或加密

incebx dececx ;等同于指令:loopencrypt

jnzencrypt ;處理下一個字符

moveax,offsetmsg2 calldispmsg moveax,offsetbuffer ;顯示密文

calldispmsg〔例4-11〕簡單加密解密程序-3

popecx ;從堆棧彈出字符個數,作為循環的次數

xorebx,ebx ;EBX指向輸入字符

moval,key ;AL=解密關鍵字decrypt: xorbuffer[ebx],al ;異或解密

incebx dececx jnzdecrypt ;處理下一個字符

moveax,offsetmsg3 calldispmsg moveax,offsetbuffer ;顯示明文

calldispmsg示意圖簡單加密解密程序運行實例返回4.2.3條件控制循環根據條件決定是否進行循環需要使用有條件轉移指令實現多見“先判斷、后循環”結構先行判斷的條件控制循環程序很像雙分支結構主要分支需要重復執行多次(JMP的目標位置是循環開始)另一個分支用于跳出這個循環先行循環的條件控制循環程序類似單分支結構,循環體就是分支體順序執行就跳出循環〔例4-12〕字符個數統計程序題目說明:已知某個字符串以0結尾,統計其包含的字符個數,即計算字符串的長度。〔例4-12〕字符個數統計程序 ;數據段string byte‘DoyouhavefunwithAssembly?’,0 ;以0結尾的字符串 ;代碼段

xorebx,ebx ;EBX用于記錄字符個數,也用于指向字符的指針again: moval,string[ebx] cmpal,0 ;用指令“testal,al”也可

jzdone incebx ;個數加1

jmpagain ;繼續循環done: moveax,ebx ;顯示個數

calldispuid〔例4-13〕字符剔除程序題目說明現有一個以0結尾的字符串,要求剔除其中的空格字符。處理方法:

1、用結尾標志0作為循環控制條件

2、循環體判斷每個字符,如果不是空格,不予處理繼續循環;如果是空格,則進行剔除,也就是將后續所有字符逐個前移一個字符位置,將空格覆蓋。這是一個雙重循環的程序結構。〔例4-13〕字符剔除程序-1Stringbyte‘Letushaveatry!’0dh,0ah,0’moveax,offsetstring ;顯示處理前字符串

calldispmsg movesi,offsetstringoutlp: cmpbyteptr[esi],0 ;外循環,先判斷后循環

jzdone ;為0結束again: cmpbyteptr[esi],'';是否是空格

jnznext ;不是空格繼續循環

movedi,esi ;是空格,剔除空格分支inlp: incedi ;該分支是循環程序

moval,[edi] ;前移一個位置

mov[edi-1],al〔例4-13〕字符剔除程序-2

cmpbyteptr[edi],0

;內循環,先循環后判斷

jnzinlp ;內循環結束處

jmpagain ;再次判斷是否為空格(處理連續空格)next: incesi ;繼續對后續字符進行判斷處理

jmpoutlp ;外循環結束處done: moveax,offsetstring ;顯示處理后字符串

calldispmsg4.3子程序結構經常用到的應用問題編寫成一個通用子程序大型處理過程分解成能夠解決的模塊使用子程序可以使程序的結構更為清楚程序的維護更為方便有利于大程序開發時的多個程序員分工合作子程序(Subroutine)=函數(Function)=過程(Procedure)4.3.1子程序指令子程序:與主程序分開的、完成特定功能的一段程序當主程序(調用程序)執行調用指令CALL調用子程序子程序(被調用程序)執行返回指令RET返回主程序CALLlabel主程序RET子程序回到CALL指令后的指令處1.子程序調用指令CALLCALL指令用在主程序中,實現子程序的調用分成段內調用(近調用)和段間調用(遠調用)目標地址采用相對尋址、直接尋址或間接尋址入棧返回地址:將CALL下條指令的地址壓入堆棧

CALLlabel ;調用標號指定的子程序

CALLreg16/reg32

;調用寄存器指定地址的子程序

CALLmem16/mem32 ;調用存儲單元指定地址的子程序2.子程序返回指令RETRET指令用在子程序結束,實現返回主程序

RET

;無參數返回:出棧返回地址

RETi16 ;有參數返回:出棧返回地址

;ESP←ESP+i16MASM會根據存儲模型等信息確定子程序的遠近調用,并相應產生返回指令3.過程定義偽指令MASM利用過程定義偽指令獲得子程序信息

過程名 PROC

…… ;過程體

過程名 ENDP

;過程名為符合語法的標識符PROC后面可加參數:NEAR或FAR簡化段定義源程序格式中,通常不需指定〔例4-14〕子程序調用程序-1

;代碼段,主程序00000000 B800000001 moveax,100000005 BD00000005 movebp,50000000A E800000016

callsubp ;子程序調用0000000F B900000003

retp1: movecx,300000014 BA00000004retp2: movedx,400000019 E800000000E

calldisprd〔例4-14〕子程序調用程序-2 ;子程序subp proc ;過程定義,過程名為subp

pushebp movebp,esp movesi,[ebp+4] ;ESI=CALL下條指令(標號RETP1)偏移地址

movedi,offsetretp2 ;EDI=標號RETP2的偏移地址

movebx,2 popebp ;彈出堆棧,保持堆棧平衡

ret ;子程序返回subp endp ;過程結束MOV[EBP+4],EDI?示意圖子程序調用的堆棧返回4.3.2子程序設計子程序的編寫方法與主程序一樣但需要留意幾個問題:利用過程定義,獲得子程序名和調用屬性RET指令返回主程序,CALL指令調用子程序壓入和彈出操作要成對使用,保持堆棧平衡開始保護寄存器,返回前相應恢復安排在代碼段的主程序之外子程序允許嵌套和遞歸最好有完整的注釋難點是參數傳遞〔例4-15〕十六進制顯示程序題目說明將每個16進制數位轉換為ASCII碼。4位2進制數對應一位16進制數,具有16個數碼:0-9,A-F。依次對應的ASCII碼是30H-39H,41H-46H。所以,16進制數0-9只要加30H就可以轉換成ASCII碼,而對A-F需要再加7。HTOASC:主程序通過AL的低4位將要轉換的16進制數位傳遞給子程序,子程序轉換后的ASCII碼通過AL反饋給主程序。〔例4-15〕十六進制顯示程序-1.dataregd byte'EAX=',8dup(0),'H',0.code

moveax,1234abcdh ;假設一個數據

xorebx,ebx movecx,8 ;8位十六進制數again: roleax,4 ;高4位循環移位進入低4位

pusheax callhtoasc ;調用子程序

movregd+4[ebx],al ;保存轉換后的ASCII碼

popeax incebx dececx jnzagain moveax,offsetregd calldispmsg ;顯示regdbyte'EAX=',8dup(0),'H',0〔例4-15〕十六進制顯示程序-2

;子程序htoasc proc;將AL低4位表達的一位十六進制數轉換為ASCII碼

andal,0fh ;只取AL的低4位

oral,30h ;AL高4位變成3

cmpal,39h ;是0~9,還是A~F

jbehtoend addal,7 ;是A~F,ASCII碼再加上7htoend: ret ;子程序返回htoasc endp〔例4-15〕十六進制顯示程序-3

;子程序htoasc proc andeax,0fh ;取AL低4位

moval,ASCII[eax];換碼

ret ;子程序的局部數據(只讀)ASCII byte'0123456789ABCDEF'htoasc endpEAX=1234ABCDH運行結果4.3.3參數傳遞主程序與子程序間通過參數傳遞建立聯系入口參數(輸入參數):主程序→子程序出口參數(輸出參數):子程序→主程序傳遞參數的多少反映程序模塊間的耦合程度參數的具體內容數據本身(傳遞數值)數據的存儲地址(傳遞地址,傳遞引用)參數傳遞方法寄存器變量堆棧1.寄存器傳遞參數最簡單和常用的參數傳遞方法把參數存于約定的寄存器少量數據直接傳遞數值大量數據只能傳遞地址帶有出口參數的寄存器不能保護和恢復帶有入口參數的寄存器可以保護、也可以不保護,但最好能夠保持一致〔例4-16〕有符號十進制數顯示程序-1轉換的算法如下:(1)首先判斷數據是零、正數或負數,是零顯示“0”退出(2)是負數,顯示負號“-”,求數據的絕對值(3)接著數據除以10,余數為十進制數碼,加30H轉換為ASCII碼保存(4)重復(3)步,直到商為0結束(5)依次從高位開始顯示各位數字〔例4-16〕有符號十進制數顯示程序-2

;數據段array dword1234567890,-1234,0,1,...writebuf byte12dup(0) ;顯示緩沖區

;代碼段

movecx,lengthofarray movebx,0again: moveax,array[ebx*4] ;EAX=入口參數

callwrite ;調用子程序,顯示一個數據

calldispcrlf ;換行以便顯示下一個數據

incebx dececx jnzagain寄存器傳遞參數〔例4-16〕有符號十進制數顯示程序-3 ;顯示有符號十進制數的子程序write proc ;EAX=入口參數

pushebx ;保護寄存器

pushecx pushedx movebx,offsetwritebuf;EBX指向顯示緩沖區

testeax,eax ;判斷數據是零、正數或負數

jnzwrite1 ;不是零,跳轉

movbyteptr[ebx],'0' ;是零,設置“0”

incebx jmpwrite5 ;轉向顯示write1: jnswrite2 ;是正數,跳轉

movbyteptr[ebx],'-';是負數,設置負號

incebx negeax ;數據求補(絕對值)寄存器傳遞參數〔例4-16〕有符號十進制數顯示程序-4write2: movecx,10 pushecx ;10壓入堆棧,作為退出標志write3: cmpeax,0 ;數據(商)為零,轉向保存

jzwrite4 xoredx,edx ;零位擴展被除數為EDX.EAX

divecx ;數據除以10:EDX.EAX÷10

addedx,30h ;余數(0~9)轉換為ASCII碼

pushedx ;數據先低位后高位壓入堆棧

jmpwrite3〔例4-16〕有符號十進制數顯示程序-5write4: popedx ;數據先高位后低位彈出堆棧

cmpedx,ecx ;是結束標志10,轉向顯示

jewrite5 mov[ebx],dl ;數據保存到緩沖區

incebx jmpwrite4write5: movbyteptr[ebx],0 ;顯示內容加上結尾標志

moveax,offsetwritebuf calldispmsg

popedx ;恢復寄存器

popecx popebx ret ;子程序返回write endp2.共享變量傳遞參數子程序和主程序使用同一個變量名存取數據如果變量定義和使用不在同一個程序模塊中,需要利用PUBLIC、EXTREN聲明共享變量傳遞參數,子程序的通用性較差特別適合在多個程序段間、尤其在不同的程序模塊間傳遞數據〔例4-17〕有符號十進制數輸入程序-1十進制有符號整數轉換為補碼的算法如下:(1)判斷輸入了正數、還是負數,用一個寄存器記錄(2)判斷下一個字符是否為有效數碼 字符無效,提示錯誤重新輸入,并轉向(1) 字符有效,繼續(3)字符有效,減30H轉換為二進制數;然后將前面輸入的數值乘10,并與剛輸入的數字相加得到新的數值(4)判斷輸入的數據是否超出有效范圍超出范圍,提示錯誤重新輸入,并轉向(1)沒有超出范圍,則繼續(5)重復(2)~(4)步,輸入字符都有效,一直處理完(6)是負數進行求補,轉換成補碼;否則直接將數值保存〔例4-17〕有符號十進制數輸入程序-2

;數據段count =10array dwordcountdup(0)temp dword?readbuf byte30dup(0) ;代碼段

movecx,count movebx,offsetarrayagain: callread ;調用子程序,輸入一個數據

moveax,temp ;獲得出口參數

mov[ebx],eax ;存放到數據緩沖區

addebx,4 dececx jnzagain共享變量傳遞參數〔例4-17〕有符號十進制數輸入程序-3 ;輸入有符號十進制數的子程序read proc ;出口參數:變量TEMP=補碼表示的二進制數值

pusheax ;說明:負數用“-”引導

pushebx

pushecx pushedxread0: moveax,offsetreadbuf

callreadmsg ;輸入一個字符串

testeax,eax jzreaderr ;沒有輸入數據,錯誤

cmpeax,12 jareaderr ;輸入超過12個字符,錯誤〔例4-17〕有符號十進制數輸入程序-4

movedx,offsetreadbuf;EDX指向輸入緩沖區

xorebx,ebx ;EBX保存結果

xorecx,ecx ;ECX為正負標志,0為正,-1為負

moval,[edx] ;取一個字符

cmpal,'+' ;是“+”,繼續

jzread1 cmpal,'-' ;是“-”,設置-1標志

jnzread2 movecx,-1read1: incedx ;取下一個字符

moval,[edx] testal,al ;是結尾0,轉向求補碼

jzread3〔例4-17〕有符號十進制數輸入程序-5read2: cmpal,'0' ;不是0~9之間的數碼,錯誤

jbreaderr cmpal,'9' jareaderr subal,30h ;是0~9之間的數碼,轉換

imulebx,10 ;原數值乘10:EBX=EBX×10

jcreaderr ;CF=1,乘積溢出,出錯

movzxeax,al ;零位擴展,便于相加

addebx,eax ;原數乘10后,與新數碼相加

cmpebx,80000000h ;數據超過231,出錯

jberead1 ;繼續轉換下一個數位〔例4-17〕有符號十進制數輸入程序-6readerr: moveax,offseterrmsg ;顯示出錯信息

calldispmsg jmpread0 ;read3: testecx,ecx ;判斷是正數還是負數

jzread4

negebx ;是負數,進行求補

jmpread5read4: cmpebx,7fffffffh ;正數超過231-1,出錯

jareaderr〔例4-17〕有符號十進制數輸入程序-7read5: movtemp,ebx ;設置出口參數

popedx popecx popebx popeax ret ;子程序返回errmsg byte'Inputerror,enteragain:',0read endp共享變量傳遞參數3.堆棧傳遞參數主程序將入口參數壓入堆棧,子程序從堆棧中取出參數出口參數通常不使用堆棧傳遞高級語言進行函數調用時提供的參數,實質也利用堆棧傳遞采用堆棧傳遞參數是程式化的,它是編譯程序處理參數傳遞、以及匯編語言與高級語言混合編程時的常規方法〔例4-18〕計算有符號數平均值程序-1

;數據段array dword675,354,-34,... ;代碼段

pushlengthofarray ;壓入數據個數

pushoffsetarray ;壓數組的偏移地址

callmean ;調用求平均值子程序

;出口參數:EAX=平均值(整數部分)

addesp,8 ;平衡堆棧(壓入了8個字節數據)

calldispsid ;顯示堆棧傳遞參數〔例4-18〕計算有符號數平均值程序-2

;計算32位有符號數平均值子程序mean proc ;入口參數:順序壓入數據個數和數組偏移地址

pushebp ;出口參數:EAX=平均值

movebp,esp

pushebx ;保護寄存器

pushecx pushedx movebx,[ebp+8] ;EBX=取出的偏移地址

movecx,[ebp+12] ;ECX=取出的數據個數

xoreax,eax ;EAX保存和值

xoredx,edx ;EDX=指向數組元素堆棧傳遞參數〔例4-18〕計算有符號數平均值程序-3mean1: addeax,[ebx+edx*4] ;求和

addedx,1 ;指向下一個數據

cmpedx,ecx ;比較個數

jbmean1 ;循環

cdq ;將累加和EAX符號擴展到EDX

idivecx ;有符號數除法,EAX=平均值

popedx ;恢復寄存器

popecx popebx popebp retmean endp示意圖求和溢出與個數為0的問題?利用堆棧傳遞參數返回4.3.4程序模塊程序分段、子程序等是進行程序模塊化開發大型程序時采用的方法子程序模塊子程序庫庫文件包含宏匯編源文件包含1.子程序模塊子程序單獨編寫,匯編形成目標模塊OBJ文件連接時輸入子程序模塊文件名用共用偽指令PUBLIC和外部偽指令EXTERN聲明PUBLIC標識符[,標識符…] ;定義標識符的模塊使用EXTERN標識符:類型[,標識符:類型…] ;調用標識符的模塊使用子程序在代碼段,與主程序文件采用相同的存儲模型,沒有開始執行和結束執行點處理好子程序與主程序之間的參數傳問題〔例4-19〕數據輸入輸出程序-1;eg0419s.asm(子程序文件)

includeio32.incpublic read,write,mean ;子程序共用extern temp:dword ;外部變量

.data ;定義的變量集中起來writebuf byte12dup(0) ;顯示緩沖區readbuf byte30dup(0) .code ;代碼段write procc ;明確采用C語言規范

…… ;輸出子程序read pro

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論