文章目錄
- 引言
- 第一章 基礎知識
- 1.1 機器語言
- 1.2 彙編語言的產生
- 1.3 彙編語言的組成
- 1.4 存儲器
- 1.5 指令和數據
- 1.6 存儲單元
- 1.7 CPU對存儲器的讀寫
- 1.8 地址總線
- 1.9 數據總線
- 1.10 控制總線
- 1.11 內存地址空間(概述)
- 1.12 主板
- 1.13 接口卡
- 1.14 各類存儲器芯片
- 1.15 內存地址空間(詳解)
- 小結
- 第二章 寄存器(CPU工作原理)
- 2.1 通用寄存器
- 2.2 字在寄存器中的存儲
- 2.3 幾條彙編指令
- 2.4 物理地址
- 2.5 16位架構CPU
- 2.6 8086CPU給出物理地址的方法
- 2.7 “段地址X16+偏移地址=物理地址”的本質含義
- 2.8 段的概念
- 2.9 段寄存器
- 2.10 CS和IP
- 2.11 修改CS、IP的指令
- 2.12 代碼段
- 小結
- DEBUG
- 第三章 寄存器(內存訪問)
- 3.1 內存中字的存儲
- 3.2 DS和[address]
- 3.3 字的傳送
- 3.4 mov、add、sub指令
- 3.5 數據段
- 小結
- 3.6 棧
- 3.7 CPU提供的棧機制
- 3.8 棧頂超界的問題
- 3.9 push、pop指令
- 3.10 棧段
- 第四章 第一個程序
- 第五章 [BX]和loop指令
- 第六章 包含多個段的程序
- 第七章 更靈活的定位內存地址的方法
- and和or指令
- 關於ASCII碼
- 大小寫轉換的問題
- [bx+idata]
- 用[bx+idata]的方式進行數組的處理
- SI和DI
- [bx+si]和[bx+di]
- [bx+si+idata]和[bx+di+idata]
- 不同的尋址方式的靈活應用
- 第八章 數據處理的兩個基本問題
- 第九章 轉移指令的原理
- 待續待續
引言
- 彙編語言是直接在硬件之上工作的編程語言,首先要了解硬件系統的結構,纔能有效的應用彙編語言對其編程。
- 彙編課程的研究重點放在如何利用硬件系統的編程結構和指令集有效靈活的控制系統進行工作。
第一章 基礎知識
1.1 機器語言
- 機器語言是機器指令的集合
- 機器指令展開來講就是一臺機器可以正確執行的命令
1.2 彙編語言的產生
- 彙編語言的主體是彙編指令
- 彙編指令和機器指令的差別在於指令的表示方法上。彙編指令是機器指令便於記憶的書寫格式。
- 彙編指令是機器指令的助記符
機器指令:1000100111011000
操作:寄存器BX的內容送到AX中
彙編指令:MOV AX,BX
彙編這樣的寫法與人類語言接近,便於閱讀和記憶。
- 寄存器:簡單的講是CPU中可以存儲數據的器件。
AX,BX是其中的一個寄存器的代號
1.3 彙編語言的組成
- 彙編語言由以下3類組成:
- 彙編指令(機器碼的助記符)
- 僞指令(由編譯器執行)
- 其它符號
- 彙編語言的核心是彙編指令,它決定了彙編語言的特性
1.4 存儲器
- CPU 是計算機的核心部件,它控制整個計算機的運作並進行運算,要想讓一個CPU工作,就必須向它提供指令和數據
- 指令和數據在存儲器中存放,也就是平時所說的內存
- 在一臺PC機中內存的作用僅次於CPU
- 離開了內存,性能再好的CPU也無法工作
- 磁盤不同於內存,磁盤上的數據或程序如果不讀到內存中,就無法被CPU使用
1.5 指令和數據
- 指令和數據是應用上的概念
- 在內存或磁盤上,指令和數據沒有任何區別,都是二進制信息
二進制信息:1000100111011000------>89D8H(數據)
------->MOV AX,BX(程序)
1.6 存儲單元
- 存儲器被劃分爲若干個存儲單元,每個存儲單元從0開始順序編號;
例如:一個存儲器有128個存儲單元,編號從0-127。
- 對於大容量的存儲器一般還用以下單位來計量容量(以下用B來代表Byte):
- 1KB=1024B
- 1MB=1024KB
- 1GM=1024MB
- 1TB=1024GB
磁盤的容量單位同內存的一樣,實際上以上單位是微機中常用的計量單位。
1.7 CPU對存儲器的讀寫
- CPU要想進行數據的讀寫,必須和外部器件(標準說法是芯片)進行三類信息的交互
- 存儲單元的地址(地址信息)
- 器件的選擇,讀或寫命令(控制信息)
- 讀或寫的數據(數據信息)
那麼CPU是通過什麼將地址、數據和控制信息傳到存儲芯片中的呢?
- 電子計算機能處理、傳輸的信息都是電信號,電信號當然要用導線傳送
- 在計算機中專門有連接CPU和其它芯片的導線,通常稱爲總線
- 物理上:一根根導線的集合
- 邏輯上劃分爲:地址總線、數據總線、控制總線
1.8 地址總線
對於8086CPU,下面的機器碼能夠完成從3號單元讀數據:
- 機器碼:101000000000001100000000
- CPU是通過地址總線來指定存儲單元的
- 地址總線上能傳送多少個不同的信息,CPU就可以對多少個存儲單元進行尋址
- 一個CPU有N根地址總線,則可以說這個CPU的地址總線寬度爲N
- 這樣的CPU最多可以尋找2N個內存單元
1.9 數據總線
- CPU與內存或其它器件之間的數據傳送是通過數據總線來進行的
- 數據總線的寬度決定了CPU和外界的數據傳送速度
1.10 控制總線
- CPU對外部器件的控制是通過控制總線來進行的。這裏控制總線是總稱,控制總線式一些不同控制線的集合。
- 有多少根控制總線,就意味着CPU提供了對外部器件的多少種控制。所以,控制總線的寬度決定了CPU對外部器件的控制能力。
內存讀或寫命令是由幾根控制線綜合發出的:
- 其中有一根名爲讀信號輸出控制線負責由CPU向外傳送讀信號,CPU向該控制線上輸出低電平表示將要讀取數據
- 有一根名爲寫信號輸出控制線負責由CPU向外傳送寫信號
1.11 內存地址空間(概述)
什麼是內存地址空間?
- 一個CPU的地址線寬度爲10,那麼可以尋址1024個內存單元,這1024個可尋到的內存單元就構成這個CPU的內存地址空間
1.12 主板
- 在每一臺PC機中,都有一個主板,主板上有核心器件和一些主要器件。
- 這些器件通過總線(地址總線、數據總線、控制總線)相連
1.13 接口卡
- 計算機系統中所有可用程序控制其工作的設備,必須受到CPU的控制
- CPU對外部設備不能直接控制,如顯示器、音響、打印機等。直接控制這些設備進行工作的是擴展插槽上的接口卡。
1.14 各類存儲器芯片
- 從讀寫屬性上看分爲兩類:隨機存儲器(RAM)和只讀存儲器(ROM)
- 從功能和連接上分類:
- 隨機存儲器RAM
- 裝有BIOS的ROM
BIOS:Basic Input/Output System,基本輸入輸出系統
BIOS是由主板和各類接口卡(如:顯卡、網卡等)廠商提供的軟件系統,可以通過它利用該硬件設備進行最基本的輸入輸出。在主板和某些接口卡上插有存儲相應BIOS的ROM - 接口卡上的RAM
1.15 內存地址空間(詳解)
上述器件都有以下兩點相同:
- 都和CPU的總線相連
- CPU對它們進行讀或寫的時候通過控制線發出內存讀寫命令
將各類存儲器看作一個邏輯存儲器:
- 所有的物理存儲器被看作一個由若干存儲單元組成的邏輯存儲器
- 每個物理存儲器在這個邏輯存儲器中佔有一個地址段,即一段地址空間
- CPU在這段地址空間中讀寫數據,實際上就是在相對應的物理存儲器中讀寫數據。
不同的計算機系統的內存地址空間分配情況是不同的
內存地址空間:
- 最終運行程序的是CPU,我們用匯編編程的時候,必須要從CPU角度考慮問題
- 對CPU來講,系統中的所有存儲器中的存儲單元都處於一個統一的邏輯存儲器中,它的容量受CPU尋址能力的限制。這個邏輯存儲器即是我們所說的內存地址空間。
小結
- 彙編指令是機器指令的助記符,同機器指令一一對應。
- 每一種CPU都有自己的彙編指令集。
- CPU可以直接使用的信息在存儲器中存放。
- 在存儲器中指令和數據沒有任何區別,都是二進制信息。
- 存儲單元從零開始順序編號
- 一個存儲單元可以存儲8個bit(用作單位寫成"b"),即8位二進制數
- 1B=8b 1KB=1024B 1MB=1024KB 1GB=1024MB
- 每一個CPU芯片都有許多管腳,這些管腳和總線相連。也可以說,這些管腳引出總線。一個CPU可以引出三種總線的寬度標誌了這個CPU的不同方面的性能:1、地址總線的寬度決定了CPU的尋址能力; 2、數據總線的寬度決定了CPU與其它器件進行數據傳送時的一次數據傳送量; 3、控制總線寬度決定了CPU對系統中其它器件的控制能力。
第二章 寄存器(CPU工作原理)
2.1 通用寄存器
CPU概述
一個典型的CPU由運算器、控制器、寄存器等器件組成,這些器件靠內部總線相連。
區別
內部總線實現CPU內部各個器件之間的聯繫。
外部總系實現CPU和主板上其它器件的聯繫。
寄存器概述
8086CPU有14個寄存器,它們的名稱爲:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
8086CPU所有的寄存器都是16位的,可以存放兩個字節。
AX、BX、CX、DX通常用來存放一般性數據被稱爲通用寄存器。
2.2 字在寄存器中的存儲
一個字可以存在一個16位寄存器中,這個字的高位字節和地位字節自然就存在這個寄存器的高8位寄存器和低8位寄存器中。
關於數制的討論
- 由於一個內存單元可以存放8位數據,CPU中的寄存器又可以存放n個8位數據也就是說,計算機中的數據大多是由1~N個8位數據構成。
- 用十六進制來表示數據可以直觀的看出這個數據是由哪些8位數據構成的。每兩位對應一個八進制!
2.3 幾條彙編指令
彙編指令不區分大小寫。
彙編指令 | 控制CPU完成的操作 | 用高級語言的語法描述 |
---|---|---|
mov ax,18 | 將18送入AX | AX=18 |
mov ah,78 | 將78送入AH | AH=78 |
add ax,8 | 將寄存器AX中的數值加上8 | AX=AX+8 |
mov ax,bx | 將寄存器BX中的數據送入寄存器AX | AX=BX |
add ax,bx | 將AX,BX中的內容相加,結果存在AX中 | AX=AX+BX |
2.4 物理地址
- CPU訪問內存單元時要給出內存單元的地址。所有的內存單元構成的存儲空間是一個一維的線性空間。
- 我們將這個唯一的地址稱爲物理地址。
2.5 16位架構CPU
- 概括的講,16位結構描述了一個CPU具有以下幾個方面特徵:
- 運算器一次最多可以處理16位的數據
- 寄存器的最大寬度爲16位
- 寄存器和運算器之間的通路是16位的
2.6 8086CPU給出物理地址的方法
- 8086有20位地址總線,可傳送20位地址,尋址能力爲1M。
- 8086內部爲16位結構,它只能傳送16位的地址,表現出的尋址能力卻只有64K(216=64K)。
- 8086CPU採用一種在內部用兩個16位地址合成的方法來形成一個20位的物理地址。
2.7 “段地址X16+偏移地址=物理地址”的本質含義
“段地址X16”有一個更爲常用的說法就是數據左移4位。(二進制位)
把十六進制的數乘於16就相當於左移一位。
2.8 段的概念
錯誤的認識:
內存被劃分成了一個一個的段,每一個段有一個段地址。
其實:
內存並沒有分段,段的劃分來自於CPU,由於8086CPU用“段地址X16+偏移地址=物理地址”的方式給出內存單元的物理地址,使得我們可以用分段的方式來管理內存。
以後,在編程時可以根據需要,將若干地址連續的單元看作一個段,用段地址X16定位的起始地址(基礎地址),用偏移地址定位段中的內存單元。
兩點需要注意
- 段地址X16必然是16的倍數,所以一個段的起始地址也一定是16的倍數;
- 偏移地址爲16位,16位地址的尋址能力爲64K,所以一個段的長度最大爲64K。
內存單元地址小結
- CPU訪問內存單元時,必須向內存提供內存單元的物理地址
- 8086CPU在內部用段地址和偏移地址移位相加的方法形成最終的物理地址。
在8086PC機中,存儲單元的地址用兩個元素來描述,即段地址和偏移地址。
“數據在21F60H內存單元中。”對於8086PC機的兩種描述:
- 數據存在內存2000:1F60單元中
- 數據存在內存的2000段中的1F60H單元中
可以根據需要,將地址連續、起始地址爲16的倍數的一組內存單元定義爲一個段。
2.9 段寄存器
段寄存器就是提供段地址的。
8086CPU有4個段寄存器:CS、DS、SS、ES
當8086CPU要訪問內存時,由這4個段寄存器提供內存單元的段地址。
2.10 CS和IP
CS和IP是8086CPU中最關鍵的寄存器,它們指示了CPU當前要讀取指令的地址。
CS爲代碼段寄存器
IP爲指令寄存器
- 在8086CPU加電啓動或復位後(即CPU剛開始工作時)CS和IP被設置爲CS=FFFFH,IP=0000H
- 即在8086PC機剛啓動時,CPU從內存FFFF0H單元中讀取指令執行。
- FFFF0H單元中的指令是8086PC機開機後執行的第一條指令
- 在任何時候,CPU將CS、IP中的內容當作指令的段地址和偏移地址,用它們合成指令的物理地址,到內存中讀取指令碼,執行。
- 如果說,內存中的一段信息曾被CPU執行過的話,那麼,它所在的內存單元必然被CS:IP指向過。
2.11 修改CS、IP的指令
- 在CPU中,程序員能夠用指令讀寫的部件只有寄存器,程序員可以通過改變寄存器中的內容實現對CPU的控制。
- CPU從何處執行指令是由CS、IP中的內容決定的,程序員可以通過改變CS、IP中的內容來控制CPU執行目標指令。
mov指令可以改變8086CPU大部分寄存器的值,被稱爲傳送指令。
但是mov指令不能用於設置CS、IP的值,8086CPU沒有提供這樣的功能。
8086CPU爲CS、IP提供了另外的指令來改變它們的值:轉移指令
轉移指令
同時修改CS、IP的內容:
jmp 段地址 :偏移地址
jmp 2AE3:3
jmp 3:0B16
功能:用指令中給出的段地址修改CS,偏移地址修改IP。
2.12 代碼段
- 對於8086PC機,在編程時,可以根據需要,將一組內存單元定義爲一個段。
- 可以將長度爲N(N<=64KB)的一組代碼,存在一組地址連續、起始地址爲16的倍數的內存單元中,這段內存是用來存放代碼的從而定義了一個代碼段。
- 將一段內存當作代碼段,僅僅是我們在編程時的一種安排,CPU並不會由於這種安排,就自動地將我們定義得代碼段中的指令當作指令來執行。
- CPU只認被CS:IP指向的內存單元中的內容爲指令。
小結
段地址在8086CPU的寄存器中存放。當8086CPU要訪問內存時,由寄存器提供內存單元的段地址。8086CPU有4個段寄存器,其中CS用來存放指令的段地址。
CS存放指令的段地址,IP存放指令的偏移地址。
8086機中,任意時刻,CPU將CS:IP指向的內容當做指令執行。
8086CPU的工作過程:
- 從CS:IP指向內存單元讀取指令,讀取的指令進入指令緩衝器;
- IP指向下一條指令;
- 執行指令。(轉到步驟1,重複這個過程)
8086CPU提供轉移指令修改CS、IP的內容。jmp
DEBUG
在win10要下載其它文件才能使用,所以我開了臺win7的虛擬機來測試。
- R命令查看、改變CPU寄存器的內容;
- D命令查看內存中的內容;
- E命令改寫內存中的內容;
- U命令將內存中的機器指令翻譯成彙編指令;
- T命令執行一條機器指令;
- A命令以彙編指令的格式在內存中寫入一條機器指令;
書中的實驗 mov ax,1
add ax,ax
jmp 2000:0003
第三章 寄存器(內存訪問)
3.1 內存中字的存儲
任何兩個地址連續的內存單元,N號單元和N+1號單元,可以將它們看成兩個內存單元,也可以看成一個地址爲N的字單元中的高位字節單元和低位字節單元。
3.2 DS和[address]
- CPU要讀取一個內存單元的時候,必須先給出這個內存單元的地址;
- 在8086CPU中,內存地址由段地址和偏移地址組成。
- 8086CPU中有一個DS寄存器,通常用來存放要訪問的數據的段地址。
mov al,[0]
已知的mov指令可完成的兩種傳送功能:
- 將數據直接送入寄存器;
- 將一個寄存器中的內容送入另一個寄存器中。
除此之外,mov指令還可以將一個內存單元中的內容送入一個寄存器。
將內存單元送到寄存器中mov指令的格式:
mov 寄存器名,內存單元地址
“[…]”表示一個內存單元,“[…]”中的0表示內存單元的偏移地址。
主要過程:數據==》通用寄存器==》段寄存器
3.3 字的傳送
因爲8086CPU是16位結構,有16根數據線,所以,可以一次性傳送16位的數據,也就是一次性傳送一個字。
3.4 mov、add、sub指令
已學mov指令的幾種形式:
mov 寄存器,數據
mov 寄存器,寄存器
mov 寄存器,內存單元
mov 內存單元,寄存器
mov 段寄存器,寄存器
add、sub和mov指令一樣,都有兩個操作對象
3.5 數據段
我們可以將一組長度爲N(N<=64K)、地址連續、起始地址爲16的倍數的內存單元當作專門存儲數據的內存空間,從而定義了一個數據段。
將一段內存當作數據段,是我們在編程時的一種安排,我們可以在具體操作的時候,用DS存放數據段的段地址,再根據需要,用相關指令訪問數據段中的具體單元。
小結
- 字在內存中存儲時,要用兩個地址連續的內存單元存放,字的低位字節存放在低地址單元中,高位字節存放再高地址單元中
- 用mov指令要訪問單元,可以在mov指令中給出單元的偏移地址,此時,段地址默認在DS寄存器中
- [address]表示一個偏移地址爲address的內存單元
- 在內存和寄存器之間傳送字型數據時,高地址單元和高8位寄存器、低地址單元和低8位寄存器相對應
- mov、add、sub是具有兩個操作對象的指令。jmp是具有一個操作對象的指令
- 可以根據自己的推測,在Debug中實驗的新格式,winxp有,win10要裝插件
3.6 棧
棧是一種具有特殊的訪問方式的存儲空間。它的特殊性就在於,最後進入這個空間的數據,最先出去。
入棧和出棧
LIFO,Last In First Out
3.7 CPU提供的棧機制
現今CPU中都有棧設計
指令:
PUSH
POP
寄存器CS和IP中存放着當前指令的段地址和偏移地址。
8086CPU中有兩個寄存器,段寄存器SS:存放棧頂的段地址
寄存器SP:存放棧頂的偏移地址
任意時刻,SS:SP指向棧頂元素。
任意時刻,SS:SP指向棧頂元素,當棧爲空的時候,棧中沒有元素,也就不存在棧頂元素
所以SS:SP只能指向棧的最低部單元下面的單元,該單元的偏移地址爲棧最底部的字單元的偏移地址+2
棧最底部字單元的地址爲1000:000E,所以棧空時SP=0010H。
3.8 棧頂超界的問題
棧頂超界是危險的
8076CPU的工作原理,只考慮當前的情況:
- 當前棧頂在何處
- 當前要執行的指令是哪一條
3.9 push、pop指令
push和pop指令是可以在寄存器和內存之間傳送數據的。
push、pop等棧操作指令,修改的只是SP。也就是棧頂的變化範圍最大爲:0~FFFFH
SS、SP指棧頂;改變SP後寫內存的入棧指令;讀內存後改變SP的出棧指令。
這就是8086CPU提供的棧操作機制。
用棧來暫存以後需要恢復的寄存器的內容時,寄存器出棧的順序要和入棧的順序相反。
PUSH、POP實質上是一種內存傳送指令,注意它們的靈活運用。
3.10 棧段
跟數據段一樣,棧段。
將一段內存當作棧段,僅僅是我們在編程時的一種安排,CPU並不會由於這種安排,就在執行push、pop等棧操作指令時就自動地將我們定義的棧段當作棧空間來訪問。
- 棧爲空,就相當於棧中唯一的元素出棧,出棧後,SP=SP+2。
- SP原來爲FFFEH,加2後SP=0,所以,當棧爲空的時候,SS=1000H,SP=0。
不管我們如何安排,CPU將內存中的某段內存當作棧,是因爲CS:IP指向那裏;CPU將某段內存當作棧,是因爲SS:IP指向了那裏。
要非常的清楚CPU的工作機理,才能控制CPU來按照我們的安排,運行的時候做到遊刃有餘。
一段內存,可以既是代碼的存儲空間,又是數據空間,還可以是棧空間,也可以什麼也不是。
第四章 第一個程序
一個源程序從寫出到執行的過程
編寫==》編譯連接==》執行
源程序
- 彙編指令
- 有對應的機器碼的指令,可以被編譯爲機器指令,最終爲CPU所執行。
- 僞指令
- 僞指令是由編譯器來執行的指令,編譯器根據僞指令來進行相關的編譯工作
定義一個段
segment和ends是一對成對使用的僞指令,這是在寫可被編譯器編譯的彙編程序時,必須要用到的一對僞指令。
segment和ends的功能是定義一個段,segment說明一個段開始,ends說明一個段結束。
一個段必須有一個名稱來標識,使用格式爲:
段名 segment
段名 ends
一個彙編程序是由多個段組成的,這些段被用來存放代碼、數據或當作棧空間來使用。
一個有意義的彙編程序中至少要有一個段,這個段用來存放代碼。
End
End是一個彙編程序的結束標記,編譯器在編譯彙編程序的過程中,如果碰到了僞指令end,就結束對源程序的編譯。
如果程序寫完了,要在結尾處加上僞指令end。否則,編譯器在編譯程序時,無法知道程序在何處結束。
切記不要把end和ends搞錯
assume
含義爲假設,它假設某一段寄存器和程序中的某一個用segment…ends定義的段相關聯。
通過assume說明這種關係,在需要的情況下,編譯程序可以將段寄存器和某一個具體的段相聯繫。
源程序中的“程序”
彙編源程序:僞指令(編譯器處理)、彙編指令(編譯爲機器碼)
程序:源程序中最終由計算機執行、處理的指令或數據
注意:我們可以將源程序文件中的所有內容稱爲源程序,將源程序中最終由計算機執行處理的指令或數據,稱爲程序。
程序最先以彙編指令的形式存在源程序中經過編譯、連接後轉變爲機器碼,存儲在可執行文件中。
標號
- 一個標號指代了一個地址
- codesg:放在segment的前面,作爲一個段的名稱,這個段的名稱最終將被編譯、連接程序處理爲一個段的段地址
DOS中的程序運行
DOS是一個單任務操作系統。
- 一個程序P2在可執行文件中,則必須有一個正在運行的程序P1,將P2從可執行文件中加載如內存後,將CPU的控制權交給P2,P2才得以運行。P2開始運行後,P1暫停運行。
- 而當P2運行完畢後,應該將CPU的控制權交還給使它得以運行的程序P1,此後,P1繼續運行。
程序返回
一個程序結束後,將CPU的控制權交還給使它得以運行的程序,我們稱這個過程爲:程序返回。
編譯 and 連接
連接的作用:
-
當程序很大時,可以將它分爲多個源程序文件來編譯,每個源程序編譯成爲目標文件後,再用連接程序將它們連接到一起,生成一個可執行文件;
-
程序中調用了某個庫文件中的子程序,需要將這個庫文件和該程序生產的目標文件連接到一起,生成一個可執行文件;
編輯器(Edit)、編譯器(masm)、連接器(link)、調試工具(debug)等工具
可執行文件中的程序裝入內存並行的原理
- 一個程序P2在可執行文件中,則必須有一個正在運行的程序P1,將P2從可執行文件中加載如內存後,將CPU的控制權交給P2,P2才得以運行。P2開始運行後,P1暫停運行。
- 而當P2運行完畢後,應該將CPU的控制權交還給使它得以運行的程序P1,此後,P1繼續運行。
程序執行的跟蹤
操作系統的外殼
操作系統是由多個功能模塊組成的龐大、複雜的軟件系統。任何同用的操作系統,都要提供一個稱爲shell(外殼)的程序,用戶(操作人員)使用這個程序來操作計算機系統工作。
第五章 [BX]和loop指令
[bx]
我們要完整地描述一個內存單元,需要兩種信息:
- 內存單元地地址
- 內存單元地長度(類型)
我們用[0]表示一個內存單元時,0表示單元的偏移地址,段地址默認在ds中,單元的長度(類型)可以由具體指令中的其它操作對象(比如說寄存器)指出,如前邊的AX,AL。
[bx]同樣也表示一個內存單元,它的偏移地址在bx中。
Loop指令
指令的格式是:loop標號,CPU執行loop指令的時候,要進行兩步操作:
- [cx]=[cx]-1
- 判斷cx中的值,不爲零則轉至標號處執行程序,如果爲零則向下執行
計算22,結果存放在ax中。
assume cs:code
code segment
start: mov ax,2
add ax,ax
mov ax,4c00h
int 21h
code ends
end start
計算23
assume cs:code
code segment
start: mov ax,2
add ax,ax
add ax,ax
mov ax,4c00h
int 21h
code ends
end start
計算212,使用loop簡化代碼
assume cs:code
code segment
start: mov ax,2
mov cx,11
s: add ax,ax
loop s
mov ax,4c00h
int 21h
code ends
end start
分析s爲標號,它表示了一個地址,指令的格式是:loop標號,CPU執行loop指令的時候,要進行兩步操作:
- [cx]=[cx]-1
- 判斷cx中的值,不爲零則轉至標號處執行程序,如果爲零則向下執行
總結:
- 在cx中存放循環次數
- loop指令中的標號所標識地址要在前面
- 要循環執行的程序段,要寫在標號和loop指令的中間
框架如下:
mov cx,循環次數
s: 循環執行的代碼段
loop s
注意
- 在彙編源程序中,數據不能以字母開頭,所以要在前面加0
- [bx]的作用:作爲偏移地址與DS配合
- loop和cx合作
一段安全的空間
在8086模式中,隨意向一段內存空間寫入內容是很危險的,因爲這段空間中可能存放着重要的系統數據或代碼
我們在純DOS方式(實模式)下,可以不理會DOS,直接用彙編語言去操作真實的硬件,因爲運行在CPU實模式下的DOS,沒有能力對硬件系統進行全面而嚴格的管理。
但在Windows XP\2000、UNIX這些於CPU保護模式下的操作系統中,不理會操作系統,用彙編語言去操作真實的硬件,是根本不可能的。
硬件已被這些操作系統利用CPU保護模式所提供的功能全面而嚴格地管理。
在一般地PC機中,DOS方式下,DOS和其它合法程序一般都不會使用0:200~0:2FF的256個字節的空間。所以,我們使用這段空間是安全的。
以下總結:
- 我們需要直接向一段內存中寫入內容
- 這段內容不應該存放系統或其它程序的數據或代碼,否則寫入操作很可能引發錯誤。
- DOS方式下,一般情況,0:200~0:2FF空間中沒有系統或其它程序的數據或代碼
- 以後,我們需要直接向一段內存中寫入內容時,就使用0:200~0:2FF這段空間
第六章 包含多個段的程序
在代碼段中使用數據
- dw是定義字型數據。dw即define word。
- end除了通知編譯器程序結束外,還可以通知編譯器程序的入口在什麼地方。
將數據、代碼、棧放入不同的段
8086CPU不允許將一個數值直接送入段寄存器中。
mov ds,data中的data將被編譯器處理爲一個表示段地址的數值。
我們在源程序的最後用“end start”說明了程序的入口,這個入口將被寫入可執行文件的描述信息,可執行文件中的程序被加載入內存後,CPU的CS:IP被設置指向這個入口,從而開始執行程序中的第一條指令。
標號“start”在code段中,這樣CPU就將code段中的內容當作指令來執行了。
第七章 更靈活的定位內存地址的方法
and和or指令
and指令:邏輯與指令,按位進行與運算。
如 :
mov al,01100011B
and al,00111011B
執行後:al = 00100011B
通過該指令可將操作對象的相應位設爲0,其它位不變。
例如:
將al的第6位設爲0:and al, 10111111B
將al的第7位設爲0:and al, 01111111B
將al的第0位設爲0:and al, 11111110B
or指令:邏輯或指令,按位進行或運算。
如
mov al,01100011B
and al,00111011B
執行後:al = 01111011B
可以通過該指令將操作對象的相應爲設爲1,其它位不變。
例如:
將al的第6位設爲1:and al, 0100000B
將al的第7位設爲1:and al, 1000000B
將al的第0位設爲1:and al, 0000001B
關於ASCII碼
世界上有很多編碼方案,有種方案叫做ASCII編碼,是在計算機系統中通常被採用的,utf-8也是。
簡單地說,所謂編碼方案,就是一套規則,它約定了用什麼樣地信息來表示現實對象。
大小寫轉換的問題
大寫字母ASCII碼的第六位爲0,小寫字母的第六位爲1
[bx+idata]
[bx+idata]表示一個內存單元,它的偏移地址爲[bx]+idata(bx中的數值加上idata)
用[bx+idata]的方式進行數組的處理
C/C++等高級語言定位方式:a[i],b[i]
彙編語言定位方式:0[bx],5[bx]
SI和DI
SI和DI是8086CPU中和bx功能相近的寄存器,但是SI和DI不能分成兩個8爲寄存器來使用。
[bx+si]和[bx+di]
這兩個表示一個內存單元,它的偏移地址爲[bx]+[si](di),也就是bx中的數值加上si(di)中的數值
[bx+si+idata]和[bx+di+idata]
都表示一個內存單元,它的偏移地址爲[bx]+[si]+idata,原理同上
不同的尋址方式的靈活應用
- [idata]用一個常量來表示地址,可用於直接定位一個內存單元
- [bx]用一個變量來表示內存地址,可用於間接定位一個內存單元
- [bx+idata]用一個變量和常量表示地址,可在一個起始地址的基礎上用變量間接定位一個內存單元
- [bx+si]用兩個表示地址
- [bx+si+idata]用兩個變量和一個常量表示地址。
第八章 數據處理的兩個基本問題
bx、si、di、bp
在8086CPU中只有這4個寄存器(bx、bp、si、di)可以用在“[…]”中進行內存單元的尋址。
在“[…]”中,這四個可以單獨出現,或只能以四種組合出現
bx和si、bx和di、bp和si、bp和di
只要在“[…]”中使用寄存器bp,而指令中沒有顯性的給出段地址,段地址就默認在ss中。
機器指令處理的數據所在的位置
指令在執行前,所要處理的數據可以在三個地方:CPU內部、內存、端口
彙編語言中用三個概念來表達數據的位置。
- 立即數
- 寄存器
- 段地址(SA)和偏移地址(EA)
立即數,是指直接包含在機器指令中的數據(執行前在CPU的指令緩衝器中),在彙編語言中稱爲:立即數(idata),在彙編指令中直接給出。
寄存器,指令要處理的數據在寄存器中,在彙編指令中給出相應的寄存器名。
段地址(SA)和偏移地址(EA),指令要處理的數據在內存中,在彙編指令中可用[x]的格式給出EA,SA在某個段寄存器中。
存放段地址的寄存器可以是默認的
也可以是顯性的給出
尋址方式
- 直接尋址
- 寄存器間接尋址
- 寄存器相對尋址
- 基址變址尋址
- 相對基址變址尋址
指令要處理的數據
8086CPU的指令,可以處理兩種尺寸的數據,byte和word。所以在機器指令中要指明,指令進行的是字操作還是字節操作。
尋址方式的綜合應用
一般來說,我們可以用[bx+idata+si]的方式來訪問結構體中的數據。用bx來定位整個結構體,用idata定位結構體中的某一個數據項,用si定位數組項中的每一個元素。爲此,彙編語言提供了更爲貼切的書寫方式。
div指令
是除法指令(division),使用div作除法的時候:
除數:8位或16位,在寄存器或內存單元中
被除數:(默認)放在AX或DX和AX中
除數 | 被除數 |
---|---|
8位 | 16位(AX) |
16位 | 32位(DX+AX) |
僞指令 dd
dd是用來定義dword(double word雙字)型數據的
dup
是一個操作符,在彙編語言中同db、dw、dd等一樣,也是由編譯器識別處理的符號。
它是和db、dw、dd等數據定義僞指令配合使用的,用來進行數據的重複。
第九章 轉移指令的原理
操作符offset
8086CPU的轉移指令分爲以下幾類:
- 無條件轉移指令(如:jmp)
- 條件轉移指令
- 循環指令(如:loop)
- 過程
- 中斷
操作符offset在彙編語言中是由編譯器處理的符號,它的功能是取得標號的偏移地址。
jmp指令
無條件轉移,可以只修改IP,也可以同時修改CS和IP。
jmp指令要給出兩種信息:
- 轉移的目的地址
- 轉移的距離(段間轉移、段內轉短移,段內近轉移)
jmp short 標號
這種指令格式是段內短轉移,它對IP的修改範圍爲-128~127,也就是說,它向前轉移時可以最多越過128個字節,向後轉移可以最多越過127個字節。
轉移的目的地址在指令中的jmp指令
指令“jmp far ptr”實現的是段間轉移,又稱爲遠轉移
轉移地址在內存中的jmp指令
jmp dword ptr 內存單元地址(段間轉移)
jcxz指令
爲有條件轉移指令,所有的有條件轉移指令都是短轉移,在對應的機器碼中包含轉移的位移,而不是目的地址,對IP的修改範圍都爲-128~127
指令格式:jcxz 標號
loop指令
爲循環指令,所有的循環指令都是短轉移,在對應的機器碼中包含轉移的位移,而不是目的地址。
對IP的修改範圍都爲-128~127
指令格式:loop 標號