以下是本人學習王爽老師的《彙編語言》一書之後的一些小總結 内容比較傾向于草稿 不适合正式學習
學習彙編的初衷是想更加深入的了解計算機的運作原理,也希望彙編這種最接近底層的語言能夠在我使用進階語言時提供更好的設計思路。ps.當我發現學作業系統時需要用到很多彙編語言時 内心是無比激動的。
也許日後不會使用很多彙編 但是能看懂未來某個陰暗角落裡無法避免的彙編代碼 也算是解決了後顧之憂
--------習慣唠嗑的小菜雞
- 彙編語言的産生: 機器隻能識别機器語言也就是一系列機器指令,一列二進制數字。計算機将之轉變為高低電平來使得電子器件收到驅 動,進行運算。然而這種語言對于人類不夠友好,開發和調試周期很長。于是人們定義 規定出一套對人類更加友好的語言 彙編來解決這個障礙
- 彙編語言的組成:彙編語言由下列三類指令組成
- 彙編指令 機器碼的助記符 對應着機器碼(核心)
- 僞指令 由編譯器執行 計算機不執行的代碼 不對應機器碼
- 其他符号 加減乘除等符号 由編譯器識别 計算機不執行
彙編語言其實就是機器語言便于記憶的書寫格式,寫法上更接近人類的語言,便于閱讀和記憶
編譯器:将彙編語言翻譯成機器碼,以供機器執行
-
存儲器 :如果CPU提供大腦的運算功能,那麼存儲器就是用來提供記憶的,指令和資料都存在裡面,直接或間接地被CPU讀取來運作
再聰明的人沒了記憶都無法思考,是以存儲器地地位僅次于CPU,思考的前提就是運用CPU讀取存儲器。
- 指令和資料:資料和指令在記憶體中是沒有差別的,實質都是機器碼,當它被CPU讀取并識别時CPU就會差別二者的不同意義 什麼是資料 什麼是指令。
- 存儲單元:一個存儲單元為8bit 即 1byte 是形容微機存儲器容量最小機關
- CPU對存儲器的讀寫過程:
CPU想要向存儲器讀寫資料必須有三個步驟
a 找到資料位址
b 選擇哪個器件 選擇讀還是寫
c 令資料傳輸
對應的我們需要有三種總線
a 位址總線 将位址資訊發出
b 選中存儲晶片 通知它将要從中讀/寫資料
c 存儲器/CPU 發送資訊
-
總線(位址,資料,控制)
資料總線:它的寬度決定了每次能傳輸多少資料
寬度為 8 代表每次可傳輸一個8位的二進制資料 如果要發送16位必須分兩次發送 且後面的資料先發送
寬度位16 代表每次可傳輸兩個位元組的二進制資料
控制總線:控制總線代表了對系統中其他器件的控制能力,讀寫過程其實是不同總線來共同承擔的
(“讀信号輸出控制線” “寫信号輸出控制線”)
-
記憶體位址空間:
一個CPU的位址總線寬度為10 那麼可以尋址2^10 也就是1024個 存儲單元 ,這些可以被查詢到的位址單元的集合就是這個CPU的記憶體位址空間
- 主機闆 :将所有器件(核心器件 主要器件 )整合在上面 通過總線相連
11.接口卡 CPU無法與外圍器件直接通信 需要有中轉裝置 接口卡
CPU-------擴充槽上的接口卡-------外圍裝置
12.各類存儲器晶片
存儲器讀寫屬性上分類
随機存儲器 RAM 可讀可寫 帶電存儲 掉電丢失
隻讀存儲器 ROM 隻可讀 掉電不丢失
存儲器從功能和連接配接上分類
随機存儲器 —主随機存儲器(主機闆上RAM+擴充插槽上的RAM) 儲存絕大多數程式和資料
裝有BIOS的ROM
接口卡上的RAM 顯存 用于暫時存儲資訊 我們将要顯示的内容先寫入顯存 然後他會将資訊發送到顯示器上
13.記憶體位址空間 :
所有的實體存儲器被看作一個由若幹存儲單元組成的邏輯存儲器;
每個實體存儲器在這個邏輯存儲器中占有一個位址段,即一段位址空間;
CPU在這段位址空間中讀寫資料,實際上就是在相對應的實體存儲器中讀寫資料。
不同的計算機系統的記憶體位址空間配置設定情況是不同的。
8086CPU的最小存儲單元是位元組 8BIT
如圖 我們常将每一個存儲單元都用16進制數标記按出

三種資訊:
位址 資料 控制
通過三種總線來區分三種資訊:
位址總線 資料總線 控制總線
位址總線的寬度決定了CPU能夠尋址的存儲單元的大小以及CPU尋址的速度
資料總線的寬度決定了CPU和外界的資料傳送速度
8088 8位
8086 16位 速度快一倍
控制總線的寬度決定了CPU對外部器件的控制能力
記憶體位址空間的概述:
主機闆和接口卡的概念:
CPU通路記憶體單元時要給出記憶體單元的位址,所有記憶體單元構成的存儲空間是一個一位的線性空間,這個唯一的位址也就稱為實體位址
8086CPU給出實體位址的方法:
8086有20根位址總線 尋址能力是2的20次方=1M
但是8086内部是16位的結構 它隻能傳送16位的位址,表現出的尋址能力卻隻有64K
由圖中我們可以看出,位址加法器會将段位址x16再加上偏移位址 例如:
段位址1230H X 16 + 偏移位址00C8 = 12300 + 00C8 = 123C8
将16位位址轉化為20位 就可以将外部總線的資源充分利用起來
一個錯誤的認識:記憶體被劃分為一個一個的段,每一個段有一個段位址
糾正:記憶體并沒有分段,段的劃分來自于CPU 由于8086CPU為16位結構而外部位址總線為20位 是以為了充分利用總線資源
采用段位址x16+偏移位址=實體位址的方式給出記憶體單元的實體位址使得我們可以用分段的方式來管理記憶體
(從CPU的角度看 記憶體空間隻是一個線性空間)
用于提供段位址的四個段寄存器:
CS code DS data SS stack ES extern
CS為代碼段寄存器
IP 為指令指針寄存器
DS寄存器用于存儲段位址 ,配合[ x ]将段位址*16 + x來尋址和拿去資料
DS 是個害羞的小女孩 間接指派
mov add sub指令的幾種形式
一個例子:
mov ax,1000
mov ds, ax
mov bx,[0]
mov [0],bx
mov 寄存器,寄存器 mov ax,bx
mov 寄存器,資料 mov ax,1000
mov 寄存器,記憶體單元 mov bx,[0]
mov 記憶體單元,寄存器 mov [0], bx
mov 段寄存器,寄存器 mov ds,ax
資料段:
CS:IP所指就是代碼段
DS:[X]所指就是資料段
将段位址123B0H - 123BAH的記憶體單元定義為資料段 累加這個資料段中前三個單元的位址:
mov ax,123B
mov ds,ax
mov al,0
add al,[0]
add al,[1]
add al,[2]
PSP用于DOS與被加載程式的通信 常用于debug
DOS 磁盤作業系統 主要是一種面向磁盤的系統軟體。 簡單來說就是人與計算機之間的一座橋梁
可以不必記憶機器碼而用更加自然的語言操縱機器(是罩在機器硬體外面的一層“外殼”SHELL)
在不能确定一點記憶體空間是否存在重要資料的時候不可以随意向其中寫入内容 否者會引起當機 PC機中 一般程式以及DOS都不會占用00200 -
002FF這一塊256位元組的記憶體 被稱為安全空間
CX loop下代碼的執行次數
CS:IP
DS:SI DI BX 操縱[bx]中的資料時如果沒有顯式說明 都預設段位址在DS中
SI DI也和BX相似 但不能被分為兩個8位寄存器使用 即部分low位和high位
SS:SP BP 操縱[bp]中的資料時如果沒有顯式說明 都預設段位址在SS中
尋址方式有如何約定:
标志寄存器
-
ZF-零标志 zero flag
ZF标記相關指令的計算結果是否為0
ZF=1(ZR),表示“結果是0 ”,1表示“邏輯真”
ZF=0 ( NZ ),表示“結果不是0”,0表示“邏輯假”
-
PF-奇偶标志 parity flag
PF記錄指令執行後,結果的所有二進制位中1的個數:
PF = 1 (PE ),表示1的個數為偶數
PF = 0 (PO),表示1的個數為奇數
-
SF-符号标志 sign flag
SF記錄指令執行後,将結果視為有符号數
SF = 1 (NG), 表示結果為負
SF = 0(PL),表示結果為非負
SF 标志是CPU對有符号數運算結果的一種記錄 。
将資料當作有符号數來運算的時候,通過SF可知結果的正負;将資料當作無符号數來運算,SF的值則沒有意義,雖然相關的指令影響了它的值。
-
CF-進位标志 carry flag
在進行無符号數運算的時候,CF記錄了運算結果的最高有效位向更高位的進位值,或從更高位的借位值
CF=1(CY), 表示有進位或借位
CF=0(NC), 表示無進位或借位
-
OF-溢出标志 overflaw flag
在進行有符号數運算的時候,如結果超過了機器所能表示的範圍稱為溢出
OF = 1(OV), 表示有溢出
OF = 0(NV), 表示無溢出
eg:
mov al,0F0H
add al,88H
執行結果:CF=1, OF=1
即當無符号數運算有進位,當有符号數運算有溢出
彙編語言中用于開記憶體的幾個操作符:
dw db dd 三者前面的d為define 定義 w:word b:byte d:double word
mov word ptr ds:[2],0
dup 用于配合上面開記憶體的三個操作符号使用初始化記憶體上的數值 例如:
db 3 dup(0) ;開了三個位元組的記憶體并初始化為0
db 3 dup(0,1,2); 開了三個位元組的記憶體并分别初始化為0,1,2
簡潔的初始化方法:
db 0,1,2
offset 是由編譯器識别的一個符号 用于擷取标志的位址 例如:
assume code:codesg
code segment
start : mov ax,offset start
s : mov ax,offset start
code ends
end
轉移指令:
轉移的意思就是跳轉pc指針 修改cs:IP的位址
80x86的轉移行為有兩種:段内轉移 (jmp ax) 段間轉移(jmp 1000:0) 差別在于是否跨出了一個段(2^16=64k)的距離
80x86的轉移指令有:條件轉移,無條件轉移,循環loop,過程,中斷。
jmp 使用jmp需要給出跳轉的大緻距離長短 和 具體的目的位址
jmp short
jmp near ptr
jmp far ptr
jcxz 條件跳轉
loop 循環 配合cx寄存器和标志使用
call和ret retf
call指令可以:
将目前CALL指令下一條的CS IP 放入棧中 然後轉移到目标位置 也分近轉移和遠轉移
call 标号/寄存器
call far ptr 标号/寄存器
call word ptr ds:[0]
ret retf指令可以看成call指令的逆過程:
将棧内的資料彈出并指派給CS IP 然後轉移到CS IP 所指的位置
CALL RET 配合使用實作函數的調用與傳回
函數的設計還需要有 傳入參數和傳回值 實作傳參和傳回值的方法有:
1 隻有少量的參數和傳回值的情況下使用寄存器儲存資料
2 大量參數時的解決方法:
将參數放入一段記憶體中 然後将這段記憶體的起始位址放入寄存器來傳參 傳回值也可依照存儲
當軟這段記憶體也可以是棧
中斷:定義學過單片機的都懂 不必贅述
産生中斷的原因:1 除法錯誤
2 單步執行
3 執行into指令
4 執行int指令
CPU用一個位元組(256)存儲一個名為中斷類型碼的标記 可以存儲256種不同的資料來辨別256種不同的中斷類型
CPU會由中斷資訊中擷取到中斷類型碼去到一塊記憶體中查詢中斷向量表 那裡面儲存了每一種中斷類型對應的中斷服務函數的起始位址 拿到起始位址就可以設定CS IP來執行對應中斷服務函數::
是以 相應的 中斷處理函數中需要寫出使用者自己的處理過程 還需要iret指令:
pop ip
pop cs
popf //恢複标志位
除此之外 要想在CPU内部産生中斷還可以人為主動地去産生中斷 這就需要利用指令 :int + 中斷類型碼