【匯編基礎】1.基礎知識
1.1機器語言
說到匯編語言的產生,首先要講一下機器語言。機器語言是機器指令的集合。機器指令展開來講就是一臺機器可以正確執(zhí)行的命令。電子計算機的機器指令是一列二進制數(shù)字。計算機將之轉變?yōu)橐涣懈叩碗娖剑允褂嬎銠C的電子器件受到驅動,進行運算。
上面所說的計算機指的是可以執(zhí)行機器指令,進行運算的機器。這是早期計算機的概念。現(xiàn)在,在我們常用的PC機中,有一個芯片來完成上面所說的計算機的功能。這個芯片就是我們常說的CPU(Central Processing Unit,中央處理單元),CPU是一種微處理器。以后我們提到的計算機是指由CPU和其他受CPU直接或間接控制的芯片、器件、設備組成的計算機系統(tǒng),比如我們最常見的PC機。
每一種微處理器,由于硬件設計和內部結構的不同,就需要用不同的電平脈沖來控制,使它工作。所以每一種微處理器都有自己的機器指令集,也就是機器語言。
早期的程序設計均使用機器語言。程序員們將用0、1數(shù)字編成的程序代碼打在紙帶或卡片上,1打孔,0不打孔,再將程序通過紙帶機或卡片機輸入計算機,進行運算。
早期的程序設計均使用機器語言。程序員們將用0、1數(shù)字編成的程序代碼打在紙帶或卡片上,1打孔,0不打孔,再將程序通過紙帶機或卡片機輸入計算機,進行運算。
應用8086CPU完成運算s=768+12288-1280,機器碼如下。
101110000000000000000011000001010000000000110000001011010000000000000101
假如將程序錯寫成以下這樣,請你找出錯誤。
101100000000000000000011000001010000000000110000000101101000000000000101
書寫和閱讀機器碼程序不是一件簡單的工作,要記住所有抽象的二進制碼。上面只是一個非常簡單的小程序,就暴露了機器碼的晦澀難懂和不易查錯。寫如此小的一個程序尚且如此,實際上一個有用的程序至少要有幾十行機器碼,那么,情況將怎么樣呢?
在顯示器上輸出“welcome to masm”,機器碼如下。
00011110 101110000000000000000000 01010000 101110001100011000001111 1000111011011000 1011010000000110 1011000000000000 1011011100000111 101110010000000000000000 1011011000011000 1011001001001111 1100110100010000 1011010000000010 1011011100000000 1011011000000000 1011001000000000 1100110100010000 1011010000001001 10001101000101100010101000000000 1100110100100001 1011010000001010 10001101000101100011000100000000 1100110100100001 1011010000000110 1011000000010100 1011011100011001 1011010100001011 1011000100010011 1011011000001101 1011001000111100 1100110100010000 1011010000000010 1011011100000000 1011000000001100 1011001000010100 1100110100010000 1011010000001001 10001101000101100000000000000000 1100110100100001 11001011
看到這樣的程序,你有什么感想?如果程序里有一個“1”被誤寫為“0”,又如何去查找呢?
1.2 匯編語言的產生
早期的程序員們很快就發(fā)現(xiàn)了使用機器語言帶來的麻煩,它是如此難于辨別和記憶,給整個產業(yè)的發(fā)展帶來了障礙。于是匯編語言產生了。
匯編語言的主體是匯編指令。匯編指令和機器指令的差別在于指令的表示方法上。匯編指令是機器指令便于記憶的書寫格式。
例如:機器指令1000100111011000表示把寄存器BX的內容送到AX中。匯編指令則寫成mov ax,bx。這樣的寫法與人類語言接近,便于閱讀和記憶。
操作:寄存器BX的內容送到AX中 機器指令:1000100111011000 匯編指令:mov ax,bx
(寄存器,簡單地講是CPU中可以存儲數(shù)據(jù)的器件,一個CPU中有多個寄存器。AX是其中一個寄存器的代號,BX是另一個寄存器的代號。更詳細的內容我們在以后的課程中將會講到。)
此后,程序員們就用匯編指令編寫源程序。可是,計算機能讀懂的只有機器指令,那么如何讓計算機執(zhí)行程序員用匯編指令編寫的程序呢?這時,就需要有一個能夠將匯編指令轉換成機器指令的翻譯程序,這樣的程序我們稱其為編譯器。程序員用匯編語言寫出源程序,再用匯編編譯器將其編譯為機器碼,由計算機最終執(zhí)行。圖1.1描述了這個工作過程。
1.3 匯編語言的組成
匯編語言發(fā)展至今,有以下3類指令組成。
(1)匯編指令:機器碼的助記符,有對應的機器碼。
(2)偽指令:沒有對應的機器碼,由編譯器執(zhí)行,計算機并不執(zhí)行。
(3)其他符號:如+、一、*、/ 等,由編譯器識別,沒有對應的機器碼。
匯編語言的核心是匯編指令,它決定了匯編語言的特性。
1.4 存儲器
CPU是計算機的核心部件,它控制整個計算機的運作并進行運算。要想讓一個CPU工作,就必須向它提供指令和數(shù)據(jù)。指令和數(shù)據(jù)在存儲器中存放,也就是我們平時所說的內存。在一臺PC機中內存的作用僅次于CPU。離開了內存,性能再好的CPU也無法工作。這就像再聰明的大腦,沒有了記憶也無法進行思考。磁盤不同于內存,磁盤上的數(shù)據(jù)或程序如果不讀到內存中,就無法被CPU使用。要靈活地利用匯編語言編程,我們首先要了解CPU是如何從內存中讀取信息,以及向內存中寫入信息的。
1.5 指令和數(shù)據(jù)
指令和數(shù)據(jù)是應用上的概念。在內存或磁盤上,指令和數(shù)據(jù)沒有任何區(qū)別,都是二進制信息。CPU在工作的時候把有的信息看作指令,有的信息看作數(shù)據(jù),為同樣的信息賦予了不同的意義。就像圍棋的棋子,在棋盒里的時候沒有任何區(qū)別,在對弈的時候就有了不同的意義。
1.6 存儲單元
存儲器被劃分成若干個存儲單元,每個存儲單元從0開始順序編號,例如一個存儲器有128個存儲單元,編號從0~127,如圖1.2所示。
那么一個存儲單元能存儲多少信息呢?我們知道電子計算機的最小信息單位是bit(音譯為比特),也就是一個二進制位。8個bit組成一個Byte,也就是通常講的一個字節(jié)。微型機存儲器的存儲單元可以存儲一個Byte,即8個二進制位。一個存儲器有128個存儲單元,它可以存儲128個Byte。
微機存儲器的容量是以字節(jié)為最小單位來計算的。對于擁有128個存儲單元的存儲器,我們可以說,它的容量是128個字節(jié)。
對于大容量的存儲器一般還用以下單位來計量容量(以下用B來代表Byte):
1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB
磁盤的容量單位同內存的一樣,實際上以上單位是微機中常用的計量單位。
1.7 CPU對存儲器的讀寫
以上講到,存儲器被劃分成多個存儲單元,存儲單元從零開始順序編號。這些編號可以看作存儲單元在存儲器中的地址。就像一條街,每個房子都有門牌號碼。
CPU要從內存中讀數(shù)據(jù),首先要指定存儲單元的地址。也就是說它要先確定它要讀取哪一個存儲單元中的數(shù)據(jù)。就像在一條街上找人,先要確定他住在哪個房子里。
另外,在一臺微機中,不只有存儲器這一種器件。CPU在讀寫數(shù)據(jù)時還要指明,它要對哪一個器件進行操作,進行哪種操作,是從中讀出數(shù)據(jù),還是向里面寫入數(shù)據(jù)。
可見,CPU要想進行數(shù)據(jù)的讀寫,必須和外部器件(標準的說法是芯片)進行下面3類信息的交互。
- 存儲單元的地址(地址信息)
- 器件的選擇,讀或寫的命令(控制信息)
- 讀或寫的數(shù)據(jù)(數(shù)據(jù)信息)
那么CPU是通過什么將地址、數(shù)據(jù)和控制信息傳到存儲器芯片中的呢?電子計算機能處理、傳輸?shù)男畔⒍际请娦盘枺娦盘柈斎灰脤Ь€傳送。在計算機中專門有連接CPU和其他芯片的導線,通常稱為總線。總線從物理上來講,就是一根根導線的集合。
根據(jù)傳送信息的不同,總線從邏輯上又分為3類,地址總線、控制總線和數(shù)據(jù)總線。
CPU從3號單元中讀取數(shù)據(jù)的過程(見圖1.3)如下。
(1)CPU通過地址線將地址信息3發(fā)出。
(2)CPU通過控制線發(fā)出內存讀命令,選中存儲器芯片,并通知它,將要從中讀取數(shù)據(jù)。
(3)存儲器將3號單元中的數(shù)據(jù)8通過數(shù)據(jù)線送入CPU。
寫操作與讀操作的步驟相似。如向3號單元寫入數(shù)據(jù)26。
(1)CPU通過地址線將地址信息3發(fā)出。
(2)CPU通過控制線發(fā)出內存寫命令,選中存儲器芯片,并通知它,要向其中寫入數(shù)據(jù)。
(3)CPU通過數(shù)據(jù)線將數(shù)據(jù)26送入內存的3號單元中。
從上面我們知道了CPU是如何進行數(shù)據(jù)讀寫的。可是,如何命令計算機進行數(shù)據(jù)的讀寫呢?
要讓一個計算機或微處理器工作,應向它輸入能夠驅動它進行工作的電平信息(機器碼)。
對于8086CPU,下面的機器碼,能夠完成從3號單元讀數(shù)據(jù)。
機器碼:101000010000001100000000 含義:從3號單元讀取數(shù)據(jù)送入寄存器AX
CPU接收這條機器碼后將完成我們上面所述的讀寫工作。
機器碼難于記憶,用匯編指令來表示,情況如下。
機器碼:101000010000001100000000 對應的匯編指令:MOV AX,[3] 含義:傳送3號單元的內容入AX
1.8 地址總線
現(xiàn)在我們知道,CPU是通過地址總線來指定存儲器單元的。可見地址總線上能傳送多少個不同的信息,CPU就可以對多少個存儲單元進行尋址。
現(xiàn)假設,一個CPU有10根地址總線,讓我們來看一下它的尋址情況。我們知道,在電子計算機中,一根導線可以傳送的穩(wěn)定狀態(tài)只有兩種,高電平或是低電平。用二進制表示就是1或0,10根導線可以傳送10位二進制數(shù)據(jù)。而10位二進制數(shù)可以表示多少個不同的數(shù)據(jù)呢?2的10次方個。最小數(shù)為0,最大數(shù)為1023。
圖1.4展示了一個具有10根地址線的CPU向內存發(fā)出地址信息11時10根地址線上傳送的二進制信息。考慮一下,訪問地址為12、13、14等的內存單元時,地址總線上傳送的內容是什么?
一個CPU有N根地址線,則可以說這個CPU的地址總線的寬度為N。這樣的CPU最多可以尋找2的N次方個內存單元。
1.9 數(shù)據(jù)總線
CPU與內存或其他器件之間的數(shù)據(jù)傳送是通過數(shù)據(jù)總線來進行的。數(shù)據(jù)總線的寬度決定了CPU和外界的數(shù)據(jù)傳送速度。8根數(shù)據(jù)總線一次可傳送一個8位二進制數(shù)據(jù)(即一個字節(jié))。16根數(shù)據(jù)總線一次可傳送兩個字節(jié)。
8088CPU的數(shù)據(jù)總線寬度為8,8086CPU的數(shù)據(jù)總線寬度為16。我們來分別看一下它們向內存中寫入數(shù)據(jù)89D8H時,是如何通過數(shù)據(jù)總線傳送數(shù)據(jù)的。圖1.5展示了8088CPU數(shù)據(jù)總線上的數(shù)據(jù)傳送情況;圖1.6展示了8086CPU數(shù)據(jù)總線上的數(shù)據(jù)傳送情況。
8088CPU分兩次傳送89D8,第一次傳送D8,第二次傳送89。
8086有16根數(shù)據(jù)線,可一次傳送16位數(shù)據(jù),所以可一次傳送數(shù)據(jù)89D8H;而8088只有8根數(shù)據(jù)線,一次只能傳8位數(shù)據(jù),所以向內存寫入數(shù)據(jù)89D8H時需要進行兩次數(shù)據(jù)傳送。
1.10 控制總線
CPU對外部器件的控制是通過控制總線來進行的。在這里控制總線是個總稱,控制總線是一些不同控制線的集合。有多少根控制總線,就意味著CPU提供了對外部器件的多少種控制。所以,控制總線的寬度決定了CPU對外部器件的控制能力。
前面所講的內存讀或寫命令是由幾根控制線綜合發(fā)出的,其中有一根稱為“讀信號輸出”的控制線負責由CPU向外傳送讀信號,CPU向該控制線上輸出低電平表示將要讀取數(shù)據(jù);有一根稱為“寫信號輸出”的控制線則負責傳送寫信號。
1.11 內存地址空間(概述)
什么是內存地址空間呢?舉例來講,一個CPU的地址總線寬度為10,那么可以尋址1024個內存單元,這1024個可尋到的內存單元就構成這個CPU的內存地址空間。下面進行深入討論。首先需要介紹兩部分基本知識,主板和接口卡。
1.12 主板
在每一臺PC機中,都有一個主板,主板上有核心器件和一些主要器件,這些器件通過總線(地址總線、數(shù)據(jù)總線、控制總線)相連。這些器件有CPU、存儲器、外圍芯片組、擴展插槽等。擴展插槽上一般插有RAM內存條和各類接口卡。
1.13 接口卡
計算機系統(tǒng)中,所有可用程序控制其工作的設備,必須受到CPU的控制。CPU對外部設備都不能直接控制,如顯示器、音箱、打印機等。直接控制這些設備進行工作的是插在擴展插槽上的接口卡。擴展插槽通過總線和CPU相連,所以接口卡也通過總線同CPU相連。CPU可以直接控制這些接口卡,從而實現(xiàn)CPU對外設的間接控制。簡單地講,就是CPU通過總線向接口卡發(fā)送命令,接口卡根據(jù)CPU的命令控制外設進行工作。
1.14 各類存儲器芯片
一臺PC機中,裝有多個存儲器芯片,這些存儲器芯片從物理連接上看是獨立的、不同的器件。從讀寫屬性上看分為兩類:隨機存儲器(RAM)和只讀存儲器(ROM)。隨機存儲器可讀可寫,但必須帶電存儲,關機后存儲的內容丟失;只讀存儲器只能讀取不能寫入,關機后其中的內容不丟失。這些存儲器從功能和連接上又可分為以下幾類。
- 隨機存儲器。用于存放供CPU使用的絕大部分程序和數(shù)據(jù),主隨機存儲器一般由兩個位置上的RAM組成,裝在主板上RAM和插在擴展插槽上的RAM。
- 裝有BIOS(Basic Input/Output System,基本輸入/輸出系統(tǒng))的ROM BIOS是由主板和各類接口卡(如顯卡、網卡等)廠商提供的軟件系統(tǒng),可以通過它利用該硬件設備進行最基本的輸入輸出。在主板和某些接口卡上插有存儲相應BIOS的ROM。例如,主板上的ROM中存儲著主板的BIOS(通常稱為系統(tǒng)BIOS):顯卡上的ROM中存儲著顯卡的BIOS;如果網卡上裝有ROM,那其中就可以存儲網卡的 BIOS。
- 接口卡上的RAM某些接口卡需要對大批量輸入、輸出數(shù)據(jù)進行暫時存儲,在其上裝有RAM。最典型的是顯示卡上的RAM,一般稱為顯存。顯示卡隨時將顯存中的數(shù)據(jù)向顯示器上輸出。換句話說,我們將需要顯示的內容寫入顯存,就會出現(xiàn)在顯示器上。
1.15 內存地址空間
上述的那些存儲器,在物理上是獨立的器件,但是在以下兩點上相同。
- 都和CPU的總線相連。
- CPU對它們進行讀或寫的時候都通過控制線發(fā)出內存讀寫命令。
這也就是說,CPU在操控它們的時候,把它們都當作內存來對待,把它們總的看作一個由若干存儲單元組成的邏輯存儲器,這個邏輯存儲器就是我們所說的內存地址空間。
在匯編這門課中,我們所面對的是內存地址空間。
在圖中,所有的物理存儲器被看作一個由若干存儲單元組成的邏輯存儲器,每個物理存儲器在這個邏輯存儲器中占有一個地址段,即一段地址空間。CPU在這段地址空間中讀寫數(shù)據(jù),實際上就是在相對應的物理存儲器中讀寫數(shù)據(jù)。
假設,圖中的內存地址空間的地址段分配如下。
地址0~7FFFH的32KB空間為主隨機存儲器的地址空間:
地址8000H-9FFFH的8KB空間為顯存地址空間:
地址A000H-FFFFH的24KB空間為各個ROM的地址空間。
這樣,CPU向內存地址為1000H的內存單元中寫入數(shù)據(jù),這個數(shù)據(jù)就被寫入主隨機存儲器中;CPU向內存地址為8000H的內存單元中寫入數(shù)據(jù),這個數(shù)據(jù)就被寫入顯存中,然后會被顯卡輸出到顯示器上;CPU向內存地址為C000H的內存單元中寫入數(shù)據(jù)的操作是沒有結果的,C000H單元中的內容不會被改變,C000H單元實際上就是ROM存儲器中的一個單元。
內存地址空間的大小受CPU地址總線寬度的限制。8086CPU的地址總線寬度為20,可以傳送220個不同的地址信息(大小從0至220-1)。即可以定位220個內存單元,則8086PC的內存地址空間大小為lMB。同理,80386CPU的地址總線寬度為32,則內存地址空間最大為4GB。
我們在基于一個計算機硬件系統(tǒng)編程的時候,必須知道這個系統(tǒng)中的內存地址空間分配情況。因為當我們想在某類存儲器中讀寫數(shù)據(jù)的時候,必須知道它的第一個單元的地址和最后一個單元的地址,才能保證讀寫操作是在預期的存儲器中進行。比如,我們希望向顯示器輸出一段信息,那么必須將這段信息寫到顯存中,顯卡才能將它輸出到顯示器上。要向顯存中寫入數(shù)據(jù),必須知道顯存在內存地址空間中的地址。
不同的計算機系統(tǒng)的內存地址空間的分配情況是不同的,下圖展示了8086PC機內存地址空間分配的基本情況。
上圖告訴我們,從地址0-9FFFF的內存單元中讀取數(shù)據(jù),實際上就是在讀取主隨機存儲器中的數(shù)據(jù);向地址A0000-BFFFF的內存單元中寫數(shù)據(jù),就是向顯存中寫入數(shù)據(jù),這些數(shù)據(jù)會被顯示卡輸出到顯示器上;我們向地址C0000-FFFFF的內存單元中寫入數(shù)據(jù)的操作是無效的,因為這等于改寫只讀存儲器中的內容。
內存地址空間
最終運行程序的是CPU,我們用匯編語言編程的時候,必須要從CPU的角度考慮問題。對CPU來講,系統(tǒng)中的所有存儲器中的存儲單元都處于一個統(tǒng)一的邏輯存儲器中,它的容量受CPU尋址能力的限制。這個邏輯存儲器即是我們所說的內存地址空間。