拷贝源操作数到目标操作数:
mov 目标操作数,源操作数
源操作数可以是任意单元(r/m/sr/imm) (sr:Segment Register)
目标操作数可以是除了立即数之外的任意单元(r/m/sr)
操作数的宽度必须前后一致
源操作数和目标操作数不能同时为内存单元
加/减/与/或/异或:
?? add/sub/and/or/xor 目标操作数,源操作数
源操作数可以是r/m/imm
目标操作数可以是r/m
操作数的宽度除了源操作数是立即数的情况之外(即:立即数可以是任意位)必须前后一致
?? 非:
从指定内存中写入/读取数据:
mov dword ptr ds:[m],imm ? //写
mov r,dword ptr ds:[r] ???? //读
ptr: Point 代表后面是一个指针 (指针即里面存的不是普通的值,而是个地址)
在8086中设置4个16位的段寄存器,用于管理4种段:
①数据段---ds(Data Segment):数据段寄存器
②代码段---cs(Code Segment):代码段寄存器
③堆栈段---ss(Stack Segment):堆栈段寄存器
④附加段---es(Extra Segment):附加段寄存器
BYTE 字节 = 8(BIT)
WORD 字 = 16(BIT)
DWORD 双字 = 32(BIT)
1KB = 1024 BYTE
寻址公式
(LEA与MOV的区别在于MOV是取地址中的值,而LEA是取地址)
①[imm]形式
读取内存的值 | 向内存中写数据 | 读取内存编号 |
---|---|---|
mov r,dword ptr ds:[m] | mov dword ptr ds:[m],r/imm | lea r,dword ptr ds:[m] |
②[r]形式
读取内存的值 | 向内存中写数据 | 读取内存编号 |
---|---|---|
mov r‘,imm mov r‘‘,dword ptr ds:[r‘] |
mov r,imm mov dword ptr ds:[r],imm |
lea r‘,dword ptr ds:[r‘‘] mov r‘,dword ptr ds:[r‘‘] |
③[r+imm]形式
读取内存的值 | 向内存中写数据 | 读取内存编号 |
---|---|---|
mov r‘,imm? mov r‘‘,dword ptr ds:[r‘+imm] |
mov r,imm? mov dword ptr ds:[r+imm],imm |
lea r,dword ptr ds:[r+imm]? mov r,dword ptr ds:[r+imm] |
④[r+r*(1/2/4/8)]形式
读取内存的值 | 向内存中写数据 | 读取内存编号 |
---|---|---|
mov r‘,imm mov r‘‘,imm? mov r‘‘‘,dword ptr ds:[r‘+r‘‘*4] |
mov r‘,imm mov r‘‘,imm mov dword ptr ds:[r‘+r‘‘*4],imm |
lea?r‘,dword ptr ds:[r‘+r‘‘*4] |
⑤[r+r*(1/2/4/8)+imm]
读取内存的值 | 向内存中写数据 | 读取内存编号 |
---|---|---|
mov r‘,imm mov r‘‘,imm mov r‘‘‘,dword ptr ds:[r‘+r‘‘*4+8] |
mov r‘,imm mov r‘‘,imm mov dword ptr ds:[r‘+r‘‘*4+8],imm |
lea r‘,dword ptr ds:[r‘+r‘‘*4+8] |
压栈与出栈
PUSH与POP的语法:
PUSH:
POP:
?? 注意:
? PUSH/POP加减2/4是看它PUSH/POP的是16/32位的单元
?? 附:
? PUSHAD可将八个通用寄存器中的数据写入内存中,然后即可对八个通用寄存器中的数据进行随意更改
? 而更改完之后需要恢复现场,就可以用POPAD再将刚刚PUSHAD出去的八个通用寄存器中的值原封不动的还原回去
带进/借位加/减法
?ADC/SBB:带 进位/借位 加/减法
? 格式:
? ADC/SBB r/m , r/m/imm ?? 两边不能同时为内存,宽度要一样
? 计算过程:
? 当使用ADC/SBB指令后,在执行加/减法时会先看C位寄存器的值:
??①C位寄存器值为1----执行加/减法时自动多加/减1
??②C位寄存器值位0----正常执行加/减法
e.g.
①C位寄存器值为1MOV EAX,3
MOV ECX,1将C位寄存器值置为1
ADC EAX,ECX
将C位寄存器值置为1
SBB EAX,ECX
②C位寄存器值为0
MOV EAX,3
MOV ECX,1将C位寄存器值置为0
ADC EAX,ECX
将C位寄存器值置为0
SBB EAX,ECX
交换数据:
XCHG:
? 格式:
?XCHG r/m , r/m ?? 两边都必须为容器且不能同时为内存,宽度要一样
e.g.
XCHG AL,CL
XCHG DWORD PTR DS:[12FFC4],EAX
XCHG BYTE PTR DS:[12FFC4],AL
移动数据:
MOVS:
?即:把一块内存中的数据移动到另一块内存中
?内存--内存(注意宽度) (唯一可以两边同时为内存单元的指令)
?此指令默认操作[EDI]和[ESI]寄存器
?格式:
?MOVSB == MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
?MOVSW == MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
?MOVSD == MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
?// 注意:[EDI]搭配的是PTR ES,而不是PTR DS
?计算过程:
??①将[ESI]中存储的地址 对应的 内存中的值 赋给[EDI] 指定的内存
??②[ESI]和[EDI]中存储的地址同时 加/减 1/2/4
?注意:
??[ESI]和[EDI]中存储地址 加/减 取决于D位寄存器的值为 0/1
串存储指令
STOS(Store inTO String):
?功能:
将[EAX/AX/AL]中的值存入[EDI]指定的内存单元(注意:不是存入[EDI]) 中 (存入的值的位数由BYTE/WORD/DWORD决定,存入后[EDI]的值加/减 由 D位寄存器的值是0/1 决定)
?格式:
?STOSB == STOS BYTE PTR ES:[EDI]
?STOSW == STOS WORD PTR ES:[EDI]
?STOSD == STOS DWORD PTR ES:[EDI]
重复指令
REP:
?功能:
按计数寄存器(ECX)中指定的次数重复执行字符串指令
每执行一次,就根据D位寄存器中的值(0/1)把内存地址加/减1/2/4
MOV ECX,10
//注意,ECX,10 中的10为十六进制,即十进制的16
REP MOVSD
REP STOSD
修改[EIP]寄存器
补充[关于[EIP]]:
[EIP]中存储的是一个地址,这个地址就是CPU下一步要去的地方,即决定了CPU即将要执行的代码是什么
想要修改CPU的行为就要修改[EIP]的值
?? JMP:
?功能:
只修改[EIP]的值,相当于专用于[EIP]的MOV指令
?格式:
JMP r/imm
注: JMP只影响[EIP]。
完整操作简述为:
MOV EIP,r/imm
?? CALL:
?功能:
修改[EIP]的值,和JMP一样,但是CALL会修改[ESP]的值,会把下一行指令的地址压栈,而下一行指令的地址的计算是根据CALL这一行存储的字节数相加得到的,然后[ESP]中的值移动到[ESP-4]的内存地址中,相当于把CALL的下一个地址进行一个PUSH。
?格式:
CALL r/addr
注:函数的返回地址就是此处CALL压入栈中的地址值
完整操作简述为:
PUSH [CALL的地址+CALL行存储的字节数]
MOV EIP,m/addr
?? RET:
?功能:
回到刚刚CALL的位置,出栈,相当于一个POP,然后把CALL的下一个地址写入[EIP]。
?格式:
RET
完整操作简述为:
比较指令:
?? CMP:
?功能:
该指令是比较两个操作数,实际上,它相当于SUB指令,但是相减的结构并不保存到第一个操作数中。即:在不改变任何数据的情况下,比较两个操作数的大小,比较结果可以通过Z位、S位寄存器得到。
0001 0000 0010 0000
-0010 0000 -0001 0000
=1111 0000 =0001 0000
S=1 S=0
?格式:
CMP r/m,r/m/imm
?? TEST:
?功能:
两个数值进行与操作,该指令在一定程序上和CMP指令类似,结果不保存,但是会改变相应标志位。
?格式:
TEST r/m,r/m/imm
?常见用法:
用TEST指令判断某个单元是否为0,通过Z位寄存器即可得到结果。
TEST EAX,EAX
e.g.
标准用法MOV EAX,3
TEST EAX,3
常见用法
MOV EAX,3
TEST EAX,EAX
MOV EAX,0
TEST EAX,EAX
原文:https://www.cnblogs.com/tibbors/p/12726912.html