<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Decode360's Blog

    業精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
      302 隨筆 :: 26 文章 :: 82 評論 :: 0 Trackbacks
    ??? 最近想初步了解一下匯編的內容,在網上搜了搜,發現一篇寫得很不錯的文章,特地轉過來留存。寫得淺顯易懂,而且加入了很多個人的見解,比書上寫的好懂多了。比較欽佩作者,可惜找了半天沒有找到這篇文章的原作者是誰。轉載地址:http://www.zxbc.cn/html/20070611/22772.html
    ?
    ?
    ?
    ?
    學習匯編前你應該知道的知識
    ?

    1、匯編需要什么工具和程序,到哪里下載?

    ??? 目前階段,匯編程序僅需要兩個程序就夠了。masm.exe,link.exe。 前者是編譯程序,后者是鏈接程序。另外,為了驗證和調試程序,還需要一個程序debug.exe,該程序由windows本身就提供。
    ??? 將二者下載后,放到某一個目錄中(任意目錄都可以),考慮到很多命令需要通過鍵盤敲入,所以建議你不要把文件放入到長文件名目錄、中文目錄或很深的目錄中。比如你可以建一個“D:\Masm”目錄,并建議此后的程序都放這個目錄,此后稱這個目錄為匯編目錄。
    ?
    2、學習匯編需要有哪些編程方面的知識?
    ?
    ??? 沒有任何編程方面的知識,學習此語言等于緣木求魚,所以請放棄學習的想法。一般來說至少要知道如下幾點:
    ??? *)程序的運行邏輯結構有順序(按語句依次執行)、分支結構(IF...THEN...ELSE...),循環結構(FOR...NEXT)三種結構。
    ??? *)知道什么是子程序,什么是調用。
    ??? *)匯編程序員的視角。不同編程視角編程要求是不一樣的。比如刪除文件:
    ??????? >>用戶的視角是找到“刪除”按鈕或菜單,然后單擊一下即可。
    ??????? >>高級程序員的視角是知道刪除的文件,并發出刪除命令。這些通過API實現。
    ??????? >>匯編程員的視角是得到要刪除的文件名,找到該文件所在位置,通過調用刪除“中斷命令”進行刪除。
    ??????? >>操作系統開發人員的視角則是接到刪除命令后,先找到系統根目錄區,由根目錄區的鏈接依次找到子目錄區,直到找到要刪除的文件,然后按照操作系統刪除文件的規則對該文件名進行修改。比如DOS,只把第一個字符改成"?"。
    ?
    ??? 按程序語句等價的角度看,一行VB的打印語句,用匯編實現大約需要一百二十多行。知道匯編語言的視角后就要知道,前面的道路是坎坷的,沒有耐心是不行的。想通過幾分鐘幾行程序就完成很復雜的操作不是件容易的事。
    ?
    3、學匯編有什么用?
    ?
    ??? 匯編產生于DOS時代或更早,而現在是Windows時代,所以可能 遺憾地說:盡管還有批牛人在用匯編開發核心級程序,但我們幾乎沒什么用,除了必要時間能拿來分析一兩個程序的部分代碼之外,別的也就沒干什么用了。并且并不是所有的匯編命令都能在windows下使用。而泛泛地追求“時髦”而學本語言,最后的結果是損了夫人又折兵。所以學之前你要考慮好。我勸那些為了當“黑客”而學匯編的人就此止步。
    ?
    ?
    第零講 預備知識
    ?
    ?
    1、一個匯編程序的編譯過程是怎么樣的?

    ??? 1)首先你需要找一個編輯器,編輯器用任何“純文本”編輯器都可以。比如記事本。編好以后保存到匯編目錄中。擴展名為asm,比如myfirst.asm。但這里建議你找一個能顯示出當前行的編譯器。這樣出錯后排錯很容易。
    ??? 2)然后在DOS下進入D:\Masm目錄中,輸入“masm myfirst.asm",如果有錯系統會提示出錯的行位置和出錯原因。
    ??? 3)然后再輸入“link myfirst.obj”,即可看到當前目錄下有一個myfirst.exe程序。
    ?
    2、宏匯編和匯編有什么區別嗎?
    ?
    ??? 二者的區別在于前者提供宏,后者不提供。后者已找不到了,所以你可以認為二者沒有區別。
    ?
    3、機器語言、匯編語言、高級語言的關系

    ??? 最早的計算機采用機器語言,這種語言直接用二進制數表示,通過直接輸入二進制數,插拔電路板等實現,這種“編程”很容易出錯,每個命令都是通過查命令表實現,既然是通過“查表”實現的,那當然也可以讓計算機來代替人查表實現了。于是就產生了匯編語言,所以不管別人怎么定義機、匯語言,我就認為,二者是等價。后來人們發現,用匯編語言編某一功能的時候,連續一段代碼都是相同或相似,于是就考慮用一句語言來代替這一段匯編語言,于是就產生了高級語言。因此,所有高級語言都能轉化成匯編語言,而所以匯編語言又可轉化成機器語言。反之,所有機器語言可以轉成匯編語言(因為二者等價)。但并不是所以匯編語言都能轉成高級語言。
    ?
    4、計算機的組成

    ??? 通常都把計算機定義成五部分:運算器、控制器、存儲器、輸入系統、輸出系統。
    ??? 為了簡單起見,我們如此理解:運算器+控制器=CPU。存儲器=內存(暫不包括外存,也不包括CACHE)。輸入系統=鍵盤(不包括鼠標),輸出系統=顯示器(不包括打印機,繪圖儀)。
    ?
    5、寄存器和內存的區別

    ??? 寄存器在CPU中。內存在內存條中。前者的速度比后者快100倍左右。后面的程序要求每條指定要么沒有內存數據,要么在有一個寄存器的參與下有一個內存數據。(也就是說,不存在只訪問內存的指令)。
    ?
    6、匯編語言的計數

    ??? 與生活中的計數不一樣,匯編中的計數是從0開始的。比如16個計數,則是從0~15,而不是生活中的1~16。這一點看起來簡單,真運算起來就不是件容易的事了,不信等著瞧。
    ?
    7、進制問題
    ?
    ??? 又與生活中不一樣的地方是進制。切記下面的常識:
    ??? *)計算機內部存儲都用二進制。
    ??? *)我們的匯編源程序默認都用十進制。(除非你指明類型)
    ??? *)我們用的調試程序debug默認的都是十六進制。(無法指明其他類型)
    ??? 其中十六進制的十六個個位數依次是:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F。
    ?
    8、進制轉換

    ??? 一個比較簡單的方法是查表法。
    ??? 十進制?十六進制?二進制
    ????? 0????? 0????? 0000
    ????? 1????? 1????? 0001
    ????? 2????? 2????? 0010
    ????? 3????? 3????? 0011
    ????? 4????? 4????? 0100
    ????? 5????? 5????? 0101
    ????? 6????? 6????? 0110
    ????? 7????? 7????? 0111
    ????? 8????? 8????? 1000
    ????? 9????? 9????? 1001
    ????? 10????A????? 1010
    ????? 11????B????? 1011
    ????? 12????C????? 1100
    ????? 13????D????? 1101
    ????? 14????E????? 1110
    ????? 15????F????? 1111
    ??
    ??? 好了,結合6,7,8三條。大家來算一個“題”。某一組數據顯示時,每個數據占了四個位置,每行共十六個。問:十六進制的13位置在哪里(第幾行,第幾列)。
    ??? 格式如下:m m m m n n n n o o o o p p p p '注:之所以沒用ABC是怕與上面十六進制弄混。
    ??????????? r r r r s s s s t t t t u u u u
    ?
    ?
    第一講 基礎知識
    ?

    1、訪問內存

    ??? 程序在內存中,訪問內存是幾乎每一程序都要進行的操作,計算機對內存編址是線性的,也就是說是一維的,比如256M的內存,地址就應該是從0~(256M-1),這個地址稱為物理地址或絕對地址。

    ? 1.1 地址表示
    ?
    ??? 但從匯編程序員的角度看,內存卻是二維的,要說明一個地址,需要給出兩個值,就象你在平面上指定一點需要說出(X,Y)坐標一樣,匯編程序員的內存視角也需要兩個“坐標”,前一個稱為段地址(Segment),后一個稱為偏移地址(Offset),該地址稱為邏輯地址。
    ??? 比如“1234:3DF5”就是一個地址。“1F3F:”不是一個地址,因為他只有段地址,沒有偏移地址。注意此后的地址都用十六進制表示。
    ?
    ? 1.2 地址計算
    ?
    ??? 前面提到,計算機編址是一維的,匯編程序員是二維的,那么二者怎么換算呢?由后者到前者的換算方法是,“段地址串”后面加個“0”,然后再加上偏移地址。
    ??? 比如“1234:3DF5”(十六進制的加減運算參見相關資料)
    ??? 12340? --串后加了一個0
    ???? 3DF5
    ??? -----
    ??? 16135??--注意此串仍然是十六進制。
    ??? 所以,匯編程序員眼中的地址“1234:3DF5”就是物理地址(計算機編址):16135。
    ??? 知道了由后者向前者的轉換,那么由前者向后者的轉換呢?
    ??? “不知道”,為什么不知道,繼續往下看。
    ?
    ? 1.3 到底哪個地址對
    ?
    ??? 知道了1.2的地址算法后,我又發現一個問題:
    ??? “1000:6135”的物理地址是多少呢? 10000+6135=16135。
    ??? “1001:6125”的物理地址呢? 10010+6125=16135。
    ??? ......
    ??? 那么到底哪個對呢?問題的回答是這樣的:假設我現在讓你按一下“L”鍵,我可以告訴你如下幾種方法中的一種或幾種。1 請按一下“L”鍵; 2請按一下鍵盤上第四行第十個鍵;3 請按一下第十列中的第四個鍵;4 請按一下“K”右邊的鍵;5 按標準指法單擊一下右手無名指。
    ?
    ??? 舉上面的例子也就是說,同一個地址有很多種表示方式,具體用哪一種,要看實際使用時的情況。但無論用哪種方式,只要能達到目的即可。(實際中該問題一般不會受此問題困擾,但初學時突然想不通)。
    ?
    ? 1.4 有多少內存可以訪問
    ?
    ??? 無論是段地址還是偏移地址都是四位十六進制(如果不夠四位,前面補0)。也就是說:總共可以訪問的地址說是:0000:0000~FFFF:FFFF。 總共FFFF0+FFFF+1=10FFF0個地址。也就是不到1M的空間。
    ??? 記住如下結論:
    ??? *) 不管你實際內存有多少,目前我們只能訪問不到1M的空間。
    ??? *) 而實際上連這1M也用不完。其中上端的384K的址只能讀不能寫,只能讀,一般稱為ROM。
    ??? *) 低端的640K可以讀寫。但這640K的低端100多K也不能隨便寫,因此DOS系統使用該區。
    ??? *) 原來1024M的內存,匯編程序只能使用其中400多K。這段內存的容易相當于一個普通文檔的大小。不過這就足夠了。

    2、DEBUG的使用
    ?
    ??? 先記住以下兩個命令:D命令和Q命令。前者是顯示內存內容,后者是退出DEBUG命令。

    ------------------------以下為抄別的人內容----------------------
    ??? DEBUG.EXE程序是專門為分析、研制和開發匯編語言程序而設計的一種調試工具,具有跟蹤程序執行、觀察中間運行結果、顯示和修改寄存器或存儲單元內容等多種功能。它能使程序設計人員或用戶觸及到機器內部,因此可以說它是80X86CPU的心靈窗口,也是我們學習匯編語言必須掌握的調試工具。
    ?
    ??? 1) DEBUG程序使用
    ?
    ??? 在DOS提示符下鍵入命令:
    ??? C>DEBUG [盤符:][路徑][文件名.EXE][參數1][參數2]
    ?
    ??? 這時屏幕上出現DEBUG的提示符“-”,表示系統在DEBUG管理之下,此時可以用DEBUG進行程序調試。若所有選項省略,僅把DEBUG裝入內存,可對當前內存中的內容進行調試,或者再用N和L命令,從指定盤上裝入要調試的程序;若命令行中有文件名,則DOS把DEBUG程序調入內存后,再由DEBUG將指定的文件名裝入內存。
    ?
    ??? 2) DEBUG的常用命令
    ?
    ???????? (1)退出命令 Q
    ??????? 格式:Q
    ??????? 功能:退出DEBUG,返回到操作系統。
    ????????(2)顯示存儲單元命令 D
    ??????? 格式1:D[起始地址]
    ??????? 格式2:D[起始地址][結束地址|字節數]
    ??????? 功能:格式1從起始地址開始按十六進制顯示80H個單元的內容,每行16個單元,共8行,每行右邊顯示16個單元的ASCII碼,不可顯示的ASCII碼則顯示“.”。格式2顯示指定范圍內存儲單元的內容,其他顯示方式與格式1一樣。如果缺省起始地址或地址范圍,則從當前的地址開始按格式1顯示。
    ??????? 例如:-D 200???????--表示從DS:0200H開始顯示128個單元內容
    ?????????????-D 100 120???--表示顯示DS:0100-DS:0120單元的內容
    ??????? 說明:在DEBUG中,地址表示方式有如下形式:
    ??????? 段寄存器名:相對地址,如:DS:100
    ??????? 段基值:偏移地址(相對地址),如:23A0:1500
    --------------------------小抄結束--------------------------------
    ?
    3、驗證第一節里的內容
    ?
    ??? 運行“開始/程序/附件/MS-DOS命令提示符”(這是win2000,win98下自己找吧)
    ??? 在“-”下輸入D,顯示
    -d
    1398:0100? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1398:0110? 00 00 00 00 00 00 00 00-00 00 00 00 34 00 87 13? ............4...
    1398:0120? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1398:0130? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1398:0140? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1398:0150? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1398:0160? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1398:0170? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    -
    ??? 我們記下:1398:011C的值是個34。1389:011C的物理地址應該是:13A9C。
    ??? 那么1000:3A9C的物理地址也應該是13A9C,他的內存也應該是34,(因為本來就是一個地址嗎,就象第三行第十列和第十列第三行當然應該是同一個位置)。
    -d 1000:3A9C
    1000:3A90????????????????????????????????????? 34 00 87 13????????????? 4...
    1000:3AA0? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1000:3AB0? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1000:3AC0? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1000:3AD0? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1000:3AE0? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1000:3AF0? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1000:3B00? 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    1000:3B10? 00 00 00 00 00 00 00 00-00 00 00 00????????????? ............
    -
    ??? 果然如此,同樣你可以驗證:13A9:000C也肯定是指這一個地址,不信試試。
    ?
    4、DEBUG命令

    ------------------------繼續小抄----------------------------
    ??? 前面已學過:顯示存儲單元命令 D
    ??? 再學一個命令
    ????(1)修改存儲單元命令 E
    ?
    ??? 格式1:E[起始地址] [內容表]
    ??? 格式2:E[地址]
    ??? 功能:格式1按內容表的內容修改從起始地址開始的多個存儲單元內容,即用內容表指定的內容來代替存儲單元當前內容。
    ?
    ??? 例如:-E DS:0100 'VAR' 12 34
    ??? 表示從DS:0100 為起始單元的連續五個字節單元內容依次被修改為
    ??? 'V'、'A'、'R'、12H、34H。
    ??? 格式2是逐個修改指定地址單元的當前內容。
    ??? 如:-E DS:0010
    ??? 156F:0010 41.5F
    ??? 其中156F:0010單元原來的值是41H,5FH為輸入的修改值。若只修改一個單元的內容,這時按回車鍵即可;若還想繼續修改下一個單元內容,此時應按空格鍵,就顯示下一個單元的內容,需修改就鍵入新的內容,不修改再按空格跳過,如此重復直到修改完畢,按回車鍵返回DEBUG“-”提示符。如果在修改過程中,將空格鍵換成按“-”鍵,則表示可以修改前一個單元的內容。
    ----------------------小抄結束------------------------------
    ?
    5、使用DOS時,匯編用戶可以從DOS操作系統中得到什么?

    ??? 現在編程,通常很多功能都是通過調用系統API。很多高級語言都直接把這些API包裝起來,以系統接口或函數的方式提供給用戶,那么匯編函數都能得到什么呢?
    ??? 首先,匯編用戶有很多東西可以調用。他們主要是:
    ?
    ??? 5.1 BIOS提供的接口。現在硬件與軟件的區分已越來越不明顯,很多硬件不僅僅是電路,而還要提供一些固化寫入硬件的一部分“程序”,這些程序以ROM的方式出現,匯編用戶最大的好處就是可以直接使用這些“程序”,這些使用不僅功能強大,而且效率非常高。
    ?
    ??? 5.2 DOS功能調用,作為操作系統也象BIOS一樣向用戶提供了相應的“程序”。這些程序在很大程序上擴充了BIOS。與BIOS不同的是,這部分程序放在內存中,它可以被修改。而BIOS中不能再修改。
    ??? ==========================================================
    ??? 以上兩種接口都通過一種相同的格式調用,這些程序統稱為“中斷”,現在先不要理解中斷的本意,你現在可以認為是系統提供給你的函數。
    ??? ============================================================
    ?
    ??? 5.3 系統共享數據區。編過程序的人都知道全局變量的好處,全局變量方便之外在于任何函數、過程都可以調用、讀取、修改。全局變量不足之處是危險性,有一個過程改了這個變量值,其它的也得跟著改變了。DOS操作系統同樣也提供了這樣的共享數據區,該區是整個系統的共享區,任何程序都可以查找、修改。當然,修改某處必然會對其它程序造成影響。
    ?
    6、再談中斷

    ??? 前面5.2已提到中斷了,現在問題是不同硬件不一樣,即使相同硬件的ROM,不同版本,各個BIOS中斷程序所處的位置也不一樣。DOS中斷也一樣,不同版本、不同配置,在內存位置也不一樣。那么你使用某一個中斷,系統怎么知道你使用的那個中斷程序在哪呢?
    ??? 為了解決這一問題,DOS會在啟動的時候,把所有這些(BIOS和DOS)中斷的首地址保存到一個地址。這個地址很容易記,這段地址是內存的絕對零地址(0000:0000)。前面已講過,每個地址在匯編程序員角度來看是二維的,也就是分為段地址和偏移地址。每個地址各占兩個字節,所以要表示這個二維地址需要4個字節。所以每個中斷首地址由4個字節表示。一共256個中斷,占用了1024個字節的位置。
    ??? 另外需要注意的是,這4個表示地址的字節,數據是由低向高的。比如12 34 56 78所表示的地址是:7856:3412。
    ?
    ??? 一般用INT M表示中斷M,如果M是十六進制,則在后面加上一個H。比如19號中斷,十六進制應該是13H。所以該中斷就是INT 13H。

    7、再談系統共享數據區

    ??? 該共享數據區在絕對地址:0040:0000開始。
    ?
    8、驗證我上面說的內容
    ?
    ??? 8.1 找中斷
    ?
    ??? 運行DEBUG后。輸入D 0000:0000。顯示絕對零地址的內容。
    C:\>debug
    -d 0:0
    0000:0000? 68 10 A7 00 8B 01 70 00-16 00 9B 03 8B 01 70 00? h.....p.......p.
    0000:0010? 8B 01 70 00 B9 06 0E 02-40 07 0E 02 FF 03 0E 02? ..p.....@.......
    0000:0020? 46 07 0E 02 0A 04 0E 02-3A 00 9B 03 54 00 9B 03? F.......:...T...
    0000:0030? 6E 00 9B 03 88 00 9B 03-A2 00 9B 03 FF 03 0E 02? n...............
    0000:0040? A9 08 0E 02 99 09 0E 02-9F 09 0E 02 5D 04 0E 02? ............]...
    0000:0050? A5 09 0E 02 0D 02 DC 02-B8 09 0E 02 8B 05 0E 02? ................
    0000:0060? 02 0C 0E 02 08 0C 0E 02-13 0C 0E 02 AD 06 0E 02? ................
    0000:0070? AD 06 0E 02 A4 F0 00 F0-37 05 0E 02 71 84 00 C0? ........7...q...
    -u 0070:018B
    0070:018B 1E??????????? PUSH??? DS
    0070:018C 50??????????? PUSH??? AX
    0070:018D B84000??????? MOV????AX,0040
    0070:0190 8ED8????????? MOV????DS,AX
    0070:0192 F70614030024? TEST??? WORD PTR [0314],2400
    0070:0198 754F????????? JNZ????01E9
    0070:019A 55??????????? PUSH??? BP
    0070:019B 8BEC????????? MOV????BP,SP
    0070:019D 8B460A??????? MOV????AX,[BP+0A]
    0070:01A0 5D??????????? POP????BP
    0070:01A1 A90001??????? TEST??? AX,0100
    0070:01A4 7543????????? JNZ????01E9
    0070:01A6 A90002??????? TEST??? AX,0200
    0070:01A9 7422????????? JZ????? 01CD
    ??? 首先,D命令把中斷首地址顯示出來。每4個表示一個地址。其中INT 0的中斷首地址為:00A7:1068,INT 1的中斷地址為:0070:018B.......0070:018B是中斷3的首地址。后面那個U命令就表示顯示該地址的“中斷程序”的內存。
    ?
    ??? 你們可以試著找找INT 13H的位置在哪。
    ?
    ??? 8.2 驗證系統共享數據區
    ?
    ??? 系統共享數據區內容極為豐富,我實在記不住哪么多了。我曾記在一個本上,可惜那個本早在N年前(3<N<6)就丟了。兄弟們誰找到這個地址的內容,一定要貼上來,這里有東西可以讓大家眼界大開。
    ??? 前幾年,我用的286計算機是黑白顯示器(555555~~~~~~~~~,別嫌我老、舊、慢呀),可當時有個游戲非要彩顯,不是彩顯不讓運行。我就是改了這個區的某一個位,讓哪游戲“以為”我用的是彩顯,于是游戲能用了。雖然不好看,但總能用。
    ??? 在DOS下,你每按一個鍵,系統都會記下來,下面我們一起找找這個鍵盤緩沖區的地址。知道這個地址,你就可以作一個“虛擬”鍵盤,通過發命令來模擬某個人在按鍵。這個地址位于:0040:001E。 其中每個鍵有兩個字節,一個字節是ASCII碼,一個是掃描碼。共16個。
    ?
    C:\>debug
    -d 40:0
    0040:0000? F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F? ..........x.x...
    0040:0010? 22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 20 39? "....(....*.*. 9
    0040:0020? 34 05 30 0B 3A 27 30 0B-0D 1C 64 20 20 39 34 05? 4.0.:'0...d? 94.
    0040:0030? 30 0B 3A 27 30 0B 0D 1C-71 10 0D 1C 64 20 00 00? 0.:'0...q...d ..
    0040:0040? A2 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00? ..........P.....
    0040:0050? 00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    0040:0060? 0F 0C 00 D4 03 29 30 7F-03 00 C0 00 A1 B7 11 00? .....)0.........
    0040:0070? 00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01? ................
    -d 0040:0000
    0040:0000? F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F? ..........x.x...
    0040:0010? 22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 3A 27? "....(....*.*.:'
    0040:0020? 30 0B 30 0B 30 0B 30 0B-0D 1C 64 20 20 39 30 0B? 0.0.0.0...d? 90.
    0040:0030? 30 0B 30 0B 30 0B 08 0E-08 0E 34 05 30 0B 00 00? 0.0.0.....4.0...
    0040:0040? 1F 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00? ..........P.....
    0040:0050? 00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00? ................
    0040:0060? 0F 0C 00 D4 03 29 30 7F-03 00 C0 00 24 B8 11 00? .....)0.....$...
    0040:0070? 00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01? ................
    -
    ??? 既然是鍵盤緩沖區,每個輸入的鍵都會顯示在該區中,第一次我只輸入了“d 40:0”,所以你可以在此后顯示數據右邊字符中找到這些字符,注意是間隔開的。
    ??? 第二次我輸入“d 0040:0000”,則右邊顯示的是“d 0040:0000”的內容。你可以找找。
    ?
    ?
    第二講 內存映象
    ?

    ??? 之所以把這個內存單獨放一章,是為了說明它的重要性,后面的幾乎很多程序都需要你對這一章的理解。這里的內存映象就是指當你把一個可執行文件(EXE或COM文件)放到內存后,整個內存“看”起來是什么樣子的。
    ?
    ??? 前面講過,這里匯編程序只能訪問1M的內存空間,所以下面就以1M內存為例。并且以DOS操作系統作為講解對象,所以所編出來的程序也僅是DOS程序。事實上,通過winasm可以訪問遠遠超過1M的空間,并且可以編出FOR windows的程序。但那是另外的話題。我們暫且不說那些。

    2.1內存映象

    ??? 首先,這1M內存如果我們不再以二維的方式看,而是一維的,線性地看(二維和一維的轉化方式參見前面章節)。但描述還是以二維的方式描述,從最底端到最高端依次是:
    ??? 1) 中斷向量區:該區由0000:0000~0000:03FF。這里存著系統的所有中斷的中斷向量表對于中斷向量表,你現在先理解為一些程序的首地址。由這個地址你就能找到該程序。
    ??? 2) 系統數據區:該區由0040:0000~0040:XXXX (不好意思,忘了),這里存著整個系統中,DOS操作系統要用的數據,由于這個區的數據對用戶是開放的,所以用戶當然也可以從這里讀出來用。
    ??? 3) DOS操作系統區:操作系統常駐內存,你向計算機發的每個命令其實都是操作系統執行的。這個區的大小主要是由操作系統的版本和用戶的配置大小決定,如果是驅動程序配置,就放到根目錄下的config.sys里,如果是程序,就放到autoexec.bat里。這里設置在現在的windows 95/98/nt/me/2000/xp/2003中仍然有,所以我就不多說了。
    ??? 4) 用戶程序:這個當然就是你執行的程序了,這種程序分兩種,一種是擴展名為com文件,一種是exe文件從程序內部看,前者程序的四個段重合(后面要講這四個段),所以最大長度只等于一個段,用前面段地址的理解就是com文件最大只能是64K,所以com文件只適合小的程序。而exe,四個段可任何分配,并可擴充段,而且每個段的段地址可以任何改動,因此exe的訪問內存能力大多了。這種格式訪問能力只受地址結構的限制了。
    ??? 用戶程序所占的內存大小完全由程序本身決定,但最大,只能到640K。這一點,怪不得別人,只能怪當前計算機軟硬件設置高手高手高高手們(包括比爾蓋茨)們的失誤了,60年代的超級計算機只有36K的內存,所以他們就在80年代得到一個結論:640K的內存足夠了。
    ??? 如果用戶程序大于由操作系統所占內存的頂底到640K之間的內存量,就會顯示:內存不夠,因而程序不能執行。這種現象對于一開始就用windows的人來說,幾乎沒見過,但對于一開始用DOS并打漢字的人來說,再正常不過。如果小于這段內存,多余部分就空著。
    ??? 5) 從640K到1M-64K,這段內存就很難說清了。這段內存中有一部分被硬件占有,有一部分是顯示緩沖區點有,還有一部分是系統ROM占有。
    ??? 6) 從1M-64K到1M之間的這段64K的內存叫作HMA。這段內存是小孩沒娘,說來話長,我們先不說他。
    ???
    2.2 驗證上面的理論
    ?
    ??? 2.2.1 中斷向量表
    ?
    ??? 中斷向量表就是所有中斷向量首地址表,這里保存著每個中斷程序的首地址,幾乎所有的匯編書都把中斷放到后面的章節中,并且對中斷的解釋也僅從字面意思解釋,所以導致大學對中斷的不重要和誤解。沒耐心的沒到這個章節就不學匯編了,有耐心的到這里才豁然開朗。我現在不講中斷的原意。我直接告訴你,你把中斷當成API也許更合適。也就是說,別人把很多已作好的功能放到了內存中。并且把調用這一功能的號告訴了你,你只要調用這些功能號,系統就自動從這個中斷向量表中找到對應的中斷,然后執行你的功能。
    ?
    ??? 首先讓你感受一下中斷的魅力一下吧。比如中斷21H的2A功能調用是讀取系統的日期,這個調用的規則是,調用前AH寄存器置為2A。調用后年在CX中,月在DH中,DL在日中,星期在AL中。
    -a
    139D:0100 mov ah,2a
    139D:0102 int 21
    139D:0104 int 3
    139D:0105
    -g=100
    ?

    AX=2A05? BX=0000? CX=07D4? DX=0C18? SP=FFEE? BP=0000? SI=0000? DI=0000
    DS=139D? ES=139D? SS=139D? CS=139D? IP=0104? NV UP EI PL NZ NA PO NC
    139D:0104 CC??????????? INT??? 3
    -

    ??? 可能上面的程序你目前還看不懂。不過沒關系,“mov ah,2a”表示調用功能號是2a的API。“int 21”表示調用十六進制21號中斷,“int 3”表示3號中斷,表示程序運行到這一句時停一下。“g=100”表示從“139D:0100 ”開始執行。
    ??? AX=2A05? BX=0000? CX=07D4? DX=0C18? SP=FFEE? BP=0000? SI=0000? DI=0000
    ??? DS=139D? ES=139D? SS=139D? CS=139D? IP=0104? NV UP EI PL NZ NA PO NC
    ??? 表示執行的結果。其中CX是年,這個年是由CX中存。07D4十進制就是2004年。DH+DL=DX,所以DH=0C,DL=18。二者轉化為十進制就是DH=12,DL=24,也就是今天了。AX=AH+AL=2A05,所以AL=05。那就是今天是星期五。
    ??? 上面可能你們現在還看不懂,不過通過解說你應該可以知道,僅僅兩行命令,就讀到了現在的值。現在需要作的就是把這些值提取出來用作他用了。
    ?
    ??? 從中斷的作來與中斷向量表又有什么關系呢?原來你在匯編里運行int 21時,系統就在上面的中斷向量表中找到int 21的中斷地址,該中斷的地址應該位于: 0000:0084~0000:0087,具體算法前面已說明了。
    -d 0000:0084 0087
    0000:0080????????????? 7C 10 A7 00????????????????????????????? |...
    -

    ??? 找到內容是:00A7:107C。然后系統就轉到這個地址執行int 21。
    ?
    ??? 2.2.2 系統數據區
    ?
    ??? 前面都已說明過。不再多說。系統區,很多DOS中斷程序實現部分就在這個區。程序運行區依不同的程序而不用。
    ?
    ??? 2.2.3 640K~1M之間
    ?
    ??? 這期間有些地方是ROM,有些地方是硬件的BIOS區。我僅以兩個例子說明這一區。
    ?
    ??? ROM區 :ROM區就是只讀內存,也就是說這個區的數據只能讀不能寫。比如F000:0000開始的內存是ROM。我們來寫一下,然后再看看效果。
    ?
    -d f000:0000 0005??--顯示由F000:0000到F000:0005的六個字節值
    F000:0000? 04 E8 A2 FF F9 C3??????????????????????????????? ......
    -e f000:0000????--修改命令
    F000:0000? 04.00? E8.00? A2.00? FF.00? F9.00? C3.00?? --注意,.后面的是我改的,把這幾個值都改成0了。
    ?
    -d f000:0000 0005?? --再次顯示這個區的數據。
    F000:0000? 04 E8 A2 FF F9 C3??????????????????????????????? ......
    -
    ??? 通過上面測試,發現該區數據仍然未改變。但你要是試別的RAM區的,肯定會變。如果想試你自己試試吧。
    ?
    ??? 顯示緩沖區 :在文本方式下,B800:0000開始的地址保存著屏幕上每個字符位置的值。在文本方式下,屏幕被分為80×25。每個位置有兩個值,一個值是ASCII字符,一個值是該ASCII的屬性值(主要是顏色)。所以一個屏幕共有80×25×2=400個字符。
    ??? 我們來改:
    -d b800:0000 0010?? --顯示屏幕緩沖區的內容,注意此時本行最左邊的“-”是屏幕左上角。
    B800:0000? 2D 07 64 07 20 07 62 07-38 07 30 07 30 07 3A 07? -.d. .b.8.0.0.:.
    B800:0010? 30??????????????????????????????????????????????? 0
    -
    ??? 看上面的命令,屏幕最上邊一行是“-d b800:0000 0010”,所以他的內容就是“2D 07 64 07 20 07 62 07-38 07 30 07 30 07 3A 07”其中,2D是“-”的ASCII值,07是“-”的屬性值。64是“d”的ASCII值,07是“d”的屬性值。。。。。
    ??? 現在修改這些值。我把左上角的字改成黃顏色的“-”,那當然是改b800:0001的屬性值了。
    -e b800:0001? 0e
    ??? 是不是左上角的顏色變成黃色了嗎?
    ??? 好了,把第二個字符變成綠色的“-”吧?
    -e b800:0002 2d 0b
    ??? 變了嗎?
    ?
    2.3 可執行文件內存映象
    ?
    ??? DOS下可執行文件有兩種(BAT是批處理文件,他只是簡單調用DOS內部命令或其它程序,所以此處不認為它是可執行文件):一種是COM文件,一種是EXE文件,前面提到,COM文件一般小于64K。EXE文件則可以任意大。為什么呢?
    ??? 說到這里,還要提到段。每個段64K。段的作用就是數據組織單位。段的類型有三種:代碼段(Code Segment,簡稱CS)、數據段(Data Segment,簡稱DS)、棧段(Stack Segment,簡稱SS),另外還有一個附加數據段(Extra Segment,簡稱ES),它的用與數據段DS可以認為完全一樣,當數據段的64K不夠用,或你就需要把數據放到兩個段中以便移動、復制、比較時,才用到附加數據段ES。(當然,移動、復制、比較操作在一個段中也可以完成)
    ?
    ??? 1.段的作用
    ?
    ??? 1.1 代碼段(CS):程序裝入內存中,DOS怎么知道是從哪里執行呢?答案就是系統自動從代碼段指定位置開始執行,并且始終在代碼段中執行。因此代碼段CS的作用就是保存所有的指令。這里所說的代碼也就是匯編指令了。所以編寫匯編程序也就主要是編寫代碼段中的代碼。
    ?
    ??? 1.2 數據段(DS)、附加段(ES):顧名思義,數據段中存的就是數據,這些數據供代碼段的程序調用。附加段就是附加數據段。作用與數據段相同。
    ?
    ??? 1.3 棧段(SS):這個段非常重要,但實際上,你在使用中,似乎用不著這個段,但實際上,這是黑客編程中最重要的一部分,而且系統會不停地“偷偷地”使用這個段,正是這個偷偷地用,使得系統的很多動作被記錄到這個段中。還有兩點,你必須記住:一是如果你使用了這個棧,比如你把數據存到這個棧中,則必須有相應的出棧命令,并且入幾個數據,就得出幾個數據,多一個或少一個,你的程序就可能導致死機或異常;二是你要把握操作時機,比如你不能在系統使用棧的前后使用棧,比如你在調用子程序之前入棧,而在子程序中出棧,而在系統調用子程序時,系統也要使用棧,這種也將導致出錯。
    ??? 棧就是一種先入后出(也有稱為后入先出)的結構,有地址由小到大的增加棧,有地址由大到小的逆向減棧。
    ?
    ??? 2.段重疊
    ?
    ??? 從上面,我們可以看到,CS,DS,SS三者作用各不相同,內存就是象錄音磁帶,錄新歌,則舊歌被刪,帶子上存的始終是最后錄的那段音樂。因此,如果重疊則必然相互沖突。那還能重疊嗎?
    ??? 這里所說的重疊不是指內容重疊,而是指概念上的重疊,即數據相互放到一個段中,但相互可以區分開。比如某一段既有數據也有代碼,則代碼在每要執行到數據之前加一個跳轉指令跳過這段代碼。這個跳轉指令要求用戶在編程的時候加上。
    ??? 而棧段呢?棧段有自己的特殊性,特殊就在于系統也會自動地使用,而用戶則又在不知道系統在使用的情況下使用。避免這種沖突的方法就是采用逆向的棧段。
    ?
    ???? 3 .COM文件內存映象

    ??? COM文件被讀到內存中后,該文件的前100H個字節被操作系統使用,操作系統使用這256個字節保存一些系統要使用的數據,匯編語言編程者不能在這里存自己的數據,但在知道這此數據的作用后可以使用其中的數據。從100H開始,就是程序的開始了。COM文件之所以最大只能有64K,其原因是COM文件的四個段是相互重疊的。也就是說,CS、DS、SS、ES四個段的地址都指向這個COM文件的100H處。程序代碼、數據、棧都在由100H到64K的區域內。如何把三者分開呢?棧段采用逆向棧,這個棧由64K開始,隨著數據入棧,則地址就減小。這樣作的好處是,棧段由高端向低端進展,可以詳細與數據、代碼分開;壞處也不言而喻,假如一個COM程序大量用到棧(比如是個遞歸程序)因此棧就不停地降低,而程序代碼本身也很多,甚至不停地申請新空間,這樣數據和棧就會在中間碰頭,導致程序被破壞。
    ??? 區分開數據代碼段與棧段后,下面討論把數據段和代碼段也分開。這個簡單的多,只要邏輯上分開就可以。不過一般的方法就是:在100H處放一個跳轉指令,隨后放數據,然后再放置其它的代碼。而100H處的跳轉指令就跳到這里。
    ??? 因此,COM文件內存映象就是:
    ??? CS:0000??? (由于COM的CS,DS,SS,ES三段重疊,因此此行前CS,寫成DS,SS,ES都一樣)??
    ??? CS:0100??? 一個跳轉到YYYY地址的跳轉指令。
    ??? CS:0101??? 本程序所需要用到的數據
    ??? CS:XXXX??? 數據結束處。
    ??? CS:YYYY??? 程序代碼保存處。
    ??? CS:ZZZZ??? 程序代碼結束處。
    ??? CS:FFFF??? 棧段開始處(注意棧是地址越來越小,所以這里是開始而不是結束處),也是程序的結束處。另外,此處FFFF與前面XXXX,YYYY,ZZZZ不一樣,這里是十六進制的64K。
    ?
    ??? 4.EXE文件

    ??? 比起COM文件,EXE文件要復雜一些,他的復雜就在于COM文件前面規定了100H個字節用于系統使用,而EXE文件則有個文件頭,文件頭的大小看具體內容多少。文件頭的內容使得EXE看起來復雜了,但也更靈活了。更重要的是,對于病毒設計者,這個文件頭使他們如魚得水。因為文件頭處
    ??? EXE文件的內存映象為:
    ??? XXXX:0000 文件頭
    ??? XXXX:YYYY 文件頭結束處
    ?
    ??? CS:0000 代碼段開始處
    ??? CS:ZZZZ 代碼段結束處
    ?
    ??? DS:0000 數據碼段開始處
    ??? DS:WWWW 數據碼段結束處
    ?
    ??? SS:0000 棧段開始處
    ??? SS:UUUU 棧段結束處
    ?
    ??? ES:0000 附加段開始處
    ??? ES:VVVV 附加段結束處
    ?
    ??? 說明:
    ??? 1) 上述ES可以沒有,要看實際需要
    ??? 2) CS,DS,ES,SS的順序也是看編程者是怎么安排的,好在用戶不必關心他的具體位置。
    ??? 3) 由上可見,CS,DS,ES,SS的段地址肯定保存到了文件頭中。
    ??? 4) 由上可見,實際執行的只是CS,因此DS,ES,SS的首地址,CS肯定要想辦法知道。:)
    ?
    ?
    第三講 匯編指令
    ?

    3.1 什么是機器語言
    ?
    ??? 前面提到“最早的計算機采用機器語言,這種語言直接用二進制數表示,通過直接輸入二進制數,插拔電路板等實現,這種‘編程’很容易出錯,每個命令都是通過查命令表實現”。
    ??? 比如要執行21號中斷,需要查表,得到21號中斷的指令就是CD 21。這樣不管你通過什么方式,在內存指令位置,寫入兩個字節,一個是CD(這可不是音樂光盤,而是二進制數,轉成十進制就是205),另一個是21(同樣是十六進制,十進制是33)
    ??? 上面就是機器語言。
    ?
    3.2 什么是匯編語言

    ??? 前面也提到“既然是通過‘查表’實現的,那當然也可以讓計算機來代替人查表實現了。于是就產生了匯編語言”,匯編語言產生的重要目的就是用容易記的符號來代替容易出錯的二進制數(或十六進制數)
    ??? 比如前面的21號中斷,機器語言是CD 21。而匯編語言就規定中斷用int表示(interrupt的前三個字母),21號中斷就成了int 21h。其中21后面的h表示是表示這個21是十六進制。由于大小寫不敏感,所以int 21h寫成下列方式都等價:
    ??? int 33
    ??? Int 21h
    ??? INT 21H
    ?
    3.3 匯編指令集

    一、數據傳輸指令?
    -----------------------------------------------------------------
    它們在存貯器和寄存器、寄存器和輸入輸出端口之間傳送數據.
    1. 通用數據傳送指令.
    MOV???? 傳送字或字節.
    MOVSX?? 先符號擴展,再傳送.
    MOVZX?? 先零擴展,再傳送.
    PUSH??? 把字壓入堆棧.
    POP???? 把字彈出堆棧.
    PUSHA?? 把AX,CX,DX,BX,SP,BP,SI,DI依次壓入堆棧.
    POPA??? 把DI,SI,BP,SP,BX,DX,CX,AX依次彈出堆棧.
    PUSHAD?把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次壓入堆棧.
    POPAD?? 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次彈出堆棧.
    BSWAP?? 交換32位寄存器里字節的順序
    XCHG??? 交換字或字節.( 至少有一個操作數為寄存器,段寄存器不可作為操作數)
    CMPXCHG 比較并交換操作數.( 第二個操作數必須為累加器AL/AX/EAX )
    XADD??? 先交換再累加.( 結果在第一個操作數里 )
    XLAT??? 字節查表轉換.
    BX????? 指向一張 256 字節的表的起點, AL 為表的索引值 (0-255,即0-FFH); 返回 AL 為查表結果. ( [BX+AL]->AL )
    2. 輸入輸出端口傳送指令.
    IN?I/O端口輸入. ( 語法: IN 累加器, {端口號│DX} )
    OUT I/O端口輸出. ( 語法: OUT {端口號│DX},累加器 )
    輸入輸出端口由立即方式指定時, 其范圍是 0-255; 由寄存器 DX 指定時,
    其范圍是 0-65535.
    3. 目的地址傳送指令.
    LEA 裝入有效地址.
    例: LEA DX,string ;把偏移地址存到DX.
    LDS 傳送目標指針,把指針內容裝入DS.
    例: LDS SI,string ;把段地址:偏移地址存到DS:SI.
    LES 傳送目標指針,把指針內容裝入ES.
    例: LES DI,string ;把段地址:偏移地址存到ES:DI.
    LFS 傳送目標指針,把指針內容裝入FS.
    例: LFS DI,string ;把段地址:偏移地址存到FS:DI.
    LGS 傳送目標指針,把指針內容裝入GS.
    例: LGS DI,string ;把段地址:偏移地址存到GS:DI.
    LSS 傳送目標指針,把指針內容裝入SS.
    例: LSS DI,string ;把段地址:偏移地址存到SS:DI.
    4. 標志傳送指令.
    LAHF 標志寄存器傳送,把標志裝入AH.
    SAHF 標志寄存器傳送,把AH內容裝入標志寄存器.
    PUSHF 標志入棧.
    POPF 標志出棧.
    PUSHD 32位標志入棧.
    POPD 32位標志出棧.

    二、算術運算指令
    -----------------------------------------------------------------
    ADD?加法.
    ADC?帶進位加法.
    INC?加 1.
    AAA?加法的ASCII碼調整.
    DAA?加法的十進制調整.
    SUB?減法.
    SBB?帶借位減法.
    DEC?減 1.
    NEC?求反(以 0 減之).
    CMP?比較.(兩操作數作減法,僅修改標志位,不回送結果).
    AAS?減法的ASCII碼調整.
    DAS?減法的十進制調整.
    MUL?無符號乘法.
    IMUL 整數乘法.?
    ???? --以上兩條,結果回送AH和AL(字節運算),或DX和AX(字運算),

    AAM?乘法的ASCII碼調整.
    DIV?無符號除法.
    IDIV 整數除法.?
    ???? --以上兩條,結果回送: 商回送AL,余數回送AH, (字節運算);
    ???????????????????? 或 商回送AX,余數回送DX, (字運算).
    AAD?除法的ASCII碼調整.
    CBW?字節轉換為字. (把AL中字節的符號擴展到AH中去)
    CWD?字轉換為雙字. (把AX中的字的符號擴展到DX中去)
    CWDE 字轉換為雙字. (把AX中的字符號擴展到EAX中去)
    CDQ?雙字擴展. (把EAX中的字的符號擴展到EDX中去)
    ?
    三、邏輯運算指令
    -----------------------------------------------------------------
    AND?與運算.
    OR?? 或運算.
    XOR?異或運算.
    NOT?取反.
    TEST 測試.(兩操作數作與運算,僅修改標志位,不回送結果).
    SHL?邏輯左移.
    SAL?算術左移.(=SHL)
    SHR?邏輯右移.
    SAR?算術右移.(=SHR)
    ROL?循環左移.
    ROR?循環右移.
    RCL?通過進位的循環左移.
    RCR?通過進位的循環右移.?
    ???? --以上八種移位指令,其移位次數可達255次.
    移位一次時, 可直接用操作碼. 如 SHL AX,1.
    移位>1次時, 則由寄存器CL給出移位次數.
    如 MOV CL,04
    SHL AX,CL
    ?
    四、串指令
    -----------------------------------------------------------------
    DS:SI 源串段寄存器 :源串變址.
    ES:DI 目標串段寄存器:目標串變址.
    CX??? 重復次數計數器.
    AL/AX 掃描值.
    D標志?0表示重復操作中SI和DI應自動增量; 1表示應自動減量.
    Z標志?用來控制掃描或比較操作的結束.
    MOVS?串傳送.
    ( MOVSB 傳送字符. MOVSW 傳送字. MOVSD 傳送雙字. )
    CMPS?串比較.
    ( CMPSB 比較字符. CMPSW 比較字. )
    SCAS?串掃描.
    把AL或AX的內容與目標串作比較,比較結果反映在標志位.
    LODS?裝入串.?
    ( 把源串中的元素(字或字節)逐一裝入AL或AX中.?)
    ( LODSB 傳送字符. LODSW 傳送字. LODSD 傳送雙字. )
    STOS?保存串.
    是LODS的逆過程.
    REP???????? 當CX/ECX<>0時重復.
    REPE/REPZ?? 當ZF=1或比較結果相等,且CX/ECX<>0時重復.
    REPNE/REPNZ 當ZF=0或比較結果不相等,且CX/ECX<>0時重復.
    REPC????????當CF=1且CX/ECX<>0時重復.
    REPNC?????? 當CF=0且CX/ECX<>0時重復.
    ?
    五、程序轉移指令
    -----------------------------------------------------------------
    1>無條件轉移指令 (長轉移)
    JMP 無條件轉移指令
    CALL 過程調用
    RET/RETF過程返回.

    2>條件轉移指令 (短轉移,-128到+127的距離內)
    ( 當且僅當(SF XOR OF)=1時,OP1<OP2 )
    JA/JNBE 不小于或不等于時轉移.
    JAE/JNB 大于或等于轉移.
    JB/JNAE 小于轉移.
    JBE/JNA 小于或等于轉移.
    以上四條,測試無符號整數運算的結果(標志C和Z).
    JG/JNLE 大于轉移.
    JGE/JNL 大于或等于轉移.
    JL/JNGE 小于轉移.
    JLE/JNG 小于或等于轉移.
    以上四條,測試帶符號整數運算的結果(標志S,O和Z).
    JE/JZ 等于轉移.
    JNE/JNZ 不等于時轉移.
    JC 有進位時轉移.
    JNC 無進位時轉移.
    JNO 不溢出時轉移.
    JNP/JPO 奇偶性為奇數時轉移.
    JNS 符號位為 "0" 時轉移.
    JO 溢出轉移.
    JP/JPE 奇偶性為偶數時轉移.
    JS 符號位為 "1" 時轉移.

    3>循環控制指令(短轉移)
    LOOP CX不為零時循環.
    LOOPE/LOOPZ CX不為零且標志Z=1時循環.
    LOOPNE/LOOPNZ CX不為零且標志Z=0時循環.
    JCXZ CX為零時轉移.
    JECXZ ECX為零時轉移.

    4>中斷指令
    INT 中斷指令
    INTO 溢出中斷
    IRET 中斷返回

    5>處理器控制指令
    HLT 處理器暫停, 直到出現中斷或復位信號才繼續.
    WAIT 當芯片引線TEST為高電平時使CPU進入等待狀態.
    ESC 轉換到外處理器.
    LOCK 封鎖總線.
    NOP 空操作.
    STC 置進位標志位.
    CLC 清進位標志位.
    CMC 進位標志取反.
    STD 置方向標志位.
    CLD 清方向標志位.
    STI 置中斷允許位.
    CLI 清中斷允許位.

    六、偽指令
    -----------------------------------------------------------------
    DW????? 定義字(2字節).
    PROC??? 定義過程.
    ENDP??? 過程結束.
    SEGMENT 定義段.
    ASSUME?建立段寄存器尋址.
    ENDS??? 段結束.
    END???? 程序結束.
    ?

    3.4 再談寄存器和內存的區別
    ?
    ??? 第零講說到“寄存器在CPU中。內存在內存條中。前者的速度比后者快100倍左右。后面的程序要求每條指定要么沒有內存數據,要么在有一個寄存器的參與下有一個內存數據。(也就是說,不存在只訪問內存的指令)
    ??? 寄存器是在CPU中的存儲器,而內存是在內存條中的存儲器。CPU訪問寄存器,只需要通過微指令直接就可以訪問,而訪問內存則要先經過總線,再由總線到達內存控制器,讀到某單元的內存數據后放上總線,再傳到CPU中,CPU才能使用。
    ??? 8086系列計算機的寄存器,共有14個,每個都是十六位的。
    ??? AX,BX,CX,DX,SP,BP,SI,DI,CS,DS,SS,ES,IP,FLAGS。
    ??? 其中前四位,每個可以單位再分成兩個,AX=AH+AL,BX=BH+BL,CX=CH+CL,DX=DH+DL。這些分開的每個都是8位的。
    ??? 這個分開不要理解成平時語言中的分開,你可以理解為AX是由AH和AL組合成的,你給AL付值,就意味著同時給AX的低半部付值。你給AX付值,就意味著同時改變AH和AL。這樣作的好處是你可以更靈活地控制這個寄存器。
    ?
    3.5 指令說明

    ??? 看了3.3的指令集和3.4的寄存器,是不是已經暈了,或者了迷糊?不要急,上面的東西雖然多,我也沒讓你一下學會,(其實有些永遠也不會似乎也不是什么大不了的事)。為了應付看的懂我后面所說的,我把其中的指令挑幾個重點的,你必須要記住,其它的慢慢學吧。
    ?
    1.數據傳輸指令
    ?
    ??? mov A,B?
    ??? 注意不是move,這個指令是把B中的數據復制給A,(B中仍保存原狀)。這里的A和B可以是寄存器,可以是內存。但可以同時是寄存器,不能同時是內存。比如
    ?
    ??? mov ax,100; 這是對的,注意100在這里叫立即數,但這個數在編譯系統編譯成exe的時候保存在內存中。如果學過別的高級語言,你就可以理解為這就是賦值語句 Let ax=100/ax:=100;/ax=100。

    2.偽指令

    ??? 偽指令就是不是真的指令,但他同時又是指令。之所以說這樣矛盾的話,是因為偽指令不是機器語言的一部分,而是匯編語言的一部分,是你告訴匯編的編譯系統如何去作。
    ??? string DB '這是我的第一個匯編語言程序$'
    ??? 上面一行指令中,DB就是偽指令,他的作用就是告訴編譯程序,把后面一些數據或字符串放到內存中。當然對于exe來說,已在內存中了,就不用“告訴”了。(這就是為什么叫偽指令)。string是你給這段內存起的名字,如果你不需要這段內存,不起名字也可以,但如果后面要用,當然要加上這個名字。'這是我的第一個匯編語言程序$'這個就是要處理的數據,當然你也可以換成別的內容,但需要注意的是,要以'$'結尾,這是匯編的約寫,即:只是到了$,就認為字符串結束,否則就一直向下找,直到找到一個$為止。所以這就要求你的字符串中不能有'$',如果必須有,再換別的處理方式,后面再說。
    ?
    3.地址傳送指令
    ?
    ??? Lea A,string
    ??? 前面已經定義了string,后面要把地址找到,就要用到lea指令。lea是把字符串的地址給A這個寄存器中,A當然可以上前面提到的任意寄存器。注意地址和內容的區別。如果是內容就是把string的字符串給A了。(當然這也不成立,一個字符串有很多字節,而一個寄存器只有兩個字節)
    ??? 那么從上面也看到了,string代表一個地址,lea把這個地址給了A,那這個地址到底在哪里呢?事實上這不重要,就象你要把某書店買書,這個書店在哪并不是最重要的,有沒有你要的書才是最重要的。所以你前面標出string,后面引用就行了,至于這個地址到底在哪是編譯程序的事,不是你的事。

    4.運算指令

    ??? ADD A,N
    ??? 這個很容易理解吧,寄存器A加上N,把和仍存在A中。類似于高級語言中的let a=a+n/a:=a+n/a+=n。
    ?
    5.串操作指令

    ??? 記住串操作指令表面很復雜,其實很簡單。
    ??? 因為他就象一個復雜的數學公式一樣簡單,你所要記住的就是公式的格式,使用時具體套用即可。
    ??? 從一個地址到另一個地址的復制需要注意的是:
    ??? *)把源串段地址給DS。
    ??? *)把源串編址給SI。
    ??? *)把目的串段址給ES。
    ??? *)把目的串偏址給DI。
    ??? *)把要復制的個數給CX,這里可不考慮$了。
    ??? *)把FLAG中的方向標志標志你要的方向,一個是順向,另一個是逆向。
    ??? *)發送loop movs,scans等命令。

    6.轉移指令

    ??? 記住:無條件轉移指令 jmp。等于轉 jz,不等于時轉jnz
    ?
    7.中斷指令
    ?
    ??? int 中斷號,注意進制,默認是十進制,所以十六進制就加h。
    ?
    ??? 好了,上面的指令變成七八個了,這你不能嫌多了吧,如果再嫌多就不要繼續向下看了。
    ?
    ?
    第四講 匯編程序
    ?
    ?
    4.1 匯編程序框架
    ?
    ??? data SEGMENT?'數據段,編程者可以把數據都放到這個段里
    ??? ....數據部分....? '數據格式是: 標識符 db/dw 數據。
    ??? data ENDS? '數據段結束處。
    ?
    ??? edata SEGMENT?'附加數據段,編程者可以把數據都放到這個段里
    ??? ....附加數據部分....
    ??? edata ENDS? '附加數據段結束處。
    ?
    ??? code SEGMENT? '代碼段,實際的程序都是放這個段里。
    ??????? ASSUME CS:code,DS:data,ES:edata?'告訴編譯程序,data段是數據段DS,code段是代碼段CS
    ?
    ??? start:MOV AX,data?'前面的start表示一個標識位,后面用到該位,如果用不到,就可以不加
    ??????? MOV DS,AX?'這一句與上一行共同組成把data賦值給DS。段寄存器.
    ??????? MOV AX,edata?
    ??????? MOV ES,AX?'與前一句共同組成edata->ES
    ??????? ....程序部分....
    ??????? MOV AX,4C00h? '程序退出,該句內存由下一行決定。退出時,要求ah必須是4c。
    ??????? INT 21h
    ??? code ENDS? '代碼段結束。
    ??? END start? '整個程序結束,并且程序執行時由start那個位置開始執行。
    ?
    ??? 上面就是一個程序的框架結構。在這個結構中,有三個段,DS、ES、CS。這三個段分別存數據、附加數據、代碼段。
    ?
    4.2 編寫我們的Hello,world思路

    ??? 開始編寫我們的第一個程序。
    ??? 程序要求:顯示一個“Hello,Mr.286.”怎么樣?
    ??? 思路:
    ??? 1 要顯示一個字符串,根據前面我讓你們記的七八個指令夠嗎?答案是:不僅夠,而且還用不完。
    ??? 首先定義一下總可以吧。
    ?
    ??? hellostr db 'Hello,Mr.286.$'
    ??? 最后的$不要忘了。
    ?
    ??? 2 首先要考慮的問題就是找中斷,找到合適的中斷,該中斷就能幫我們完成這個顯示任務。我找到(在哪找到的,怎么找到的,別問我,到網上或書上都能找到)
    ??? -------------------------------------------
    ??? 中斷INT 21H功能09H
    ?
    ??? 功能描述: 輸出一個字符串到標準輸出設備上。如果輸出操作被重定向,那么,將無法判斷磁盤已滿?
    ??? 入口參數: AH=09H
    ??? DS:DX=待輸出字符的地址
    ??? 說明:待顯示的字符串以'$'作為其結束標志?
    ??? 出口參數: 無?
    ??? -------------------------------------------?
    ??? 由上面看到,我們所需要作的就是把DS指向數據段,DX指向字符串的地址,AH等于9H,調用21h中斷。
    ??? mov ds,數據段地址
    ??? lea dx,hellostr?'hellostr已在前面1中定義了。
    ??? mov ah,9h
    ??? int 21h
    ??? 由于只要在調用int 21h之前把準備的東西準備齊就行了,所以int 21h前面三行的順序并不重要。
    ?
    ??? 3 退出程序,運行完總要退出呀。再查中斷手冊
    ??? --------------------------------------------
    ??? 中斷INT 21H功能4CH
    ?
    ??? 功能描述: 終止程序的執行,并可返回一個代碼?
    ??? 入口參數: AH=4CH
    ??? AL=返回的代碼?
    ??? 出口參數: 無
    ??? --------------------------------------------
    ??? mov ah,4Ch
    ??? mov al,0
    ??? int 21h
    ???
    ??? mov ax,4c00h
    ??? int 21h
    ??? 這里需要說明的是返回代碼有什么用,返回給誰?返回給操作系統,因為是操作系統DOS調用的這個程序,這個返回值可以通過批處理中的errorlevel得到,這里不多說明,實際上操作系統很少處理這一值,因此al你隨便寫什么值影響都不大。
    ?
    4.3 程序實現

    ??? data SEGMENT
    ??? msg DB 'Hello, Mr.286.$'
    ??? data ENDS
    ?
    ??? code SEGMENT
    ??????? ASSUME CS:code,DS:data
    ??? start:MOV AX,data
    ????????? MOV DS,AX
    ????????? lea dx,msg?
    ????????? mov ah,9h
    ????????? int 21h
    ????????? MOV AX,4C00h
    ????????? INT 21h
    ?
    ??? code ENDS
    ??? END start

    4.4 編譯運行

    ??? 把上面程序保存成hello286.asm后,就可以編譯運行了。進入DOS,進入匯編目錄,如果還沒下載,到前面找下載地址。
    ?
    ??? =================================================
    ??? E:\Download\Masm>masm hello286.asm
    ??? Microsoft (R) Macro Assembler Version 5.00
    ??? Copyright (C) Microsoft Corp 1981-1985, 1987.? All rights reserved.
    ?
    ??? Object filename [hello286.OBJ]:
    ??? Source listing? [NUL.LST]:
    ??? Cross-reference [NUL.CRF]:
    ?
    ????? 50408 + 415320 Bytes symbol space free
    ?
    ????????? 0 Warning Errors
    ????????? 0 Severe? Errors
    ??? 說明:上面連續三個回車,表示我要的都是默認值。下面是零個警告,零個嚴重錯誤,(當然了,我的程序還敢錯嗎?)
    ?
    ??? E:\Download\Masm>link hello286
    ?
    ??? Microsoft (R) Overlay Linker? Version 3.60
    ??? Copyright (C) Microsoft Corp 1983-1987.? All rights reserved.
    ?
    ??? Run File [HELLO286.EXE]:
    ??? List File [NUL.MAP]:
    ??? Libraries [.LIB]:
    ??? LINK : warning L4021: no stack segment
    ?
    ??? 說明:三個回車仍要默認,后面有個警告,沒有棧段,這個沒關系,沒有的話系統會自動給一個。
    ?
    ??? E:\Download\Masm>hello286
    ??? Hello, Mr.286.
    ??? 說明:運行成功。
    ??? E:\Download\Masm>
    4.4 深度思考
    ??? 4.4.1 是不是數據必須放數據段,代碼必段放代碼段呢?
    ??? 答,代碼必段放代碼段,否則你怎么執行呀?但數據也可以放到代碼段,只是程序要作修改。
    ??? code SEGMENT
    ???????? ASSUME CS:code,DS:data
    ???????? msg DB 'Hello, Mr.286.$'
    ??? start:MOV AX,data
    ????????? MOV DS,AX
    ????????? lea dx,msg?
    ????????? mov ah,9h
    ????????? int 21h
    ????????? MOV AX,4C00h
    ????????? INT 21h
    ??? code ENDS
    ??? END start
    ??? 編譯后仍然可以。
    ??? 4.4.2 我編的程序在內存中是什么樣子的呢?
    ??? ------------------------------------------------------------------------
    ??? E:\Download\Masm>debug hello286.exe
    ??? -u
    ??? 1420:0000 B81F14??????? MOV??? AX,141F
    ??? 1420:0003 8ED8????????? MOV??? DS,AX
    ??? 1420:0005 8D160000????? LEA??? DX,[0000]
    ??? 1420:0009 B409????????? MOV??? AH,09
    ??? 1420:000B CD21????????? INT??? 21
    ??? 1420:000D B8004C??????? MOV??? AX,4C00
    ??? 1420:0010 CD21????????? INT??? 21
    ??? 1420:0012 FF362421????? PUSH??? [2124]
    ?
    ??? 1420:0016 E87763??????? CALL??? 6390
    ??? 1420:0019 83C406??????? ADD??? SP,+06
    ??? 1420:001C FF362421????? PUSH??? [2124]
    ??? -d 141f:0000 L20
    ??? 141F:0000? 48 65 6C 6C 6F 2C 20 4D-72 2E 32 38 36 2E 24 00? Hello, Mr.286.$.
    ??? 141F:0010? B8 1F 14 8E D8 8D 16 00-00 B4 09 CD 21 B8 00 4C? ............!..L
    ??? -q
    ?
    ??? E:\Download\Masm>
    ??? ------------------------------------------------------------------------------
    ??? 上面是什么呀?還記得前面說的嗎?
    ??? 1420:0000 B81F14??????? MOV??? AX,141F
    ????? |? |????? |??????????? |???????|
    ??? 段址:偏址?機器語言????? mov指令 把段地址的地址(141f)賦值給AX寄存器。
    ?
    ??? 1420:0012后面的是垃圾數據,不用管它,把上面程序與源程序作一個比較,看有什么不用,差別在于把標號語言轉成實際地址了。
    ??? 程序前兩行一執行,數據段地址就變成了141f,而那個字符串偏移地址在0000,由(LEA??? DX,[0000]看出),所以我用-d 141f:0000 L20(后面L20表示只顯示20個字節),就能把段地址顯示出來了。
    ??? 所以剛才的程序在內存中就變成了:
    ??? 141f:0000 Hello, Mr.286.$? ----->這是段地址里的內存
    ??? 1420:0000 B81F14??????? MOV??? AX,141F? ------>這是代碼段里的內存。data變成了實際地址
    ??? 1420:0003 8ED8????????? MOV??? DS,AX
    ??? 1420:0005 8D160000????? LEA??? DX,[0000] ------>偏址變成了0000,因為實際上msg也就是從頭開始的。當然是0了。
    ??? 1420:0009 B409????????? MOV??? AH,09??? ------->注意Debug里,默認的是十六進制
    ??? 1420:000B CD21????????? INT??? 21
    ??? 1420:000D B8004C??????? MOV??? AX,4C00
    ??? 1420:0010 CD21????????? INT??? 21
    ?

    ?
    ?




    -The End-

    posted on 2009-05-17 23:18 decode360-3 閱讀(11484) 評論(2)  編輯  收藏 所屬分類: The Others

    評論

    # re: 匯編基礎入門知識 2009-09-17 23:56 Jassize
    太感謝了 回去慢慢啃了……  回復  更多評論
      

    # re: 匯編基礎入門知識 2014-05-23 11:00 Crystal_C++
    win7的f000:0000 0005 可以修改、  回復  更多評論
      

    主站蜘蛛池模板: 精品无码国产污污污免费网站| 精品日韩亚洲AV无码一区二区三区| 久久久久久夜精品精品免费啦| 另类专区另类专区亚洲| 亚洲综合激情另类小说区| 亚洲一本大道无码av天堂| 毛片免费观看的视频在线| 在线成人爽a毛片免费软件| 两个人www免费高清视频| 免费一区二区三区在线视频| 亚洲国产乱码最新视频| 亚洲福利一区二区精品秒拍| 亚洲gv猛男gv无码男同短文| 亚洲日韩AV一区二区三区中文| 亚洲国产美国国产综合一区二区| 国产精品爱啪在线线免费观看| 亚洲AV网一区二区三区| 色偷偷女男人的天堂亚洲网| 久久精品国产亚洲av高清漫画| 久久伊人久久亚洲综合| 亚洲色精品vr一区二区三区| 亚洲国产精品13p| 亚洲福利中文字幕在线网址| 国产无遮挡吃胸膜奶免费看视频 | 免费观看一级毛片| 在线观看视频免费完整版| 一级毛片免费在线| 未满十八私人高清免费影院| 国产在亚洲线视频观看| 亚洲高清国产拍精品熟女| 亚洲国产综合AV在线观看| 亚洲AV无码一区二区三区网址| 亚洲精品无码久久久久秋霞| 亚洲色一区二区三区四区| 亚洲精品一二三区| 亚洲日韩乱码中文字幕| 亚洲av日韩综合一区二区三区| 亚洲αⅴ无码乱码在线观看性色 | 国产v片免费播放| 亚洲A丁香五香天堂网| 亚洲精品一级无码鲁丝片|