匯編指令詳解
8080指令詳解
1.8086系統下,Inter指令系統共有117條指令(看似很多,分一下類)
1.數據傳送類指令(專門傳送數據的)
2.算術運算類指令(加減乘除的運算的)
3.位操作類指令(或 異貨 與 ….)
4.串操作類指令 (內存拷貝,內存連續地址拷貝的操作)
5.控制轉移類指令(跳轉,比如C語言的Goto)
6.處理機控制類指令(計算機的待機 ,重啟 等等,讓CPU待機睡眠的指令)
學習指令的注意事項
1.指令的功能,也就是這個指令可以實現什么操作.通常的話,指令就是指令功能英文單字的縮寫方式,比如 mov傳送指令,其實全程叫做 move
2.指令支持的尋址方式,也就是說這個指令中的操作數決定了采用何種尋址方式,尋址方式決定了指令的語法
3.指令對標志位的影響,這個指令執行之后,是否會對各個標志位又影響.
4.其他方面,比如使用指令的時候,是否效率高,CPU執行周期是否會長
a.這里提供一個匯編金手指 的軟件,可以在今天的百度雲盤連接中獲取,可以很快的查詢各種指令
b.也可以利用Inter手冊查詢指令的語法,比如昨天講的怎么看inter手冊
補充知識,理解reg mod mem imm accum segreg英文什么意思
英文名稱 |
含義 |
Reg |
寄存器的意思 |
Mod |
尋址方式是哪一種 |
Mem |
內存 |
Imm |
立即數 |
Accum |
累加寄存器(ax) |
Segreg |
段寄存器(ds ss es cs) |
M8 |
代表內存8位,一個字節 |
M16 |
代表內存16位,兩個字節 |
看一下,下面講指令的時候會用到
例如mov指令
mov reg/mem,imm 表示指令是可以把一個立即數給 寄存器,或者內存
匯編語法則為 mov ax,100 ,或者 mov byte ptr[2000],10h,把10給2000取內容
為什么有byte ptr(或者 word ptr)主要為了給2000的時候,不知道讀取多少給,指定方式給
數據傳送指令類
一丶通用數據傳送指令
mov 指令 xchg指令 xlat指令
1.MOV傳送指令
指令 |
指令支持 |
指令功能 |
||||||||
MOV |
|
|
mov 指令傳送功能圖
請注意,立即數不能直接給段寄存器,都是通過中轉的
mov 注意事項
1.兩個操作數的類型不一致
例如源操作數是字節,目的操作數是字,或者是相反
例如 mov al,050AH al是八位寄存器,只能接受八位,而這里是16位了
對於存儲器,和立即數同時都作為操作數的情況下,必須顯示的指明是什么類型
例如 mov [2000h],12h 錯誤,應該寫成 mov byte ptr(或者word ptr)[2000h],12h
如果只是12h,則用byte ptr,當然你也可以寫成word ptr,但是修改內存的值修改后則是修改的兩個字節的長度
2.兩個操作數不能是存儲器
例如 mov [2000h],[2200h] 因為內存只是存儲的,傳送的結果要保存在寄存器當
當中,顯然內存沒有內置CPU,所以通過寄存器中轉,所以不能直接這樣
3.小心段操作寄存器
1.立即數不能直接給段寄存器
例如 mov ds,100 (比如經過寄存器的中轉)
2.不能直接改變cs段寄存器的值
mov cs,[si] 這條指令是可以編譯通過,但是運行的時候,因為你把代碼段的值改了,然后CS:IP確定的嚇一跳指令就會出錯,比如你的這條指令下面還有個mov ax,0 當你上面改了,那么mov ax,0 永遠不會執行,而你熟悉的改了cs的值可以,如果不熟悉那么代碼段就被破壞,程序就會執行崩潰.
3.段寄存器和段寄存器不能直接數據傳送
mov ds,es
2.交換指令
xchg reg/mem/accum , reg/mem/accum
其實就是寄存器的值交換
例如ax = 0
bx = 1
xchg ax,bx 那么此時ax的值就是1,bx就是0
有人說mov 指令也可以,確實是可以,但是指令周期不一樣,這個比mov指令快一個
指令周期,而且還不浪費寄存器(否則需要三個寄存器完成交換)
寄存器和存儲器交換
xchg ax,[2000h] 字交換,ax正好可以放下16位
等價於 xchg [2000h],ax 這里會有人說為什么不用 word ptr說明一下
因為后面跟着的是16位寄存器,它默認就是 word ptr了
xchg al,[2000h] 字節交換
等同於 xchg [2000h],al 同上為什么不用byte ptr
3.xlat 換碼指令(查表指令)
將bx指定的緩沖區中,al執行的位移處的一個字節數據取出賦值給al
后面沒有操作數,默認操作數就是 dx和al
直接 一個 xlat即可.默認操作的就是dx 和al
但是轉變成mov 相當於 改為 mov al,ds:[dx+al]
什么意思,就是dx數據里面有一塊完整的內存(比如是ASCII碼 a b c d)
al 就給定一個下標,然后調用xlat指令,就可以根據al的下標獲取出來 abcd其中的一個
ASCII碼重新放到al中
相當於數組尋址
C語言代碼應該寫成
char d[5] = {‘a’,’b’,’c’…};
char ch = 0;
ch = *(d(數組首地址) * ch(下標))然后取出內容來重新給ch,看一下匯編怎么寫吧
當然上面只是偽代碼
第一步,使用e命令給400偏移處寫入 abcdefg的字符
第二步 使用 d命令查看
第三步開始匯編,先給bx賦值偏移量為400,則 DS:[DX]可以取得61(也就是a)的編碼
但是怎么取出來,要根據al給定的下標,比如al給了3,那么就是 DS:[DX+AL] 也就是取出63的編碼,賦值給al
我這里給的是0,所以下標取內容是61
3.堆棧指令
首先看一下棧
SS代表棧的段地址,SP代表是棧頂 BP代表是棧底
堆棧的操作指令有兩種,第一種是PUSH壓棧,第二種是POP出棧
首先mov指令模擬
第一步,要壓棧之前,sp需要-2,留出一個字的空間,這樣才可以把字壓入棧中
mov sp,bp 棧底和棧頂一樣
sup sp,2 棧頂-2留出兩個空間讓數據壓棧
mov bp sp,讓棧底和棧頂一樣的位置
mov word ptr [bp],1 棧底位置處壓入1
出棧
mov bp,sp 首先棧頂棧底一樣
mov ax,[bp] 棧底的數據給ax
add sp,2 棧頂指針移動
mov bp,sp 棧底位置和棧頂位置一樣
但是事實x86提供了指令
push 和pop
push ax 把 ax壓棧
pop ax 出棧的值放到ax中
push的指令
push r16/m16/seg (可以是16位寄存器,2個字節的內存,或者段寄存器)
pop 一樣
標志寄存器傳送指令
1.有兩對4條指令(分別對應8位寄存器,和16位寄存器)
低八位傳送 LAHF 和SAHF
16位傳送 PUSHF和POPF
什么意思
LAHF 代表 的意思 第一個字母 L代表load(加載的意思) AH八位寄存器AH,F是標志位
表示把 Flag標志寄存器里面的低八位標志,傳送到 AH中
偽代碼
mov ah,flag(當然這是不行的,flag是16位,比如使用關鍵字)
SAHF S可以理解為設置,或者保存的意思
意思就是 AH的高八位當做標志位給Flag寄存器的標志位賦值
表示我們通過AH的值,設置flag標志寄存器
如果我們要把標志位都清零怎么辦
xor ah,ah (為什么用這個,因為這個CPU尋址的時候指令執行周期短,如果
寫成 mov ah,0那么帶有立即數所以比較慢,玩匯編就是要這樣玩的)
SAHF 清零標志位
PUSHF 和POPF都是一樣的,只不過有入棧出棧的操作,所以指令周期更長
清零
pushf 獲取標志位到ax中,但是需要pop獲取
pop ax
xor ax,ax 獲取到了設置為0
push ax 重新壓棧
popf 即可 popf設置標志寄存器,一般來說不用設置標志寄存器的高八位
下面還有一段代碼
pushf ;保存全部標志到堆棧
pop ax ;從堆棧中取出全部標志
or ax,0100h ;設置D8=TF=1,這個地方就是對某一位設置
;ax其他位不變
push ax ;將ax壓入堆棧
popf ;FLAGS←AX
;將堆棧內容取到標志寄存器
上面這個代碼寫調試器相當於單步代碼
2.地址傳送指令
LEA 有效地址傳送指令 例如 LEA AX,[bp] 這樣
執行 LEA r16,mem (具體查詢 inter手冊)
上面這樣寫只是求出內存地址,假設bp的值是2000,則給ax是2000,而不是2000里面的內容,這樣寫比add快,但是真正用法不是這樣的,真正用法就是求內存地址而已(注意不是求出內存單元的值,如果寫成 add ax,[bp],如果是這樣,那么ax的值就不是2000了,就是2000地址里面的內容了)
LDS LES指針傳送指令
LDS 改變段寄存器的,試想一下,程序一大,數據段就應該有很多,但是你不能只有一個
兩個段使用的時候可以來回切換
使用 lds ax,ds:[0]
使用后會修改 ax的值和ds段寄存器的值
內存的前兩個字節給 r16
內存地址+2的連個字節給ds
LES是一樣的
例子
mov word ptr [3060h],0100h
mov word ptr [3062h],1450h
les di,[3060h] ;es=1450h,di=0100h
lds si,[3060h] ;ds=1450h,si=0100h
mem指定主存的連續4個字節作為邏輯地址(32位的地址指針),送入DS:r16或ES:r16
三丶輸入輸出指令
IN
OUT
這個指令很強大,可以直接通過端口操作硬件
比如鍵盤的端口是 64
我們可以利用IN從鍵盤中讀取數據
OUT往鍵盤的緩沖區寫入數據
當然怎么寫還有看鍵盤的規范,寄存器呀,參數呀等等.
這個功能和驅動過保護有關,以前都說驅動過保護,就是就是玩着兩個指令,
比如HOOK(鈎子,不懂可以百度)你去HOOK應用層的軟件,但是HOOK不了我,你HOOK的時候需要調用API,我連API都不用調用,直接在底層就操作數據了
從鍵盤緩沖區取一個指令
IN ax,64(端口號)
輸出(偽代碼,沒有看硬盤廠家的標准)
OUT ax,64
IN AL,i8
;字節輸入:AL←I/O端口(i8直接尋址)
IN AL,DX
;字節輸入:AL←I/O端口(DX間接尋址)
IN AX,i8
;字輸入:AX←I/O端口(i8直接尋址)
IN AX,DX
;字輸入:AX←I/O端口(DX間接尋址)
將數據傳送給外設(偽代碼)
OUT i8,AL
;字節輸出:I/O端口←AL(i8直接尋址)
OUT DX,AL
;字節輸出:I/O端口←AL(DX間接尋址)
OUT i8,AX
;字輸出:I/O端口←AX(i8直接尋址)
OUT DX,AX
;字輸出:I/O端口←AX(DX間接尋址)
算術運算類指令
a.加法指令
ADD reg,imm/reg/mem
;reg←reg+imm/reg/mem
ADD mem,imm/reg
;mem←mem+imm/reg
看指令就會操作,可以 立即數給寄存器,寄存器給雞存器,地址的內容給寄存器
2.帶進位的加法
ADC reg,imm/reg/mem
;reg←reg+imm/reg/mem+CF
ADC mem,imm/reg
;mem←mem+imm/reg+CF
帶進位的加法就是兩數相加的時候,進位也算
比如 1234 + 4321
低八位縣桑拿 34 + 21 是否進位,如果進位,假設為1
那么高八位計算的結果需要加上進位
12+43 + 1 +上面算的結果
具體自己調試一下Debug看一下
例子,雙字加法,也就是32位加法,使用8086的16位寄存器完成
mov ax,4652h ;ax=4652h
add ax,0f0f0h ;ax=3742h,CF=1 //這里的0f0f0h 前邊加0表示是16進制,比如C語言需要加上 0x
mov dx,0234h ;dx=0234h
adc dx,0f0f0h ;dx=f325h,CF=0
;DX.AX=0234 4652H
+F0F0 F0F0H
=F325 3742H
3.增量INC
INC reg/mem
;reg/mem←reg/mem+1
很簡單,寄存器,或者內存自增1
C語言中相當於i++ ++ i這種
INC bx, bx自增1
INC byte ptr[bx] 地址自增
b減法指令
SUB reg,imm/reg/mem
;reg←reg-imm/reg/mem
SUB mem,imm/reg
;mem←mem-imm/reg
同加法一樣,只不過相反
2.帶借位的減法指令
SBB reg,imm/reg/mem
;reg←(reg-(imm/reg/mem)-CF)
SBB mem,imm/reg
;mem←mem-imm/reg-CF
SBB指令將目的操作數減去源操作數,再減去借位CF(進位),結果送到目的操作數。
SBB指令按照定義相應設置狀態標志
SBB指令主要與SUB配合,實現多精度減法運算
同加法一樣,只不過是借位
雙字減法例子
mov ax,4652h ;ax=4652h
sub ax,0f0f0h ;ax=5562h,CF=1
mov dx,0234h ;dx=0234h
sbb dx,0f0f0h ;dx=1143h,CF=1
;DX.AX=0234 4652H
-F0F0 F0F0H
=1143 5562H
3.減量指令DEC
自減
DEC reg/mem
;reg/mem←reg/mem-1
INC指令和DEC指令都是單操作數指令
主要用於對計數器和地址指針的調整
4.求補指令 NEG
這個指令比較重要,求一個數的補碼
NEG reg/mem
;reg/mem←0-reg/mem
請注意,CPU並不會執行補碼,
而是寫成 SUB 0,1
用0減去操作數1,然后結果返回操作數
求補運算也可以表達成,將操作數按位取反后加1
NEG指令對標志的影響與用零作減法的SUB指令一樣
跳轉指令
JMP 預習
inter手冊放到連接中,需要的自己查詢,只需要把上面的 (imm r16 ...這些弄明白了,那么看匯編的語法就懂了,而且有指令周期)
鏈接:http://pan.baidu.com/s/1b5lo9g 密碼:4n5y
如有錯誤,希望批評改正,如果不懂,請私信留言.謝謝支持,官方論壇 www.w1x8.com希望大家可以去論壇活躍氣氛