匯編語言學(xué)習(xí)筆記_第1頁
匯編語言學(xué)習(xí)筆記_第2頁
匯編語言學(xué)習(xí)筆記_第3頁
匯編語言學(xué)習(xí)筆記_第4頁
匯編語言學(xué)習(xí)筆記_第5頁
已閱讀5頁,還剩60頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、匯編語言學(xué)習(xí)筆記-傻瓜學(xué)匯編刖言當(dāng)我在學(xué)匯編的時候發(fā)現(xiàn)一到了實際編程就發(fā)現(xiàn)學(xué)過的那些指令串不起來,什么浮 點數(shù)啊整數(shù)啊,怎么跳轉(zhuǎn)啊,怎么循環(huán)啊,腦袋立馬變成漿糊。下面的文檔是我的學(xué)習(xí)經(jīng)歷, 希望對初學(xué)者在學(xué)習(xí)加密解密,軟件調(diào)試,單片機(jī)編程有點幫助。目錄編程環(huán)境的搭建深入理解匯編語言的數(shù)據(jù)順序程序設(shè)計分支結(jié)構(gòu)程序設(shè)計循環(huán)數(shù)組及指針函數(shù)結(jié)構(gòu)綜合運用參考文獻(xiàn)一:編程環(huán)境的搭建首先裝好masm32v10和windbg,和editplus,然后在editplus中輸入下面的程序,具體 的請參考羅云彬的那本書,里面有詳盡的說明,編譯運行看看:.386.model flat,stdcalloption ca

2、semap:noneincludelibmsvcrt.libprintf proto C :VARARG.datamsg db hello,this is the first test program!, 0dh ,0ah,0.codestart:call mainretmain procpushoffset msgcall printfadd esp,4pushoffset msgcall printfadd esp,4retmainendpend start下面是運行結(jié)果:這里輸出兩行消息主要是我在寫這個最簡單的程序的時候發(fā)現(xiàn)他不換行,于是我在數(shù)據(jù)定義 后面我加了 “0ah,0dh”,呵呵

3、,就是回車換行的十六進(jìn)制表示,你也可以用其他方法試試, 程序就不多解釋了,后面會有更多的解釋,不過你一定要走到這以步,才能進(jìn)行下一章。2.深入理解匯編語言的數(shù)據(jù)整數(shù)常量及變量,先看一段很簡單的匯編程序:,386.model flat,stdcalloption casemap:none includelibmsvcrt.libprintf proto C :VARARG .dataPRICE EQU 30msg1 db.codetotal=%d”,0dh,0ah,0start:callretmainmain proclocallocalnum:dwordtotal:dwordmovmovimu

4、lmovnum,10eax,num eax,eax,PRICEtotal,eaxpush call add ret main end startoffset msg1 printf esp,4endp程序的意思很簡單就是在屏幕上打印出某個東西的價格,如過要你拿筆和紙算,拿你肯定很 快就能算出來,但你讓電腦怎么算呢?當(dāng)電腦執(zhí)行到第一個語句的時候,也就是num=10, 它就把10放到某個地方并且記住這個值,寄存器或者內(nèi)存,呵呵,它也就這兩個地方,為 什么要這么做呢?因為后面要用它來計算啊,為了算出這個值,電腦好的辦法就是放在它的 內(nèi)存里,為什么不是寄存器?因為寄存器太少了,就那么幾個,呵呵,所以了

5、它就把10存 在一個叫num的內(nèi)存里,注意了哦,num是程序里的變量名,是存中里的一個位置的名稱, 它的值是10,你可能會問,不起名不行么?行,等下在調(diào)試器中你看到的就是沒名的。來 看看它在調(diào)試器中的樣子:num變成了num變成了ebp-4了,現(xiàn)在你想象有個幾千行的程序如果都用ebp-4這樣的名字的話,那我 們會瘋的,所以匯編程序就讓我們給程序里面的變量起個直觀的名字,而不是用具體的數(shù)字 去讓你去記住變量內(nèi)存的位置。程序中imul eax,eax,1eh中的1eh就是個整形常量,也就是 30.現(xiàn)在你應(yīng)該對常量和變量有點感覺了吧。再看個例子:,386.model flat,stdcallopti

6、on casemap:noneincludelib msvcrt.libprintfproto C :VARARG.dataadb12hbdw1234hc1dd12345678hmsgl db the number is=%xh”,0dh,0ah,0 .codestart:call mainretmainprocmainprocmov al,acbwcwdepusheaxpushoffset msglcallprintfaddesp,8movax,word ptr acwdepusheaxpushoffset msglcallprintfaddesp,8moveax,dword ptr apu

7、sheaxpushoffset msglcallprintfaddsp,8retmainendpend start首先,你得想a, b, c1三個變量在程序中到底是怎么存的,是12 12 34 12 34 56 78 , 還是78 56 34 12 34 12 12呢?呵呵,用調(diào)試器載入程序看看就知道了:DOO4O31O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O32O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O33O7

8、7 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?77777777773004034077 77 77 77 77 77 77 7777 77 77 77 77 77 77 777777777777777?77DOO4O35O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O36O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O37O77 ?7 77 77 77 ?7 77 ?77

9、7 77 7? 77 ? 7? 77 77?7777?7777777777b :000 d 30403000 P0403010 30403020 30403030 30403040 30403050 30403060 30403070 b :ooo _DOO4O31O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O32O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O33O77 ?7 77 77 77 ?7 77 ?777 77

10、 7? 77 ? 7? 77 77?7777?77777777773004034077 77 77 77 77 77 77 7777 77 77 77 77 77 77 777777777777777?77DOO4O35O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O36O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?7777777777DOO4O37O77 ?7 77 77 77 ?7 77 ?777 77 7? 77 ? 7? 77 77?7777?

11、7777777777b :000 d 30403000 P0403010 30403020 30403030 30403040 30403050 30403060 30403070 b :ooo _4 8 o o o o o o 7- 7 o o o o o o5 o o o o o 1 2 0 o o o o od o o orluo o3 o o o o D o 6 3 o o o o o7 o o o o o o 8 9 o o o o o 7- 6 o o o o o oclrlurlurlu arluo o 1 2 0 o o o o o o4 _furlJO o o o 33 7

12、0 o o o o o 4 2 5 o o o o o Irli 6 o o o o o oJ,o o o 6 o o o d o o o 6 o o oo o o 7- o o o e o o oo o o o o o o 2 o o o o a o o N clll=ud o oo o o 8 8 o o LbLbo oo o o o o o o o o o o o o o o o o o o o o o o o o orluo o o o o o o o o o o o o o o o o o o o o 口rlurluo o o o o o o o o o o o o.4-xV4.th

13、e numb er i 5=:j q &$exentrvModLoad: 5cb7OOOO 5cb96OOOC:WIND0WSsystem32ShimEng.dl1ea: =00000000 ebx=7ffd7OOO ecx=D013ffbO edx=7c90e514 esi =00000003 edi =C0000000 ei p=0C401000 esp=0013ff c4 ebp=OO13fffO iopl =0nv up ei pl zr na pe ncc s =00 lb ss=OC23 ds=OO23 es=OO23 f5=CC3b g 5=0000efl =C0000246p*

14、 WARNING: Unable to verify checksum for ch2-3.exe ch2_3(start: 00401000 e801000000call ch2_3 !main (004C1006)b :000::- te.i::f 8 8 (0040 3 D0 b) ds:OO23 :00403000=12 b :000 d 0C40300 00040300? ? ? ? ? 77 7? ?-? 77 77 ? 77 7? ? ?哈哈,看到了沒,正確的是這個:00403000: 12 34 12 78 56 34 12 74-68,這是為什么?還有就是這個程序打印的三個結(jié)

15、果又是什么呢?是12h和0012h和00000012h嗎?如果是,那你就錯了哦,應(yīng)該是:the number is=12h the number is=3412h the number is=78123412h呵呵,首先,你得明白這三個你定義的數(shù)據(jù)在內(nèi)存是怎么存的,一個原則就是你定義的數(shù)據(jù) 的高位存在內(nèi)存中的高字節(jié)地址,你定義的第二個數(shù)據(jù):1234h,高位字節(jié)是12吧,低位字 節(jié)是34吧,所以編譯器它先存34字節(jié)存在內(nèi)存的低地址,然后再把12存在高地址,當(dāng)然 如果是你只定義了一個字節(jié)那順序就沒反了,就像你定義的第一個字節(jié)數(shù)據(jù)12好一樣,同 樣第三個雙自數(shù)據(jù)12345678h,編譯器它就先存78

16、好字節(jié)了,然后是56好字節(jié),34h字節(jié), 12h字節(jié)。下面我們來看看程序:mov al,a,就是是把12h放到al中,movzx ax,al 0擴(kuò)展指令,將al中的字節(jié)擴(kuò)展到 ax中,不足的位用0填充,不改變al的值,al里面是什么值,擴(kuò)展后ax的值還是等于al 中的值。 movzx eax,ax;0擴(kuò)展指令,將ax中的字節(jié)擴(kuò)展到eax中,不足的位用0填充,不改變ax的值,al里面是什么值,擴(kuò)展后eax的值還是等于ax中的值。然后push eax,和push offset msg1,call printf就是調(diào)用c語言庫函數(shù)printf打印消息, 就相當(dāng)于c語言里面的:printf(the n

17、umber is=%xhn,a);下面的和這段一樣,我就不寫廢話 了。如果面對的是有符號數(shù),那就得用movsx 了,當(dāng)然還有其他指令,后面再介紹。浮點數(shù):在計算機(jī)內(nèi)部,浮點數(shù)是以二進(jìn)制表示的,所以,要先轉(zhuǎn)換為二進(jìn)制浮點數(shù),轉(zhuǎn)換分兩部, 整數(shù)部分的裝換,采用“除2取余法”,小數(shù)部分的裝換,采用“乘2取整法”,例如19.2, 先將19轉(zhuǎn)換成二進(jìn)制:10011,然后將0.2轉(zhuǎn)換成二進(jìn)制:001100110011,它是個無窮 循環(huán)小數(shù),然后就是規(guī)格化,分三種情況:如果定義的數(shù)據(jù)類型是dword或者是real4,那 么符號位占一位,階碼占8位,位數(shù)占23位,總共是32位,如果定義的類型是qword或 r

18、eal8,那么符號位占一位,階碼占11位,位數(shù)占52位,總共64位,如果定義的類型是real10 或者是tword,那么階碼占15位,位數(shù)占64位,符號位占一位,總共80位。怎么算階碼 呢?如果是32位,就將階碼加上127,然后轉(zhuǎn)換成二進(jìn)制,如果是64位,就加上1023,如 果是80位,就加上16383。我們看看怎么將19.2轉(zhuǎn)換成32位的二進(jìn)制浮點數(shù):首先將19轉(zhuǎn)換成二進(jìn)制:10011,然后將0.2轉(zhuǎn)換成二進(jìn)制:001100110011,整理成32位 就是:10011,001100110011001100110011001。然 后規(guī)格 化為:1, 0011001100110011001100

19、110011001x2的 4 次方,階碼為 127 加 4 等于 131: 10000011。所 以當(dāng)浮點數(shù)19.2表示為三種不同的數(shù)據(jù)類型為:32 位(dword,real4): 0,10000011,001100110011001100110164 位 ( qword , real8 ):0,100000000011,001100110011001100110011001100110011001100110011001180位:0,100000000000011,0011001100110011001100110011001100110011001100110011001100110011

20、0011001。1轉(zhuǎn)換成 16 進(jìn)制就是 4199999Ah,40333333 33333333 h,403999999999999999ah。然后我們yong程序來驗證一下對不對。例子如下:.386.model flat,stdcalloption casemap:noneincludelibmsvcrt.libprintf proto C :VARARG.dataf1 real419.2f2 real819.2f3 real10 19.2msg1 db the floating number is=%g”,0dh,0ah,0.codestart:call mainretmain procl

21、ocalf:real8fld dword ptr f1 fstp fpushdword ptr f+4pushdword ptr f+8pushoffset msg1call printfadd esp,12pushdword ptr f2+4pushdword ptr f2pushdword ptr offset msglcall printfadd esp,12fld f3fstp qword ptr fpush dword ptr f+4pushdword ptr f+8push offset msg1call printfadd esp,12retmainendpend start程序

22、很簡單,就是分別在屏幕上打印三個浮點值,如下圖:在這里我要說明下,我只有把32位和80位的轉(zhuǎn)換為64位的,才能打印成功,這可能是庫 函數(shù)printf的原因,怎么轉(zhuǎn)換呢?32位浮點轉(zhuǎn)換64位浮點:首先得借助一個64位的浮點局部變量:localf:real8flddword ptr flfstpf第一句定義了 f位一個64位的浮點局部變量,第二句就是把32位浮點數(shù)轉(zhuǎn)換為80位的, 然后第三句就是把80位的轉(zhuǎn)換位64位的。80位浮點轉(zhuǎn)換位64位浮點數(shù):同樣借助一個64位的浮點局部變量:fldf3fstpqword ptr f第二句就是把80位的浮點轉(zhuǎn)換位60位的。但是這兩句怎么解釋呢:pushdwo

23、rd ptr f2+4pushdword ptr f2為什么要先把f2的高4位字節(jié)入棧呢?好,我們先來看看這個數(shù)轉(zhuǎn)換成64位的16進(jìn)制為:40333333 33333333h,前面我說了高低 對應(yīng)原則,那么這個64位的16進(jìn)制在內(nèi)存中高4字節(jié)地址應(yīng)該存40333333h,也就是存它 的高4字節(jié),然后是33333333h,但是,呵呵,在堆棧中的地址是從高往低增長的,所以我 們應(yīng)該先把這個數(shù)的高四字節(jié)入棧,也就是40333333h,怎么在內(nèi)存中得到這高4字節(jié)呢? 就是從f2+4處壓入4字節(jié)就可以了,然后就是低4字節(jié)入棧。如果還沒理解,用cdb調(diào)試 一下就清楚了。浮點與整數(shù)之間的轉(zhuǎn)換:先看例子成ch

24、2-4:,386.model flat,stdcalloption casemap:noneincludelibmsvcrt.libprintfproto C :VARARG.datafl real819.2f2 dword 20msgldb the floating to int number is=%d”,0dh,0ah,0msg2db the int to floating number is=%f,0dh,0ah,0.codestart:call mainretmain proclocalf:real8fld flfistp dword ptr f pushdword ptr f pu

25、shoffset msgl call printf add esp,8fild f2fstp fpushdword ptr f+4 pushdword ptr f+8 pushoffset msg2 call printf add esp,12retmainendpend start運行結(jié)果為:浮點數(shù)轉(zhuǎn)換成整數(shù):fldflfistpword ptr f首先我們還是借助了一個64位的局部變量,先把浮點數(shù)裝入浮點寄存器,然后用裝換整行 的指令變成整數(shù)再存入一個局部變量就行了。整數(shù)轉(zhuǎn)換成浮點數(shù):fild f2fstp f先把整數(shù)用裝換指令裝入浮點寄存器,然后把浮點數(shù)存到一個局部變量就可以了。我在后面

26、會詳細(xì)說名浮點數(shù)的運算和浮點寄存器的。字符與字符串常量:怎么定義他們?他們是以什么形式存在計算機(jī)中?首先我們怎么在匯編中定義他們呢:先看看例子ch2-5:,386.model flat,stdcalloption casemap:none includelibmsvcrt.lib printf proto C :VARARG.datastrl db this is a string test,0ah,0dh,0str2 db this is a string test”,0ah,0dh,0.codestart:call mainretmain procmov eax, offset str1p

27、ushoffset str2call printfadd esp,4pushoffset str1call printfadd esp,4retmainendpend start程序就是在屏幕上打印兩行消息,下面是運行結(jié)果:然后我們用cdb調(diào)試器看看定義的那兩個字符串變量在內(nèi)存中到底是怎么樣的:Executable search ModLoad: ModLoad: ModLoad: ModLoad:004000C0 7c90000C 7c800000 77C1OOOOpath i s : 00404000 7c9b200C 7c8f5OOO 77c68OOOch2-5.exentdll.dll

28、C:WINDOW5X sy st em3 2kernel3 2.dllC : WNDOWSXsystemB 2MSVCRT_ dl 1 exception - code 80000003 (first chance)Executable search ModLoad: ModLoad: ModLoad: ModLoad:004000C0 7c90000C 7c800000 77C1OOOOpath i s : 00404000 7c9b200C 7c8f5OOO 77c68OOOch2-5.exentdll.dllC:WINDOW5X sy st em3 2kernel3 2.dllC : W

29、NDOWSXsystemB 2MSVCRT_ dl 1 exception - code 80000003 (first chance)(d68.2e8) : Break i nstruction ea: g -Jexentry Mod Load: 5cb7OOOO* 5cb96DOO_eax =00000000 ebx=7ffd.slOOO ecx=0013ffbO edx=7c90e514 esi =00000000 edi =00000000 ei p =00401000 esp=0C13ff c4 ebp=OO13fffO iopl =0nv up ei pl zr na pe ncc

30、 5 =00 lb 55=0023 ds=OO23 es=OO23 f 5=003 b gs=COODefl =0000C246* WARNING: Unable to verify checksum for ch2-5-exe ch25(start: 00401000 eSOWOOOOC* b:000 t ea: d bO4O3DOO P0403010 30403020 bO4O3O3O P0403040 30403050 30403060 b0403070 J:0009 5 3 o o Au o o 心 6 6 7 o o o o o o8 4 o o o o o o6 7 2 o o o

31、 o o4 0 1o o o o o 0 F N 6 o o o o ointnv up ei pl nz n-a. po nc_efl=CD0Q0202not be found- Defaulted to export symbols for ntdll.dllC:WINDOW5sy st em32ShimEng.dl1cal 1rnov3 d e o o o o o 7- o 6 o o o o o 9aQ- o o o o o 6 o 6 o o o o och2_5 !mai n (0C401C06)e-arxoff setnv up ei pl zr na pe nc g s=00C

32、0ef 1 =QQQ0Q 24 6匚hN_5 !ULL_IMPORT_DESCRIPTORDxf 88 (00403000)9 9 a o o o o o _.b 6 o o o o o o 20 4 0 0 o o 0 7- 7 o o o o o 4 3 3 o o o o o 7- 7- 7 o o o o othi s i s a string test.thi sisa stri ng test.cmd to cdb.exe - cdb -2 C:Vwbch2ch2-5V:h2-5nr * -K-fT -fT -fT -fT -fT -fT恩,它們是以asii碼的形式存在的。其他的數(shù)

33、據(jù)類型我會在下面的各個章節(jié)會隨著編程的算法和調(diào)試一起講解。3:順序程序設(shè)計匯編語言的順序編程比較好理解,就是在編程的時候沒有跳轉(zhuǎn),沒有循環(huán),看看例子ch3-1: 例ch3-1:輸入三角形的邊長,求三角形的面積。我假設(shè)輸入的三邊長都是能構(gòu)成三角形的,求三角形面積的公式為area= s(s-a)(s-b(s-c)。s= ( a+b+c)/2.這里要用到浮點指令,那就先回顧下浮點指令的用法:這里要加減乘除和平方根五種指令, 由于Intel的浮點數(shù)據(jù)寄存器是種堆棧結(jié)構(gòu),我們要記住這一點。先看看數(shù)據(jù)傳送指令:fld和fild,fst,fstp:fld源操作數(shù),源操作數(shù)可以是浮點寄存器和內(nèi)存,這個指令主要

34、是把源操作數(shù)壓入浮點寄 存器堆棧(其實就是st0),如果源操作數(shù)是整數(shù),那就用fild。Fst和fstp是把st(0)浮點寄存器中的數(shù)彈出到目的操作數(shù)中,目的操作數(shù)可以為浮點寄存 器和內(nèi)存。加減法指令:fadd,faddp, fub,fsubp第一種形式:fadd目的操作數(shù),源操作數(shù)。其中目的操作數(shù),源操作數(shù)可以為浮點寄存器 和內(nèi)存。第二種形式:fadd源操作數(shù),我本人比較喜歡這種,它不會把我腦海里的浮點寄存器的順序 弄亂,這種形式的源操作數(shù)只能是內(nèi)存。減法指令同加法指令,就不多說了。乘除法指令:fmul,fdiv浮點的乘除法是不區(qū)分有符號和無符號數(shù)的,他們也有兩種形式:fmul目的操作數(shù),源

35、操作數(shù)和fmul源操作數(shù)這兩種形式,第一種操作數(shù)和源操作數(shù)可以 為浮點寄存器和內(nèi)存,但第二種源操作數(shù)值能為內(nèi)存。平方根指令:fsqrt這個指令就一種形式就是fsqrt,就是把第0個浮點寄存器st0的值變成平方根值然后存在 st0 中。再回到例題中,我們應(yīng)該先算s值,然后再算平方根下面的值然后求平方根就行了。S值是三邊長除以2,轉(zhuǎn)換成浮點指令就是:fld a ;先把a(bǔ)值放到浮點寄存器st0中再就是fadd b ;這個就是a+b,結(jié)果存在st0中然后 fadd c ;同上,結(jié)果存在st0中現(xiàn)在算出了三邊長的和,在除以2就ok 了 fiv two;結(jié)果在st0中,最后把st0里面的值用fstp s存

36、到s中就把s值算出來了。再來算根號下面的值,這里有乘法和減法,我們先算減法:fld sfsub,a;這個就是s-a,結(jié)果在 st0里再 fld sfsub b;這個結(jié)果還是在st0里,但是上面那個s-a已經(jīng)被推到st(1)這個浮點堆棧了啊,記住了。再 fld sfsub c;這個結(jié)果還是在st0里,那么s-a被推到st(2)了,s-b被推到st(1)了,s-c的值在st(0)中,這里千萬不能及亂了啊,下一步算乘法,先算s*(s-c),mul s;果在st0lifmul st(0),st(1)這一步是算s* (s-a)* (s-b)最后算 s* (s-a)* (s-b)* (s-a)fmul s

37、t(0),st(2),然后把s* (s-a)* (s-b)* (s-a)的結(jié)果再求平方根 fsqrt再把這個平方根的值彈出到area中。這是按照上面的想法寫出的程序:,386.model flat,stdcalloption casemap:noneincludelibmsvcrt.libprintfproto C :VARARGscanfproto C :VARARG.datamsgldb”%f,%f,%f”,0msg2dbarea=%7.2f”,0ah,0dh,0msg3dbplease input three floating numbers”,0ah,0dh,0two real42.0

38、.codestart:call mainretmain proclocala:real4 localb:real4 localc1:real4 locals:real4 localarea:real8pushoffset msg3 call printf add esp,4lea eax,c1pusheax lea eax,b push eax lea eax,a push eaxpush offset msg1 call scanf add esp,16fld afadd bfadd c1 fdiv twofstp sfsub a fsub b fsub c1fmul sfmulst,st(

39、1) fmulst,st(2) fsqrt fstp areapushdword ptr area+8 pushdword ptr area+4 pushoffset msg2call printfadd esp,12 retmainendpend start編譯運行:下面是結(jié)果:但是出乎意料哦,錯了,怎么辦呢?你發(fā)現(xiàn)什么問題了沒?那只有調(diào)試看看了,用cdb -2 C:wbch3ch3-1ch3-1打開程序然后逐步調(diào)試看看,當(dāng)跟蹤到下面這句是就發(fā)現(xiàn) 有問題了:就是 fstp, s,也就是 00401041 d95df0fstp dword ptr ebp-10hss:0023:0013ffac

40、=a9e45d08,然后發(fā)現(xiàn)st中的值被彈走了,但緊接著又用st (0)用與下一步 進(jìn)行計算了,先推出調(diào)試,改動下再運行看看對不對,但結(jié)果還是錯的:那還得繼續(xù)調(diào)試了,發(fā)現(xiàn)我對fsub指令理解錯了,原來這個指令執(zhí)行完之后它不把結(jié) 果推到下一個浮點堆棧:那只能用fsubp 了,改動如下:fld afsubp st(1),stfld s fld b fsubpst(1),stfld s fld cl fsubpst(1),st但結(jié)果還是錯的,一想一下“高低原則”,改成;然后改成這種了 看至這句pushpushpushpushdword ptr area+8 dword ptr area+4 dwor

41、d ptr area+4 dword ptr area+8編譯運行,哈哈,ok 了:最后正確的代碼:,386.model flat,stdcalloption casemap:noneincludelibmsvcrt.libprintfproto C :VARARGscanfproto C :VARARG.datamsgldb”%f,%f,%f”,0msg2dbarea=%7.2f”,0ah,0dh,0msg3dbplease input three floating numbers”,0ah,0dh,0two real42.0.codestart:call mainretmain procl

42、ocala:real4 localb:real4 localc1:real4 locals:real4localarea:real8;這里是變量定義pushoffset msg3 call printfadd esp,4;這里是提示輸入三個邊長lea eax,c1 pusheax lea eax,b push eax lea eax,apush eaxpush offset msg1 call scanfadd esp,16;這里是調(diào)用庫函數(shù)scanffld afadd bfadd c1 fdiv two;fstp s這一句其實是有問題的,你可以調(diào)試看看fst s;改成這句;fsuba;fsu

43、bb;fsubc1 ;經(jīng)調(diào)試發(fā)現(xiàn)這三句都是錯的fld afsubpst(1),stfld s fld bfsubp st(1),stfld s fld c1fsubp st(1),st ;然后改成這種了fmulsfmulst,st(1)fmulst,st(2)fsqrtfstp qword ptr area ;這一段是計算area值,我的文檔上有詳細(xì)解釋pushdword ptr area+4pushdword ptr area+8pushoffset msg2call printfadd esp,12;打印結(jié)果retmainendpend start呵呵,定義的時候用了 cl,因為c是匯編里

44、面的關(guān)鍵字,所以我就改了下,你可能會 說,你怎么不優(yōu)化一下呢?呵呵,先把程序?qū)憣α?,把指令理解透了再去?yōu)化也不晚。練習(xí)ch2-2:求下面xl和x2的值:x1=(b+/b*b-4ac)/2a, x2= (b- /b*b-4ac)/2a, a,b,c 由鍵盤輸入。提示下真確運行結(jié)果:a=1, b=3, c=2x1=-1.00 x2=-2.004.選擇分支結(jié)構(gòu)程序設(shè)計前面我們看到的程序都是從上到下這樣執(zhí)行的,程序的執(zhí)行流程沒有跳轉(zhuǎn)和循環(huán),cpu為我 們實現(xiàn)程序的跳轉(zhuǎn)提供了硬件環(huán)境和一些指令,首先cpu它有個處理器狀態(tài)寄存器,跳轉(zhuǎn)指 令就是無條件跳轉(zhuǎn)jmp和有條件跳轉(zhuǎn)指令jcc (里面包含了很多種形式

45、的),總的來說就是你 在你寫的程序里面用跳轉(zhuǎn)指令讓cpu取改變程序的執(zhí)行流程,cpu會根據(jù)那個狀態(tài)寄存器的 一個或多個值的改變來執(zhí)行程序,我們先來看個例子:例4.1:輸入3個整數(shù)a,b,c,請輸出其中最大的數(shù)。我們只要一次把這三個數(shù)比較一次,在每次比較中,把那個大值繼續(xù)和下一個數(shù)來做比較, 然后再輸出那個最大值就行了。代碼如下:,386.model flat,stdcalloption casemap:NONEincludelibmsvcrt.libprintfprotoc:VARARGscanfprotoc:VARARG.datamsg1dbmsg2dbmsg3db.codeplease i

46、nput three int numbers”,0ah,0dh,0The Max of three numbers is =%d,0ah,0dh,0%d,%d,%d”,0 start:call mainret mainproclocala:dword localb:dword localc1:dwordpushoffset msgl call printf add esp,4lea eax,c1push eaxlea eax,bpush eaxlea eax,apush eaxpushoffset msg3call scanfadd esp,16;提示用戶輸入三個整型數(shù)mov eax,acmp

47、 eax,bjg a_compare_c ;跳轉(zhuǎn)到將a與c比較mov eax,bcmp eax,c1jg print_max;到這里三個數(shù)已經(jīng)全部比較完,跳轉(zhuǎn)到打印最最大值:mov eax,c1;到這里三個數(shù)已經(jīng)全部比較完,跳轉(zhuǎn)到打印最最大值jmp print_max a_compare_c: cmp eax,c1jg print_max;到這里三個數(shù)已經(jīng)全部比較完,跳轉(zhuǎn)到打印最最大值jmp bprint_max: pusheax pushoffset msg2 call printf add esp,8 retmainendp運行結(jié)果運行結(jié)果:end start運行結(jié)果運行結(jié)果:無論是整數(shù)還

48、是負(fù)數(shù),結(jié)果都是正確的。這里的cmp指令相當(dāng)于減法,只是它不保存運算 結(jié)果,而是改變前面說的狀態(tài)寄存器,具體的就是狀態(tài)寄存器的符號位,零標(biāo)志位,溢出標(biāo) 志位和進(jìn)位位,然后那個條件跳轉(zhuǎn)指令jg就會根據(jù)上面那些狀態(tài)位來確定怎么跳轉(zhuǎn),這里 的jg即使指令就是根據(jù)符號位和零標(biāo)志位來確定跳轉(zhuǎn)的,你可以用windbg驗證一下。在分 支程序設(shè)計中,在前面有比較,比較完之后看當(dāng)前情況滿足哪種情況,然后用跳轉(zhuǎn)指令跳取 即可,前面這個判斷中是個最簡單的判斷,下面我們來看看比較復(fù)雜的情況,先看例子ch4-2: 例ch4-2輸入一個年份,判斷是否閏年。在判斷是否是閏年時,我們可以用一個復(fù)雜的判斷表達(dá)式來包含所有的閏年

49、條件,也就是當(dāng) 輸入的年份(year%4=0&year%100! =0)|year%400=0則輸出這個年份是閏年,否則 輸出不是,現(xiàn)在的問題就是怎么把上面的那個復(fù)雜的判斷用匯編語言來正確的表達(dá),下面是 代碼:,386.model flat,stdcalloption casemap:NONEc:VARARGc:VARARGincludelibmsvcrt.lib c:VARARGc:VARARGmsg1dbplease input a year”,0ah,0dh,0msg2db%d is not a leap year,0ah,0dh,0msg3db%d is a leap yaer ,0a

50、h,0dh,0msg4db%d.codestart:call mainretmainproclocalyear:dwordlocalleap:dwordpushoffset msglcall printfadd esp,4;到這里是輸出提示信息lea eax,yearpusheaxpush offset msg4call scanfadd esp,8;這幾句是調(diào)用輸入函數(shù)把輸入的年份存到y(tǒng)ear變量里mov eax,yearxor edx,edxmov ebx,400div ebxtest edx,edxjz is_a_leap_year ;這里先測試年份除以400,如果滿足就直接跳轉(zhuǎn)到打印是

51、閏年的代 碼處mov eax,yearxor edx,edxmov ebx,4div ebxtest edx,edx;到這里就是判斷閏年的第二種情況了,如果除以4,不能整除就直接跳到打印不是閏年的代碼處jnz is_not_a_year ;如果能整除就繼續(xù)判斷mov eax,yearxor edx,edxmov ebx,100div ebxtest edx,edxjz is_not_a_year ;這里是繼續(xù)判斷這個年份能不能整除100,如果你能整除就跳 到打印不是閏年代碼處is_a_leap_year:pushyearpushoffset msg3call printfadd esp,8;打

52、印是閏年的信息jmp out_this_program ;然后跳轉(zhuǎn)到退出本程序is_not_a_year:push yearpushoffset msg2call printfadd esp,8;打印不是閏年消息out_this_program:ret;退出本程序的地方mainendpend start下面是運行結(jié)果:C:wbch4ch4-2ch4-2please input a year20082008 is a leap yaerC:wbch4ch4-2ch4-2please input a year20002000 is a leap yaerC:wbch4ch4-2ch4-2pleas

53、e input a year19891989 is not a leap year這里我們先判斷那個比較簡單的測試點就是看年份能不能能整除400,如果為真,就直接跳 轉(zhuǎn)到打印是閏年的代碼處,然后再判斷看能不能整除4,如果為假,就直接跳轉(zhuǎn)到打印不是 閏年的代碼處,然后下面的就不用再判斷了,呵呵,因為這里是&邏輯與哦,就是著名的 “短路表達(dá)式”,程序本身比較簡單,就不多解釋了。下面來看看判斷語句的嵌套。判斷語句的嵌套:判斷語句的嵌套就是判斷里面又有判斷,呵呵,先看例子:例ch4-3:有一函數(shù):一1U 0)編一程序,輸入一個H值,輸出,值。從題意可以看出,當(dāng)輸入一個X值,程序就得先判斷是不是小與0啊

54、,然后緊接著判斷是不 是等于0啊,再判斷是不是大于0啊,然后才算判斷完全,下面是代碼:,386.model flat,stdcalloption casemap:NONE includelibmsvcrt.libprintf proto c:VARARG scanf proto c:VARARG .datamsgldbplease input aint number”,0ah,0dh,0msg2dbthe Y value is%d,0ah,0dh,0msg4db%d.codestart:call mainret mainproclocalx:dwordpush offset msglcall

55、printfadd esp,4;輸出提示信息lea eax,xpush eaxpush offset msg4call scanfadd esp,8 ;調(diào)用scanf將輸入的一個值存在局部變量x里面;moveax,x;moveax,x;cmpeax,-1;je Y_equal_minus_one;test eax,eax;jz Y_equal_zero;cmpeax,1;je Y-equal_one未優(yōu)化的嵌套判斷語句;下面是有點優(yōu)化的嵌套判斷語句mov eax,xinc eax;x如果是-1加1就是0啦,呵呵jle Y_equal_minus_one ;如果是0就跳轉(zhuǎn)到打印y值的代碼處mov

56、 eax,xtest eax,eax;用test來判斷寄存器是否為0,感覺要比cmp eax,0要好很多,你可以用cdb看看jz Y_equal_zeromov eax,xdec eax ;x如果是1減1就是0啦,呵呵jae Y_equal_one ;如果是0就跳轉(zhuǎn)到打印y值的代碼處Y_equal_minus_one:push-1pushoffset msg2call printfadd esp,8jmp out_this_program ;這里如果不跳轉(zhuǎn)的話就會執(zhí)行到Y(jié)_equal_zero 了,這明顯是不行 的,所要跳轉(zhuǎn)Y_equal_zero:xor eax,eaxpush eaxpus

57、h offset msg2call printfadd esp,8jmp out_this_program這里如果不跳轉(zhuǎn)的話就會執(zhí)行到Y(jié)_equal_zero 了,這明顯是不行 的,所要跳轉(zhuǎn)Y_equal_one:push 1push offset msg2call printfadd esp,8;這里就不要再跳轉(zhuǎn)了,直接執(zhí)行到下面就行了out_this_program:retmainendpend start下面是運行結(jié)果:C:wbch4ch4-3ch4-3 please input a int number 0the Y value is 0C:wbch4ch4-3ch4-3 please

58、 input a int number -56the Y value is -1C:wbch4ch4-3ch4-3 please input a int number 56 the Y value is 1像這種判斷嵌套的地方,就是不停的比較,然后根據(jù)判斷結(jié)果跳轉(zhuǎn)到要執(zhí)行的地方,下面我 們來看看浮點數(shù)的判斷,在比較完兩個浮點數(shù)之后,我們緊接著得用fstsw將FPU的狀態(tài)寄 存器里面的比較結(jié)果存到一個16位的內(nèi)存位置或者是個16位的寄存器,但最好是存在ax 中,因為緊接著就得用sahf指令把浮點數(shù)比較的結(jié)果存到標(biāo)志寄存器EFLAGS中,然后我 們就可用JCC條件跳轉(zhuǎn)指令來實現(xiàn)跳轉(zhuǎn)了,具體的化來看

59、看例子:例子ch4-4:求工+如= 方程的解。這個一元二次方程怎么求解,大家應(yīng)該很熟悉了吧,就不多說了,下面來看看怎么實現(xiàn)浮點 數(shù)的比較,代碼如下:,386 .model flat,stdcalloption casemap:NONEincludelibmsvcrt.lib printf scanf .data zero dq four dw msgl msg2 msg3 msg4 msg5 msg6 msg7 .codeproto c:VARARGproto c:VARARG0.00000014 db db db db db db dbplease input three numbers”,

60、0ah,0dh,0%f,%f,%f”,0The equation is not a quadratic ,0ah,0dh,0The equation has two cpmplex roots: %8.4f+%8.4fi,0ah,0dh,0The equation has two cpmplex roots: %8.4f-%8.4fi,0ah,0dh,0The equation has two equal roots: %8.4f,0ah,0dh,0The equation has two real roots: %8.4f,%8.4f,0ah,0dh,0start:call mainretm

溫馨提示

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

評論

0/150

提交評論