匯編開發(fā)(二):數據傳輸,地址和算法

1. 數據傳輸指令

1). 操作數類型
[label:] mnemonic [operands][; comment]

指令可以有零個,一個,兩個或者三個操作數。此處忽略label和comment, 如下:

mnemonic
mnemonic [destination]
mnemonic [destination],[source]
mnemonic [destination],[source-1],[source-2]

操作輸的基本類型:

  • 立即數: 使用數字文本表達式
  • 寄存器: CPU中的寄存器
  • 內存: 直接引用內存地址
2). 直接內存操作數
操作數 描述
reg8 8位普通用途的寄存器:AH, AL, BH, BL, CH, CL, DH, DL
reg16 16位普通用途的寄存器:AX, BX, CX, DX, SI, DI, SP, BP
reg32 32位普通用途的寄存器:EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP
reg 任何普通用途的寄存器
sreg 16位段寄存器:CS, DS, SS, ES, FS, GS
imm 8,16,32位立即數
imm8 8位字節(jié)立即數
imm16 16位字立即數
imm32 32位雙字立即數
reg/mem8 8位操作數,可以是8位普通寄存器或內存字節(jié)
reg/mem16 16位操作數,可以是16位普通寄存器或內存字節(jié)
reg/mem32 32位操作數,可以是32位普通寄存器或內存字節(jié)
mem 8,16,32內存操作數
3). MOV 指令
  • 功能:MOV指令從源操作數賦值數據到目標操作數中。
  • 格式:
MOV destination,source
  • 操作數規(guī)則

    • 兩個操作數必須是相同的大小
    • 兩個操作數不能是內存操作數
    • 指令指針寄存器(IP, EIP, RIP)不能作為目標操作數
MOV reg,reg
MOV mem,reg
MOV reg,mem
MOV mem,imm
MOV reg,imm
  • 覆蓋值
.data
    oneByte BYTE 78h            ; 定義一個8bit變量
    oneWord WORD 1234h          ; 定義一個16bit變量
    oneDword DWORD 12345678h    ; 定義一個32bit變量

.code
main PROC                   ; 定義主函數開始位置
    mov eax, 0              ; 為eax寄存器賦值 -- EAX = 0000 0000h
    mov al, oneByte         ; 為al賦值         -- EAX = 0000 0078h
    mov ax, oneWord         ; 為ax賦值         -- EAX = 0000 1234h
    mov eax, oneDword       ; 為eax賦值            -- EAX = 1234 5678h
    mov ax, 0               ; 為ax賦值         -- EAX = 1234 0000h
4). 整數0和符號的擴展
  • 問題
    主要原因:占用字節(jié)空間大的寄存器低字節(jié)賦值時,高字節(jié)為做更改
    解決方法:第一種用MOVZX指令代替,第二種用MOVSX代替
COMMENT &
    第一種情況是將小位數的數賦值給大位數的寄存器時,未賦值的高字節(jié)未置空
    第二種情況是將小位數的負數賦值給大位數的寄存器時,為賦值的高字節(jié)未置F
&
.data
    count WORD 10           ; 定義變量
    signedVar SWORD -16     ; 定義負數

.code
main PROC                   ; 定義主函數開始位置
    mov ecx, 100000         ; 為ecx寄存器賦值,此時ECX = 000186A0
    mov cx, count           ; 為ecx寄存器賦值,此時ECX = 0001000A
    
    mov cx, signedVar       ; 為ecx寄存器賦值,此時ECX = 0001FFF0,解決方法之一:可在此之前將ecx設置為FFFF FFFFh
  • MOVZX 指令

功能:賦值源操作數的內容到目標操作數,為16位或32位的值進行0的擴展。這個指令僅被使用在無符號整型中, 作用域:

MOVZX reg32,reg/mem8
MOVZX reg32,reg/mem16
MOVZX reg16,reg/mem8

示例:

COMMENT &
    MOVZX 解決0擴展問題
&
.data
    byte1 BYTE 9Bh          ; 定義字節(jié)變量
    word1 WORD 0A69Bh       ; 定義字變量

.code
main PROC                   ; 定義主函數開始位置
    ; 寄存器->寄存器
    mov bx, 0A69Bh          ; 為bx賦值         ebx = 7EFD A69Bh 
    movzx eax, bx           ; 將bx的值賦值給eax, eax = 76AB 342Bh -> eax = 0000 A69Bh
    movzx edx, bl           ; 將bl的值賦值給edx, edx = 00F9 1005h -> edx = 0000 009Bh
    movzx cx, bl            ; 將bl的值賦值給cx, ecx = 0000 0000h -> ecx = 0000 009Bh

圖1.png
  • MOVSX 指令

功能:賦值源操作數的內容到目標操作數,為16位或32位的值進行符號的擴展。這個指令僅被使用在有符號整型中, 作用域:

MOVSX reg32,reg/mem8
MOVSX reg32,reg/mem16
MOVSX reg16,reg/mem8

示例:

COMMENT &
    MOVZX 解決符號擴展問題
&
.data
    byteVal BYTE 10001111b          ; 定義字節(jié)變量

.code
main PROC                   ; 定義主函數開始位置
    ; 內存 -> 寄存器
    movsx ax, byteVal       ; 將byteVal的值賦值給ax寄存器,ax = 342Bh -> ax = FF8Fh
    ; 寄存器->寄存器
    mov bx, 0A69Bh          ; 為bx賦值,bx = E000h -> bx = A69Bh
    movsx eax, bx           ; 將bx的值賦值給eax, eax = 76AB FF8Fh -> eax = FFFF A69Bh
    movsx edx, bl           ; 將bl的值賦值給edx, edx = 0035 1005h -> edx = FFFF FF9Bh
    movsx cx, bl            ; 將bl的值賦值給cx, cx = 0000h -> cx = FF9Bh
圖2.png
5). LAHF和SAHF--EFlags狀態(tài)
COMMENT &
    LANF加載EFLAGS值到AH,SANF保存AH值
&
.data
    saveflags BYTE ?        ; 定義保存flag的變量
    newflags BYTE ?         ; 定義新的flag的值

.code
main PROC                   ; 定義主函數開始位置
    lahf                    ; 加載flag到ah     eax = 76AB462Bh
    mov saveflags, ah       ; 將ah的數值保存到flag中 saveflags = 70

    mov saveflags, 100      ; 賦值 saveflags = 100
    mov ah, saveflags       ; 賦值 eax = 76AB642Bh
    sahf                    ; 保存 
6). XCHG指令

功能:交換兩個操作數的內容。形式:

XCHG reg,reg
XCHG reg,mem
XCHG mem,reg

注:XCHG不接立即數操作數。

COMMENT &
    XCHG,交換數值
&
.data
    val1 WORD 10        ; 定義變量1
    val2 WORD 20        ; 定義變量2

.code
main PROC                   ; 定義主函數開始位置
    ; 交換val1 和 val2的數值
    mov ax, val1            ; 將val1的值存入ax中
    xchg ax, val2           ; 交換ax與val2的值
    mov val1, ax            ; 將ax的值放入val1中
7). 直接偏移操作數

功能: 為數組變量名添加一個移位。

COMMENT &
    直接偏移操作數,訪問數組元素
&
.data
    arrayB BYTE 10h, 20h, 30h, 40h, 50h ; 定義字節(jié)數組元素
    arrayW WORD 100h, 200h, 300h        ; 定義字數組元素
    arrayD DWORD 10000h, 20000h         ; 定義雙字數組元素

.code
main PROC                   ; 定義主函數開始位置, eax = 76AB342Bh
    mov al, [arrayB + 3]        ; 訪問BYTE數組第4個元素, eax = 76AB3440h
    mov ax, [arrayW + 2 * 2]    ; 訪問WORD數組第3個元素, eax = 76AB0300h
    mov eax, [arrayD + 4 * 1]   ; 訪問DWORD數組第2個元素, eax = 00020000h
8). 綜合示例
.486        ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall    ; 選擇程序的內存模式為平坦模式,stdcall調用習慣
.stack 4096             ; 設置運行的堆棧大小為4096字節(jié)
ExitProcess PROTO, dwExitCode: DWORD    

COMMENT &
    直接偏移操作數,訪問數組元素
&
.data
    val1 WORD 1000h
    val2 WORD 2000h
    arrayB BYTE 10h, 20h, 30h, 40h, 50h ; 定義字節(jié)數組元素
    arrayW WORD 100h, 200h, 300h        ; 定義字數組元素
    arrayD DWORD 10000h, 20000h         ; 定義雙字數組元素


.code
main PROC                   ; 定義主函數開始位置
    ; MOVZX 指令示范            
    mov bx, 0A69Bh              
    movzx eax, bx               ; eax = 0000 A69Bh
    movzx edx, bl               ; edx = 0000 009Bh
    movzx cx, bl                ; cx = 009Bh

    ; MOVSZ 指令示范
    mov bx, 0A69Bh
    movsx eax, bx               ; eax = FFFF A69Bh
    movsx edx, bl               ; edx = FFFF FF9Bh
    mov bl, 7Bh
    movsx cx, bl                ; cx = 007Bh

    ; 內存 -> 內存 數值交換
    mov ax, val1                ; ax = 1000h
    xchg ax, val2               ; ax = 2000h, val2 = 1000h
    mov val1, ax                ; val1 = 2000h

    ; 直接偏移地址(BYTE數組)
    mov al, arrayB              ; al = 10h
    mov al, [arrayB + 1]        ; al = 20h
    mov al, [arrayB + 2]        ; al = 30h

    ; 直接偏移地址(WORD數組)
    mov ax, arrayW              ; ax = 100h
    mov ax, [arrayW + 2]        ; ax = 200h

    ; 直接偏移地址(DWORD數組)
    mov eax, arrayD             ; eax = 0001 0000h
    mov eax, [arrayD + 4]       ; eax = 0002 0000h


    INVOKE ExitProcess, 0   ; 退出程序
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 
END main            ; 設置了函數的入口與出口

2. 加與減

1). INC與DEC指令
  • 作用域:
INC reg/mem
DEC reg/mem
  • 示例代碼:
COMMENT &
    加減運算
&
.data
    myWord WORD 1000h
    
.code
main PROC                   ; 定義主函數開始位置
    inc myWord              ; myWord變量自加        myWord = 1001h
    mov bx, myWord          ; 將bx值設置為myWord  bx = 1001h
    dec bx                  ; bx值進行自減   bx = 1000h
2). ADD 指令
  • 使用方法: ADD dest,source
COMMENT &
    加減運算
&
.data
    var1 DWORD 10000h
    var2 DWORD 20000h
    
.code
main PROC                   ; 定義主函數開始位置
    mov eax, var1           ; 將var1的值賦值給eax, eax = 10000h
    add eax, var2           ; 將var2的值與eax的值相加, eax = 30000h
3). SUB 指令
  • 使用方法:SUB dest,source
COMMENT &
    加減運算
&
.data
    var1 DWORD 10000h
    var3 DWORD 30000h
    
.code
main PROC                   ; 定義主函數開始位置
    mov eax, var3           ; 將var3的值賦值給eax, eax = 30000h
    sub eax, var1           ; 將eax的值減去1000h, eax = 20000h
4). NEG 指令
  • 使用方法:NEG reg/mem
COMMENT &
    加減運算
&
.data
    var1 DWORD 10000h
    var3 DWORD 30000h
    
.code
main PROC                   ; 定義主函數開始位置
    mov eax, var3           ; 將var3的值賦值給eax, eax = 30000h
    sub eax, var1           ; 將eax的值減去1000h, eax = 20000h
    neg eax                 ; eax由20000h取反+1為FFFE0000
5). 實現算術表達式
  • 示例代碼:
COMMENT &
    加減運算
&
.data
    Rval DWORD ?
    Xval DWORD 26
    Yval DWORD 30
    Zval DWORD 40
    
.code
main PROC                   ; 定義主函數開始位置
    ; Rval = -Xval + (Yval - Zval)
    ; 第一步: -Xval
    mov eax, Xval
    neg eax                     ; eax = -26
    ; 第二步:(Yval - Zval)
    mov ebx, Yval       
    sub ebx, Zval               ; ebx = -10
    ; 第三步:計算Rval
    add eax, ebx
    mov Rval, eax               ; Rval = -36
6). 標志位測試
.code
main PROC                   ; 定義主函數開始位置
    ; ZF 零標志位示例
    mov cx, 1
    sub cx, 1                   ; ZF = 1
    mov ax, 0FFFFh
    inc ax                      ; ZF = 1

    ; SF 符號標志位示例
    mov cx, 0
    sub cx, 1                   ; SF = 1
    mov ax, 7FFFh
    add ax, 2                   ; SF = 1

    ; CF 進位標志位示例
    mov al, 0FFh
    add al, 1                   ; CF = 1, al = 00h

    ; OF 溢出標志位示例
    mov al, +127
    add al, 1                   ; OF = 1
    mov al, -128
    sub al, 1                   ; OF = 1

3. 數據相關的運算符和指令

1). OFFSET 操作數

功能:獲取偏移地址

COMMENT &
    數據相關的運算符和指令運算
&
.data
    bVal BYTE ?
    wVal WORD ?
    dVal DWORD ?
    dVal2 DWORD ?
    myArray WORD 1, 2, 3, 4, 5
    
.code
main PROC                   ; 定義主函數開始位置
    ; OFFSET 偏移
    mov esi, OFFSET bVal    ; ESI = 00904000h
    mov esi, OFFSET wVal    ; ESI = 00904001h
    mov esi, OFFSET dVal    ; ESI = 00904003h
    mov esi, OFFSET dVal2   ; ESI = 00904007h
    mov esi, OFFSET myArray + 4 ; ESI = 0090400Fh
2). ALIGN 指令

功能:對齊字節(jié)大小,將小字節(jié)內存向大字節(jié)內存靠攏

.data
    ; ALIGN 對齊
    bVal1 BYTE ?            ; 00404000h
    ALIGN 2
    wVal1 WORD ?            ; 00404002h
    bVal2 BYTE ?            ; 00404004h
3). PTR 操作數

功能:將大字節(jié)的變量轉換為小字節(jié)的變量,將小字節(jié)的數組拼接為打字節(jié)的變量

.data
    myDouble DWORD 12345678h
    wordList WORD 5678h, 1234h

.code
main PROC                   ; 定義主函數開始位置
    ; PTR 指針
    mov ax, WORD PTR myDouble   ; ax = 5678h
    mov ax, WORD PTR [myDouble + 2] ; ax = 1234h
    mov eax, DWORD PTR wordList ; eax = 12345678h
4). TYPE 操作數

功能:返回變量的所占用的字節(jié)大小

.data
    bVal BYTE ?
    wVal WORD ?
    dVal DWORD ?

.code
main PROC                   ; 定義主函數開始位置
    ; TYPE 獲取變量所占內存大小
    mov eax, TYPE bVal      ; eax = 0000 0001h
    mov eax, TYPE wVal      ; eax = 0000 0002h
    mov eax, TYPE dVal      ; eax = 0000 0004h
5). LENGTHOF 操作數

功能:獲取數組長度

.data
    byte1 BYTE 10, 20, 30
    array1 WORD 30 DUP(?), 0, 0
    array2 WORD 5 DUP(3 DUP(?))
    array3 DWORD 1, 2, 3, 4
    digitStr BYTE "12345678", 0

.code
main PROC                   ; 定義主函數開始位置
    ; LENGTHOF 計算數組長度
    mov eax, LENGTHOF byte1 ; eax = 0000 0003h
    mov eax, LENGTHOF array1 ; eax = 0000 0020h
    mov eax, LENGTHOF array2 ; eax = 0000 000Fh
    mov eax, LENGTHOF array3 ; eax = 0000 0004h
    mov eax, LENGTHOF digitStr ; eax = 0000 0009h
6). SIZEOF 操作數

功能:計算變量所占用的位數

.data
    intArray WORD 32 DUP(0)

.code
main PROC                   ; 定義主函數開始位置
    ; SIZEOF 計算所占用的字節(jié)位數
    mov eax, SIZEOF intArray    ; eax = 0000 0040h
7). LABEL 指令

**功能:設置別名,使用內存地址訪問之后定義的變量 **

.data
    val16 LABEL WORD
    val32 DWORD 12345678h
    LongValue LABEL DWORD
    val1 WORD 5678h
    val2 WORD 1234h
.code
main PROC                   ; 定義主函數開始位置
    ; LABEL 地址訪問
    mov ax, val16           ; ax = 1234h
    mov dx, [val16 + 2]     ; dx = 5678h
    mov eax, LongValue      ; eax = 1234 5678h

4. 間接尋址

1). 間接操作數

功能:使用地址訪問對應的地址的數值

  • 保護模式
.data
    byteVal BYTE 10h

.code
main PROC                   ; 定義主函數開始位置
    ; 間接操作
    mov esi, OFFSET byteVal
    mov al, [esi]
  • 使用PTR間接操作
inc BYTE PTR [esi]
2). 數組
.data
    arrayW WORD 1000h, 2000h, 3000h

.code
main PROC                   ; 定義主函數開始位置
    ; 數組
    mov esi, OFFSET arrayW
    mov ax, [esi]           ; ax = 1000h
    add esi, 2
    mov ax, [esi]           ; ax = 2000h
    add esi, 2
    mov ax, [esi]           ; ax = 3000h
3). 索引操作數
  • 表現形式
constant[reg]
[constant + reg]

示例:

.data
    arrayB BYTE 10h, 20h, 30h

.code
main PROC                   ; 定義主函數開始位置
    ; 索引操作數
    mov esi, 0
    mov al, arrayB[esi]     ; al = 10h

  • 添加位移
.data
    arrayW WORD 1000h, 2000h, 3000h

.code
main PROC                   ; 定義主函數開始位置
    ; 添加位移
    mov esi, OFFSET arrayW
    mov ax, [esi]           ; ax = 1000h
    mov ax, [esi + 2]       ; ax = 2000h
    mov ax, [esi + 4]       ; ax = 3000h
  • 使用16位寄存器
mov al,arrayB[si]
mov ax,arrayW[di]
mov eax,arrayD[bx]
  • 索引操作數中的比例因子
.data
    arrayD DWORD 100h, 200h, 300h, 400h

.code
main PROC                   ; 定義主函數開始位置
    ; 索引操作數中的比例因子
    mov esi, 3 * TYPE arrayD
    mov eax, arrayD[esi]        ; eax = 0000 0400h
4). 指針

概念:一個變量存儲另一個變量的地址

.data
arrayB BYTE 10h,20h,30h,40h
ptrB DWORD arrayB
  • TYPEDEF 操作數

功能:用戶可自定義類型名

PBYTE TYPEDEF PTR BYTE

5. JMP 和 LOOP 指令

1). JMP 指令
  • 功能

    一種非傳統的傳遞,類似于C語言中的goto語句

  • 語法

JMP destination
  • 創(chuàng)建循環(huán)
top:
.
.
jmp top
2). LOOP 指令
  • 功能

一種非傳統的傳遞,類似于C語言中的循環(huán)語句

  • 語法
LOOP destination
  • 循環(huán)
 mov ax,0
 mov ecx,5
L1:
 inc ax
 loop L1

每次循環(huán)為ax自加1,ecx進行自減,循環(huán)結束時,ax=5,ecx=0

  • 循環(huán)內部修改ECX的值
.data
count DWORD ?
.code
    mov ecx,100     ; 設置循環(huán)計數
top:
    mov count,ecx   ; 保存循環(huán)計數
    .
    mov ecx,20      ; 修改ECX
    .
    mov ecx,count   ; 恢復循環(huán)計數
    loop top
  • 嵌套循環(huán)
.data
    count DWORD ?
.code
    mov ecx,100     ; 設置外層循環(huán)計數
L1:
    mov count,ecx   ; 保存外層循環(huán)計數
    mov ecx,20      ; 設置內層循環(huán)計數
L2:
    .   
    .
    loop L2         ; 重復內層循環(huán)
    mov ecx,count   ; 恢復外層循環(huán)計數
    loop L1         ; 重復外層循環(huán)
3). 數組和
.486        ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall    ; 選擇程序的內存模式為平坦模式,stdcall調用習慣
.stack 4096             ; 設置運行的堆棧大小為4096字節(jié)
ExitProcess PROTO, dwExitCode: DWORD    


COMMENT &
    數組求和
&
.data
    intArray DWORD 10000h, 20000h, 30000h, 40000h

.code
main PROC                   ; 定義主函數開始位置
    mov edi, OFFSET intArray    ; 獲取數組偏移地址
    mov ecx, LENGTHOF intArray  ; 設置循環(huán)計數
    mov eax, 0                  ; 存儲數組元素之和
L1:
    add eax, [edi]              ; 將數組元素值加入eax
    add edi, TYPE intArray      ; 獲取下一個數組元素地址
    LOOP L1                     ; 循環(huán)

    INVOKE ExitProcess, 0   ; 退出程序2
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 
END main            ; 設置了函數的入口與出口
4). 字符串復制
 .486       ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall    ; 選擇程序的內存模式為平坦模式,stdcall調用習慣
.stack 4096             ; 設置運行的堆棧大小為4096字節(jié)
ExitProcess PROTO, dwExitCode: DWORD    


COMMENT &
    數組求和
&
.data
    source BYTE "This is the source string", 0
    target BYTE SIZEOF source DUP(0)

.code
main PROC                   ; 定義主函數開始位置
    mov esi, 0              ; 索引寄存器
    mov ecx, SIZEOF source  ; 循環(huán)計數
L1:
    mov al, source[esi]     ; 從源字符串獲取一個字符, mov指令不能夠有兩個內存操作數
    mov target[esi], al     ; 存儲到目標字符串對應位置
    inc esi                 ; 移動到下一個字符串
    LOOP L1                 ; 循環(huán)

    INVOKE ExitProcess, 0   ; 退出程序
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 
END main            ; 設置了函數的入口與出口
5). 數組求和——64位
; 數組求和

ExitProcess PROTO

.data
intArray QWORD 1000000000000h, 2000000000000h, 3000000000000h, 4000000000000h

.code
main PROC
    mov rdi, OFFSET intArray        ; 設置偏移地址
    mov rcx, LENGTHOF intArray      ; 初始化循環(huán)計數
    mov rax, 0                      ; 數組之和
L1:
    add rax, [rdi]                  ; 加入當前位置的數組值
    add rdi, TYPE intArray          ; 移動得到下一個數組元素
    LOOP L1                         ; 重復執(zhí)行,直到rcx=0
    mov ecx, 0                      ; 退出程序并返回

    call ExitProcess                ; 退出程序
main ENDP
END
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容