框架
assembly
.386
.MODEL FLAT
ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD
INCLUDE io.h ; header file for input/output
cr EQU 0dh ; carriage return character
Lf EQU 0ah ; line feed
.STACK 4096 ; reserve 4096-byte stack
.DATA ; reserve storage for data
.CODE ; start of main program code
_start:
PUBLIC _start ; make entry point public
END ; end of source code- .386 伪指令,它表示这是一个 32 位程序,能访问 32 位寄存器和地址。
- .DATA 可以用于定义变量
- .CODE 伪指令标识的程序区段包含了可执行的指令
- .STACK 伪指令标识的程序区段定义了运行时堆栈,并设置了其大小
- ExitProcess 函数的原型,它是一个标准的 Windows 服务。原型包含了函数名、PROTO 关键字、一个逗号,以及一个输入参数列表。ExitProcess 的输入参数名称为 dwExitCode
- 标号 main 它标记了程序开始执行的地址。
计算机中数的表示
- 二进制:b
- 八进制:o
- 十六进制:h -> 注意和寄存器区别
进制间的转换
有符号和无符号的区别
- 最高位1为负数
- 最高位0为正数
补码间的转换
正数:直接转换 负数:按位取反,末位加一
ASCII码
48-57: 0-9
65-90: A-Z
97-122:a-z数据类型
| 类型 | 用法 | 大小 |
|---|---|---|
| BYTE | 8 位无符号整数,B 代表字节 | 8位 |
| WORD | 16 位无符号整数 | 16位 |
| DWORD | 32 位无符号整数,D 代表双(字) | 32位 |
寄存器
- EAX:累加器
- EBX:基地址寄存器
- ECX:计数器
- EDX:总是用来放整数除法产生的余数
- ESI:源索引寄存器
- EDI:目标索引寄存器
- EBP:基址指针
- ESP:堆栈指针
操作数的三种模式
立即数——指令中含有数据: 常数、equ 寄存器——数据在寄存器中: 寄存器 存储器——数据在存储区域
存储器操作数其中两种方式
直接寻址——地址在指令中给出: 变量名、[常数] 寄存器间接寻址——数据的地址在寄存器中: [寄存器]
标志位
- ZF——零标志位:结果为0,ZF=1,否则为0
- SF——符号标志位:运算结果位负时,SF置为1
- CF——进位标志位:最高位进位,CF=1,不进位为0
- OF——溢出标志位:两操作数符号相同但结果与符号位相反,OF=1
指令
在几乎所有的汇编语言指令中,左边的操作数是目标操作数,而右边的操作数是源操作数。
复制数据指令
MOV 目的操作数,源操作数相当于
目的操作数 = 源操作数;不合法指令
assembly
mov EAX, BL × 两个寄存器位数不匹配
mov CS, AX × 往代码段寄存器中传送数据
mov [ESI], [EBX] × 源目的操作数都在内存
mov AH, 2589H × 两操作数的位数不匹配
mov ES, DS × 两操作数都是段寄存器
mov DS,3452H × 立即数往段寄存器传送数据
mov 5, AH × 目的操作数为立即数定义变量
assembly
.data ;此为数据区
sum DWORD 0 ;定义名为sum的变量输入输出
IO.H中的宏
| 宏 | 功能 |
|---|---|
dtoa 目的操作数,源操作数 ; | 把源操作数中的双字节数转换成一个11字节长的ASCII码,并存入目的操作数 |
atod 源操作数 ; | 转换一个字符串为一双字长的2进制补码数 |
itoa 目的操作数,源操作数 ; | 把源操作数(寄存器或存储器)中的单字节数转换成一个6字节长的ASCII码,并存入目的操作数 |
atoi 源操作数; | 与atod类似,只是转换的结果存入AX寄存器,并且该数允许的范围是-32768到32767 |
output | 输出源操作数中的字符串,该字符串必须以空字符串结束 |
input 目的操作数,长度 | 输入一个长度为length的字符串,并将该字符串存入目的操作数 |
算数指令
| 指令 | 功能 |
|---|---|
add 目的操作数,源操作数 | 加 |
sub 目的操作数,源操作数 | 减 |
inc 目的操作数 | 自增 |
dec 目的操作数 | 自减 |
neg 目的操作数 | 取二进制数补码数 |
mul 源操作数 | 无符号乘法 乘积为EDX:EAX |
imul 源操作数 | 累加器EAX作为另一个乘数 |
imul 寄存器 源操作数 | 乘积必须目的寄存器长度一致,那么OF、CF清零,否则置为1 |
imul 寄存器 源操作数 立即数 | 寄存器用来存放乘积,如果乘积和目的寄存器长度一致,那么OF、CF清零,否则置为1 |
idiv 源操作数 | 源操作数就是除数,被除数为AX(字节)或DX:AX(字)或EDX:EAX(双字) 商放入AL 余数放入AH |
div 源操作数 | 无符号 |
除法溢出:被除数的高半部大于等于除数
数据大小转换
| 指令 | 功能 |
|---|---|
cbw | 字节转换为字;将AL寄存器中的二进制补码数扩展为AX中的字长 |
cwd | 字转换为双字;将AX寄存器中的二进制数扩展为DX和AX中的双字 |
cdq | 双字转换为四字;将EAX寄存器中的双字扩展为EDX和EAX中的四字 |
分支和循环
| 指令 | 功能 |
|---|---|
jmp StatementLabel | 无条件转移 |
cmp 操作数1 操作数2 | 有条件转移 |
条件转移指令
assembly
j- statementLabel| 无符号 | 描述 | 有符号 |
|---|---|---|
a | 大于 | g |
b | 小于 | l |
e | 等于 | e |
n | 否定 | n |
循环指令
assembly
loop statementLabelloop指令执行以下动作:
- ECX中的值减少
- 如果ECX中新的值是0,则执行下面的语句
- 如过ECX中新的值不是0,则执行转移指令到statementLabel
数组
定义数组:
assembly
变量名 DWORD 大小 DUP (?)取地址:
assembly
lea 目的地址,源数据取当前项:
assembly
[ebx]取出数组中下一项的地址:
assembly
add ebx,4过程
80×86堆栈
分配堆栈:
assembly
.STACK 4096内容出入堆栈
assembly
push 源操作数
pushw 字源操作数
pushd 双字源操作数
pop 目的操作数过程体、调用和返回
过程体
assembly
子程序名 PROC near32
push ebp ;保存寄存器
mov ebp esp ;建立堆栈
·
·
·
pop ebp ;恢复寄存器
ret n ;参数个数×4,释放参数
子程序名 ENDP调用:
assembly
call 目的过程宏定义
assembly
name MACRO 参数列表
local 标号
·
·
·
ENDM局部标号:local
在宏定义体的第一有效行,声明局部标号(多个就写同一行)
串操作
| 指令 | 功能 |
|---|---|
cld | 将DF清零,这样串指令使ESI和EDI的值递增,从左向右处理字符串 |
std | 将DF置1,从右向左处理字符串 |
movs- | b:字节、w:字、d:双字;从源串传送到目的串:地址DS:ESI指向的源元素被复制到地址的ES:EDI |
cmps- | b:字节、w:字、d:双字;为了判断两个串是否相同,那么repe前缀和cmps最好一起使用 |
scas- | b:字节、w:字、d:双字;用来在串中扫描某个特定的串元素是否在串中存在 |
stos- | b:字节、w:字、d:双字;将寄存器中的内容复制为目的串的某个元素了,不影响标志位 |
lods- | b:字节、w:字、d:双字;按照串元素的长度复制源串中的元素到AL,AX和EAX寄存器中 |
重复前缀
| 助记符 | 循环条件 |
|---|---|
rep | ECX>0 |
repz/repe | ECX>0 && ZF=1 |
repnz/repne | ECX>0 && ZF=0 |
位运算
assembly
and 目的操作数,源操作数
or 目的操作数,源操作数
xor 目的操作数,源操作数
nor 目的操作数,源操作数
test 目的操作数,源操作数 ;与操作不存结果,影响标志位移位指令和循环移位指令
shl和shr是逻辑移位
assembly
shl 目的地址,count ;逻辑左,CF:为左边第一位,末尾补0
shr 目的地址,count ;逻辑右,CF:为右边第一位,首位补0sal和sar是算数移位
assembly
sal 目的地址,count ;算数左,CF:为左边第一位,末尾补0
sar 目的地址,count ;算数右,CF:为右边第一位,首位为1补1,为0补0一位移位中,结果符号位的值与源操作数相同则OF置为0,否则置1.