知识点
小知识
ptr 强制类型转换
lea 指令可以用来将一个内存地址直接赋给目的操作数,例如:
lea eax,[ebx+8] 就是将ebx+8这个值直接赋给eax
mov eax,[ebx+8]则是把内存地址为ebx+8处的数据赋给eax。
| 32 位 | 
16 位 | 
8 位(高) | 
8 位(低) | 
| EAX | 
AX | 
AH | 
AL | 
| EBX | 
BX | 
BH | 
BL | 
| ECX | 
CX | 
CH | 
CL | 
| EDX | 
DX | 
DH | 
DL | 
| 32 位 | 
16 位 | 
32 位 | 
16 位 | 
| ESI | 
SI | 
EBP | 
BP | 
| EDI | 
DI | 
ESP | 
SP | 
- 乘除指令默认使用EAX。它常常被称为扩展累加器(extended accumulator)寄存器。
 
- CPU 默认使用 ECX 为循环计数器。
 
- ESP 用于寻址堆栈(一种系统内存结构)数据。它极少用于一般算术运算和数据传输,通常被称为扩展堆栈指针(extended stack pointer)寄存器。
 
- ESI 和 EDI 用于高速存储器传输指令,有时也被称为扩展源变址(extended source index)寄存器和扩展目的变址(extended destination index)寄存器。
 
- 高级语言通过 EBP 来引用堆栈中的函数参数和局部变量。除了高级编程,它不用于一般算术运算和数据传输。它常常被称为扩展帧指针(extended frame pointer)寄存器。
 
- 进位标志位(CF),与目标位置相比,无符号算术运算结果太大时,设置该标志位。
 
- 溢出标志位(OF),与目标位置相比,有符号算术运算结果太大或太小时,设置该标志位。
 
- 符号标志位(SF),算术或逻辑操作产生负结果时,设置该标志位。
 
- 零标志位(ZF),算术或逻辑操作产生的结果为零时,设置该标志位。
 
- 辅助进位标志位(AC),算术操作在 8 位操作数中产生了位 3 向位 4 的进位时,设置该标志位。
 
- 奇偶校验标志位(PF),结果的最低有效字节包含偶数个 1 时,设置该标志位,否则,清除该标志位。一般情况下,如果数据有可能被修改或损坏时,该标志位用于进行 错误检测。
 
| 操作数大小 | 
可用寄存器 | 
| 8 位 | 
AL、BL、CL、DL、DIL、SIL、BPL、SPL、R8L、R9L、R10L、R11L、R12L、R13L、R14L、R15L | 
| 16 位 | 
AX、BX、CX、DX、DI、SI、BP、SP、R8W、R9W、R10W、R11W、R12W、R13W、R14W、R15W | 
| 32 位 | 
EAX、EBX、ECX、EDX、EDI、ESI、EBP、ESP、R8D、R9D、R10D、R11D、R12D、R13D、R14D、R15D | 
| 64 位 | 
RAX、RBX、RCX、RDX、RDI、RSI、RBP、RSP、R8、R9、R10、R11、R12、R13、R14、R15 | 
| h | 
十六进制 | 
r | 
编码实数 | 
| q/o | 
八进制 | 
t | 
十进制(备用) | 
| d | 
十进制 | 
y | 
二进制(备用) | 
| b | 
二进制 | 
 | 
 | 
1
2
3
4
5
6
7
  | 
26         ;十进制
26d        ;十进制
11010011b  ;二进制
42q        ;八进制
42o        ;八进制
1Ah        ;十六进制
0A3h       ;十六进制
  | 
 
 
| 运算符 | 
名称 | 
优先级 | 
| () | 
圆括号 | 
1 | 
| +,- | 
一元加、减 | 
2 | 
| *, / | 
乘、除 | 
3 | 
| MOD | 
取模 | 
3 | 
| +, - | 
加、减 | 
4 | 
| $ | 
PARITY? | 
DWORD | 
STDCALL | 
| ? | 
PASCAL | 
FAR | 
SWORD | 
| @B | 
QWORD | 
FAR16 | 
SYSCALL | 
| @F | 
REAL4 | 
FORTRAN | 
TBYTE | 
| ADDR | 
REAL8 | 
FWORD | 
VARARG | 
| BASIC | 
REAL10 | 
NEAR | 
WORD | 
| BYTE | 
SBYTE | 
NEAR16 | 
ZERO? | 
| C | 
SDORD | 
OVERFLOW? | 
 | 
| CARRY? | 
SIGN? | 
 | 
 | 
.DATA 伪指令进行标识:
.data
.CODE 伪指令标识的程序区段包含了可执行的指令:
.code
.STACK 伪指令标识的程序区段定义了运行时堆栈,并设置了其大小:
.stack 100h
指令
一条指令有四个组成部分:
- 标号(可选)
 
- 指令助记符(必需)
 
- 操作数(通常是必需的)
 
- 注释(可选)
 
不同部分的位置安排如下所示:
[label: ] mnemonic [operands] [;comment]
标号
数据标号
代码标号
1
2
3
4
  | 
target:
        mov ax,bx
        ...
        jmp target
  | 
 
指令助记符
| 助记符 | 
说明 | 
助记符 | 
说明 | 
| MOV | 
传送(分配)数值 | 
MUL | 
两个数值相乘 | 
| ADD | 
两个数值相加 | 
JMP | 
跳转到一个新位置 | 
| SUB | 
从一个数值中减去另一个数值 | 
CALL | 
调用一个子程序 | 
操作数
| 示例 | 
操作数类型 | 
示例 | 
操作数类型 | 
| 96 | 
整数常量 | 
eax | 
寄存器 | 
| 2+4 | 
整数表达式 | 
count | 
内存 | 
STC 指令没有操作数:
stc                    ;进位标志位置 1
INC 指令有一个操作数:
inc eax                ;EAX 加 1
MOV 指令有两个操作数:
mov count, ebx         ;将 EBX 传送给变量 count
IMUL 指令有三个操作数,第一个是目的操作数,第二个和第三个是进行乘法的源操作数:
imul eax,ebx,5
注释
- 单行注释,用分号(;)开始。汇编器将忽略在同一行上分号之后的所有字符。
 
- 块注释,用 COMMENT 伪指令和一个用户定义的符号开始。汇编器将忽略其后所有的文本行,直到相同的用户定义符号出现为止。
 
1
2
3
4
  | 
COMMENT !
        This line is a comment.
        This line is also a comment.
!
  | 
 
NOP(空操作)指令
1
2
3
4
5
6
7
8
9
  | 
.data                          ;此为数据区
sum DWORD 0                    ;定义名为sum的变量
.code                          ;此为代码区
main PROC
    mov eax,5                  ;将数字5送入而eax寄存器
    add eax,6                  ;eax寄存器加6
    mox sum,eax
    INVOKE ExitProcess,0       ;结束程序
main ENDP
  | 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  | 
; AddTwo.asm -两个 32 位整数相加
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD
.code
main PROC
mov  eax,5  ;将数字5送入eax寄存器
add      eax,6  ;eax寄存器加6
INVOKE ExitProcess,0
main ENDP
END main
  | 
 
- 第 3 行是 .386 伪指令,它表示这是一个 32 位程序,能访问 32 位寄存器和地址。
 
- 第 4 行选择了程序的内存模式(flat),并确定了子程序的调用规范(称为 stdcall)。其原因是 32 位 Windows 服务要求使用 stdcall 规范。
 
- 第 5 行为运行时堆栈保留了 4096 字节的存储空间,每个程序都必须有。
 
- 第 6 行声明了 ExitProcess 函数的原型,它是一个标准的 Windows 服务。原型包含了函数名、PROTO 关键字、一个逗号,以及一个输入参数列表。ExitProcess 的输入参数名称为 dwExitCode。
 
汇编伪指令回顾
CODE 的下一行声明程序的入口
ENDP 伪指令标记一个过程的结束。
main ENDP
END 伪指令标记一个程序的结束,并要引用程序入口:
END main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  | 
; AddTwo.asm - adds two 32-bit integers.
; Chapter 3 example
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD
    00000000                            .code
    00000000                            main PROC
    00000000 B8 00000005                    mov eax, 5
    00000005 83 C0 06                       add eax,6
                                            invoke ExitProcess,0
    00000008 6A 00                          push        +000000000h
    0000000A E8 00000000 E                  call        ExitProcess
    0000000F                            main ENDP
                                        END main
  | 
 
数据类型以及数据定义详解
内部数据类型
| 类型 | 
用法 | 
| BYTE | 
8 位无符号整数,B 代表字节 | 
| SBYTE | 
8 位有符号整数,S 代表有符号 | 
| WORD | 
16 位无符号整数 | 
| SWORD | 
16 位有符号整数 | 
| DWORD | 
32 位无符号整数,D 代表双(字) | 
| SDWORD | 
32 位有符号整数,SD 代表有符号双(字) | 
| FWORD | 
48 位整数(保护模式中的远指针) | 
| QWORD | 
64 位整数,Q 代表四(字) | 
| TBYTE | 
80 位(10 字节)整数,T 代表 10 字节 | 
| REAL4 | 
32 位(4 字节)IEEE 短实数 | 
| REAL8 | 
64 位(8 字节)IEEE 长实数 | 
| REAL10 | 
80 位(10 字节)IEEE 扩展实数 | 
数据定义语句
数据定义语法如下所示:
[name] directive initializer [,initializer]…
下面是数据定义语句的一个例子:
| 伪指令 | 
用法 | 
伪指令 | 
用法 | 
| DB | 
8位整数 | 
DQ | 
64 位整数或实数 | 
| DW | 
16 位整数 | 
DT | 
定义 80 位(10 字节)整数 | 
| DD | 
32 位整数或实数 | 
 | 
 | 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  | 
;AddTowSum.asm
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD
.data
sum DWORD 0
.code
main PROC
    mov eax,5
    add eax,6
    mov sum,eax
    INVOKE ExitProcess,0
main ENDP
END main
  | 
 
定义 BYTE 和 SBYTE 数据
1
2
3
4
5
6
7
8
9
  | 
value1 BYTE  'A'    ;字符常量
value2 BYTE  0      ;最小无符号字节
value3 BYTE  255    ;最大无符号字节
value4 SBYTE -128   ;最小有符号字节
value5 SBYTE +127   ;最大有符号字节
value6 BYTE ?       ;变量
val1 DB 255    ;无符号字节
val2 DB -128  ;有符号字节
  | 
 
多初始值
| 偏移量 | 
数值 | 
| 0000 | 
10 | 
| 0001 | 
20 | 
| 0002 | 
30 | 
| 0003 | 
40 | 
1
2
3
  | 
list BYTE 10,20,30,40
     BYTE 50,60,70,80
     BYTE 81,82,83,84
  | 
 
1
2
  | 
list1 BYTE 10, 32, 41h, 00100010b
list2 BYTE 0Ah, 20h, 'A', 22h
  | 
 
list1与list2不同进制,但值相同
定义字符串
1
2
  | 
greeting1 BYTE "Good afternoon",0
greeting2 BYTE 'Good night',0
  | 
 
0作为结束标记
1
2
3
4
  | 
greeting1 BYTE "Welcome to the Encryption Demo program "
          BYTE "created by Kip Irvine.",0dh, 0ah
          BYTE "If you wish to modify this program, please "
          BYTE "send me a copy.",0dh,0ah,0
  | 
 
十六进制代码 0Dh 和 0Ah 也被称为 CR/LF (回车换行符)或行结束字符。
1
2
3
4
  | 
greeting1 BYTE "Welcome to the Encryption Demo program "
和
greeting1 \
BYTE "Welcome to the Encryption Demo program "
  | 
 
行连续字符(\)把两个源代码行连接成一条语句,它必须是一行的最后一个字符。上面的语句是等价的。
DUP 操作符
1
2
3
  | 
BYTE 20 DUP ( 0 )      ;20 个字节,值都为 0
BYTE 20 DUP ( ? )      ;20 个字节,非初始化
BYTE 4 DUP ( "STACK" ) ; 20 个字节:
  | 
 
定义 WORD 和 SWORD 数据
1
2
3
  | 
word1 WORD 65535    ;最大无符号数
word2 SWORD -32768  ;最小有符号数
word3 WORD ?        ;未初始化,无符号
  | 
 
1
2
  | 
val1 DW 65535   ;无符号
val2 DW -32768  ;有符号
  | 
 
也可以使用传统的 DW 伪指令
| 偏移量 | 
数值 | 
| 0000 | 
1 | 
| 0002 | 
2 | 
| 0004 | 
3 | 
| 0006 | 
4 | 
| 0008 | 
5 | 
1
  | 
array WORD 5 DUP (?) ; 5 个数值,未初始化
  | 
 
定义 DWORD 和 SDWORD 数据
1
2
3
  | 
val1 DWORD 12345678h    ;无符号
val2 SDWORD -2147483648 ;有符号
val3 DWORD 20 DUP (?)   ;无符号数组
  | 
 
1
2
  | 
val1 DD 12345678h ;无符号
val2 DD -2147483648 ;有符号
  | 
 
| 偏移量 | 
数值 | 
| 0000 | 
1 | 
| 0004 | 
2 | 
| 0008 | 
3 | 
| 000C | 
4 | 
| 0010 | 
5 | 
定义 QWORD 数据
1
2
  | 
quad1 QWORD 1234567812345678h
quad1 DQ 1234567812345678h
  |