九、汇编减法指令sub
1.sun指令
减法指令sub(subtract)
格式: sub 操作数A,操作数B A = A-B
功能:两个操作数的相减,即从A中减去B,其结果放在A中
ZF零标志位:若当前的运算结果为零,则ZF为1,否则为0
注意:SUB指令影响ZF标志位
十、CMP和转移指令
1.比较指令CMP
格式:CMP 操作数A,操作数B //A - B
功能:两个操作数的相减,即从A中减去B,其结果会影响标志位,
对标志位的影响与SUB指令相同。
CMP指令主要是用于配合条件转移指令使用,如:JZ/JE 当ZF=1时跳转
2.等于条件转移指令JE/JZ
格式:JE/JZ 标号 //等于跳转
功能:ZF=1,跳转到指定地址执行
说明:
(1)JE与JZ等价,他们是根据标志位ZF进制转移的指令
(2)JE、JZ均为一条指令的两种助记符表示方法
1 if( a != b ) JE/JZ
{
2 a = b;
}
3 a = 2*b;
3.不等于转移指令JNE/JNZ
(1)JNE/JNZ功能
条件转移指令JNE/JNZ //不等于转移
格式:JNE/JNZ 标号
功能:ZF=0,转移至标号地址处执行
1 if( a == b ) JNE/JNZ
{
2 a = b;
}
3 a = 2*b;
4.无条件跳转指令jmp和goto指令
(1)GOTO与JMP
无条件跳转指令
格式:JMP A
(2)其中A为转移的目的地址。程序转移到目的地址所指向的指令继续往下执行。
(3)本组指令对标志位无影响
5.有符号小于/不大于等于转移指令JL/JNGE
格式: JL/JNGE 标号地址
功能: 小于/不大于等于 时转移到标号地址
JL 有符号 小于 则跳转 (Jump if less)
JNGE 有符号 不大于等于 则跳转 (Jump if not greater or equal)
SF = 1; 符号标志位为1 则跳转到标号地址执行(结果为负数)
Jump 跳转/转移
Not 不
Equal 相等
Zero 零
Less 小于
Greater 大于
if( a >=b ) //JL/JNGE
{
printf("do a>=b\n");
}
printf("do a < b\n");
6.有符号小于等于/不大于转移指令JLE/JNG
格式: JLE/JNG 标号地址
功能: 小于等于/不大于 时转到标号地址
JNG 有符号 不大于 则跳转 (Jump if Not Greater)
JLE 有符号 小于等于 则跳转 (Jump if Less or Equal)
ZF = 1 || SF != OF (溢出标志位) (SF = 1 && OF = 0 两个数相减 结果为负,且没有溢出)
(SF = 0 && OF = 1 两个数相减 结果为正,且有溢出)
7.有符号大于/不小于等于转移指令JG/JNLE
格式: JG/JNLE 标号地址
功能: 大于/不小于等于 时转到目标地址
JG 有符号 大于 则跳转 (Jump if Greater)
JNLE 有符号 不小于等于 则跳转 (Jump if Not Less or Equal)
ZF = 0 && SF = OF (SF=1 && OF=1 两个数相减 结果为负,有溢出)
(SF=0 && OF=0 两个数相减 结果为正,没有溢出)
8.程序状态字寄存器PSW
(1)CF进位标志位
当执行一个加法(减法)运算时,最高位产生进位(或借位)时,CF为1,否则为0
(2)ZF零标志位
若当前的运算结果为零,则ZF为1,否则为0
(3)SF符号标志位
该标志位于运算结果的最高位相同。即运算结果为负,则SF为1,否则为0
(4)OF溢出标志位
若运算结果超出机器能够表示的范围称为溢出,此时OF为1,否则为0
判断否是溢出的方法是:
进行二进制运算时,最高位的进位与次高位的进位值进行异或运算
若运算结果为1则表示溢出OF=1 ,否则OF=0
三条原则:
同号相加和异号相减才会发生溢出
同号相加结果的符号与参与运算的符号不同就溢出
异号相减结果的符号位与被减数的符号位不同就产生溢出
(5)PF奇偶标志
当运算结果的最低16位中含1的个数为偶数则PF=1,否则PF=0
(6)AF辅助进位标志
一个加法(减法)运算结果的低4位向高4位有进位(或借位)时则AF=1,否则AF=0
(7)TF跟踪标志
该标志位为方便程序调试而设置。若TF=1,CPU出于单步工作方式,
即在每条指令执行结束后,产生中断
(8)IF中断标志位
该标志位用来控制CPU是否响应可屏蔽中断。若IF=1则运行中断,否则禁止中断
(9)DF方向标志
该标志位用来控制串处理指令的处理方向。若DF=1则串处理过程中自动递减,否则自动递增
9.无符号大于转移指令 JA/JNBE
JA : 高于 时跳转 即 > 时跳转
JNBE : 不低于等于 时跳转 即 <= 时不跳转
Above 高于
Below 低于
JA与JG区别
JG是带符号数比较 >
JA是无符号数比较 >
CF = 0 && ZF = 0 则跳转
10.无符号大于等于转移指令JNB/JAE/JNC
JNB : 不低于 时跳转 即 >= 时不跳转
JAE : 高于等于 时跳转 即 < 时不跳转
JNC : Jump Not carry 没有进位时跳转 //CF=0
unsigned int a = 5, b = 10;
if(a2 < b2) //JAE/JNB
{
....
}
11.无符号小于转移指令JB/JNAE/JC
JB: 低于 时跳转 即 < 时跳转
JNAE: 高于等于 时不跳转 即 >= 时不跳转
JC : Jump Carry 进位时跳转 //CF=1
12.无符号大于转移指令JBE/JNA
JBE: 低于等于 时跳转 即 <= 时跳转
JNA: 高于 时不跳转 即 > 时不跳转
课后自己写if条件语句来验证,注意区分无符号转移和有符号转移的区别
十一、CALL框架
EBP 寄存器 栈底指针
ESP 寄存器 栈顶指针
1.EBP栈底指针
EBP是一个特殊的寄存器,通过EBP+偏移量 可以访问CALL里边的局部变量
它的低16位叫BP。 //EAX和AX的关系
2.ESP栈顶指针
ESP栈顶指针与EBP栈底指针构成一段空间大小,一般就是本CALL局部变量的空间大小总和。
ESP指针配合EBP使用。//SP
总结:
(1)每个CALL会分配一个独立的栈段空间,供局部变量使用
(2)CALL栈平衡。进入CALL前与出CALL后,EBP和ESP的值不变
十二、PUSH、POP和CALL栈平衡RETN指令
1.PUSH 入栈指令 (压栈指令):
格式: PUSH 操作数
push ebp相当于:
sub esp,4
mov [esp],ebp
操作数可以是寄存器,存储器,或者立即数
2.POP出栈指令 (弹栈指令)
格式:POP 操作数
pop ebp 相当于:
mov ebp,[esp]
add esp,4
操作数是寄存器,或者存储器,不能是立即数
3.代码分析
(1)测试PUSH和POP 与ESP栈顶指针关系
(2)CALL和RET(RETN)与ESP的关系
CALL 执行时 会 PUSH EIP
RETN 执行时 会 POP EIP
(3)参数和局部变量的表示
[EBP - ??] ;本call中的局部变量
[EBP + ??] ;上一个call 局部变量,作为传入参数
十三、调用约定
配置属性 --> c/c++ -->高级-->调用约定
1.cdecl调用约定
__cdecl 是C Declaration的缩写,所以参数从右到左依次入栈,
这些参数由调用者清除,称为手动清栈。
VC++ 默认约定__cdecl
(1)源代码
int __cdecl add1(int a,int b)
{
return a + b;
}
(2)生成的汇编代码
013C1000 /$ 55 push ebp ; 保存main函数EBP栈底指针
013C1001 |. 8BEC mov ebp, esp ; 把栈底指针指向上一个call的栈顶
013C1003 |. 8B45 08 mov eax, dword ptr [arg.1] ; eax = a
013C1006 |. 0345 0C add eax, dword ptr [arg.2] ; eax=eax+b=a + b
013C1009 |. 5D pop ebp ; 恢复main函数的EBP栈底指针
013C100A \. C3 ret
(3)调用代码
013C1021 |. 6A 02 push 2
013C1023 |. 6A 01 push 1
013C1025 |. E8 D6FFFFFF call 013C1000
013C102A |. 83C4 08 add esp, 8
2.stdcall 调用约定
API函数调用约定 __stdcall
_stdcall 是standardcall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,
如果是调用类成员的话,最后一个入栈的是this指针。
这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是retn X,
X表示参数占用的字节数(内存空间大小),CPU在ret之后自动弹出X个字节的栈空间,称为自动清栈。
(1)源代码
int __stdcall add2(int a,int b)
{
return a + b;
}
(2)生成的汇编代码
009B1010 /$ 55 push ebp
009B1011 |. 8BEC mov ebp, esp
009B1013 |. 8B45 08 mov eax, dword ptr [ebp+8]
009B1016 |. 0345 0C add eax, dword ptr [ebp+0C]
009B1019 |. 5D pop ebp
009B101A \. C2 0800 ret 8
(3)调用代码
009B103D |. 6A 04 push 4
009B103F |. 6A 03 push 3
009B1041 |. E8 CAFFFFFF call 009B1010
3.fastcall 调用约定
_fastcall 是编译器指定的快速调用方式
fastcall通常规定将前两个(或者若干个)参数由寄存器传递,其余参数还是通过堆栈传递。
不同编译器编译的程序规定的寄存器不同。返回方式和stdcall相同。
(1)源代码
int __fastcall add3(int a,int b)
{
return a + b;
}
(2)生成的汇编代码
00221020 /$ 55 push ebp
00221021 |. 8BEC mov ebp, esp
00221023 |. 83EC 08 sub esp, 8
00221026 |. 8955 F8 mov dword ptr [local.2], edx
00221029 |. 894D FC mov dword ptr [local.1], ecx
0022102C |. 8B45 FC mov eax, dword ptr [local.1]
0022102F |. 0345 F8 add eax, dword ptr [local.2]
00221032 |. 8BE5 mov esp, ebp
00221034 |. 5D pop ebp
00221035 \. C3 ret
(3)调用代码
00221066 |. BA 06000000 mov edx, 6
0022106B |. B9 05000000 mov ecx, 5
00221070 |. E8 ABFFFFFF call 00221020
参数传递没有用到栈,所以不用堆栈平衡
但是如果参数比较多的话,那就需要自己平衡堆栈了:
00101040 /$ 55 push ebp
00101041 |. 8BEC mov ebp, esp
00101043 |. 83EC 08 sub esp, 8
00101046 |. 8955 F8 mov dword ptr [local.2], edx
00101049 |. 894D FC mov dword ptr [local.1], ecx
0010104C |. 8B45 FC mov eax, dword ptr [local.1]
0010104F |. 0345 F8 add eax, dword ptr [local.2]
00101052 |. 0345 08 add eax, dword ptr [arg1]
00101055 |. 0345 0C add eax, dword ptr [arg2]
00101058 |. 0345 10 add eax, dword ptr [arg3]
0010105B |. 8BE5 mov esp, ebp
0010105D |. 5D pop ebp
0010105E \. C2 0C00 ret 0C
001010A5 |. 6A 0B push 0B ; /Arg3 = 0B
001010A7 |. 6A 0A push 0A ; |Arg2 = 0A
001010A9 |. 6A 09 push 9 ; |Arg1 = 9
001010AB |. BA 08000000 mov edx, 8 ; |
001010B0 |. B9 07000000 mov ecx, 7 ; |
001010B5 |. E8 86FFFFFF call 00101040 ; \Lesson13.00101040
注:
C中不加说明的默认函数为_cdecl方式
C++也一样,但是默认的调用方式可以在IDE(开发环境)中设置
带有可变参数的函数必须且只能使用_cdecl方式,如:
int printf(char* fmtstr,...);
int scanf(char* fmtstr,...);
十四、常见C语句反汇编练习
1.if-else 结构反汇编代码分析
因为if{...} 语句块中的代码被执行的话,else{...}语句块的代码不会被执行,
所以if{...} 中的代码执行完成之后,需要(jmp)无条件跳转到else{...}语句块
后面的代码执行。
ifelse02.exe 作为课后练习
2.switch-case结构反汇编代码分析
(1)普通情况
013E1000 /$ 55 push ebp ; INT Lesson14.main(void)
013E1001 |. 8BEC mov ebp, esp
013E1003 |. 83EC 08 sub esp, 8 ; 两个4字节的局部变量
013E1006 |. 68 F4203E01 push offset 013E20F4 ; ASCII "switch-case",LF
013E100B |. FF15 A0203E01 call dword ptr [<&MSVCR100.printf>]
013E1011 |. 83C4 04 add esp, 4
013E1014 |. C745 FC 03000 mov dword ptr [ebp-4], 3 ; a = 3
013E101B |. 8B45 FC mov eax, dword ptr [ebp-4] ; eax = a
013E101E |. 8945 F8 mov dword ptr [ebp-8], eax ; temp=eax=a
013E1021 |. 837D F8 01 cmp dword ptr [ebp-8], 1 ; temp与1作比较
013E1025 |.- 74 0E je short 013E1035 ; 等于则跳转
013E1027 |. 837D F8 02 cmp dword ptr [ebp-8], 2 ; temp与2作比较
013E102B |.- 74 18 je short 013E1045
013E102D |. 837D F8 0A cmp dword ptr [ebp-8], 0A ; temp与10作比较
013E1031 |.- 74 22 je short 013E1055
013E1033 |.- EB 30 jmp short 013E1065
013E1035 |> 68 04213E01 push offset 013E2104 ; ASCII "111",LF
013E103A |. FF15 A0203E01 call dword ptr [<&MSVCR100.printf>]
013E1040 |. 83C4 04 add esp, 4
013E1043 |.- EB 2E jmp short 013E1073 ; jmp printf("end")
013E1045 |> 68 0C213E01 push offset 013E210C ; ASCII "222",LF
013E104A |. FF15 A0203E01 call dword ptr [<&MSVCR100.printf>]
013E1050 |. 83C4 04 add esp, 4
013E1053 |.- EB 1E jmp short 013E1073
013E1055 |> 68 14213E01 push offset 013E2114 ; ASCII "333",LF
013E105A |. FF15 A0203E01 call dword ptr [<&MSVCR100.printf>]
013E1060 |. 83C4 04 add esp, 4
013E1063 |.- EB 0E jmp short 013E1073
013E1065 |> 68 1C213E01 push offset 013E211C ; ASCII "default",LF
013E106A |. FF15 A0203E01 call dword ptr [<&MSVCR100.printf>]
013E1070 |. 83C4 04 add esp, 4
013E1073 |> 68 28213E01 push offset 013E2128 ; ASCII "end",LF
013E1078 |. FF15 A0203E01 call dword ptr [<&MSVCR100.printf>]
013E107E |. 83C4 04 add esp, 4
013E1081 |. 33C0 xor eax, eax
013E1083 |. 8BE5 mov esp, ebp
013E1085 |. 5D pop ebp
013E1086 \. C3 ret
(2)跳转表
002A1000 /$ 55 push ebp
002A1001 |. 8BEC mov ebp, esp
002A1003 |. 83EC 08 sub esp, 8
002A1006 |. 68 F4202A00 push offset 002A20F4 ; ASCII "switch-case 2",LF
002A100B |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A1011 |. 83C4 04 add esp, 4
002A1014 |. C745 FC 20000000 mov dword ptr [local.1], 20
002A101B |. 8B45 FC mov eax, dword ptr [local.1]
002A101E |. 8945 F8 mov dword ptr [local.2], eax
002A1021 |. 8B4D F8 mov ecx, dword ptr [local.2]
002A1024 |. 83E9 10 sub ecx, 10 ; temp = temp - 0x10
002A1027 |. 894D F8 mov dword ptr [local.2], ecx
002A102A |. 837D F8 12 cmp dword ptr [local.2], 12 ; temp 与 0x12 做比较
002A102E |. 77 61 ja short 002A1091
002A1030 |. 8B55 F8 mov edx, dword ptr [local.2] ; edx = temp
002A1033 |. 0FB682 CC102A00 movzx eax, byte ptr [edx+2A10CC] ; Switch (cases 0..5, 6 exits)
002A103A |. FF2485 B4102A00 jmp dword ptr [eax*4+2A10B4]
002A1041 |> 68 04212A00 push offset 002A2104 ; ASCII "0x13",LF, case 1 of switch Lesson14.2A1033
002A1046 |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A104C |. 83C4 04 add esp, 4
002A104F |. EB 4E jmp short 002A109F
002A1051 |> 68 0C212A00 push offset 002A210C ; ASCII "0x15",LF, case 2 of switch Lesson14.2A1033
002A1056 |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A105C |. 83C4 04 add esp, 4
002A105F |. EB 3E jmp short 002A109F
002A1061 |> 68 14212A00 push offset 002A2114 ; ASCII "0x10",LF, case 0 of switch Lesson14.2A1033
002A1066 |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A106C |. 83C4 04 add esp, 4
002A106F |. EB 2E jmp short 002A109F
002A1071 |> 68 1C212A00 push offset 002A211C ; ASCII "0x20",LF, case 3 of switch Lesson14.2A1033
002A1076 |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A107C |. 83C4 04 add esp, 4
002A107F |. EB 1E jmp short 002A109F
002A1081 |> 68 24212A00 push offset 002A2124 ; ASCII "0x22",LF, case 4 of switch Lesson14.2A1033
002A1086 |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A108C |. 83C4 04 add esp, 4
002A108F |. EB 0E jmp short 002A109F
002A1091 |> 68 2C212A00 push offset 002A212C ; ASCII "default",LF, case 5 of switch Lesson14.2A1033
002A1096 |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A109C |. 83C4 04 add esp, 4
002A109F |> 68 38212A00 push offset 002A2138 ; ASCII "end",LF
002A10A4 |. FF15 A0202A00 call dword ptr [<&MSVCR100.printf>]
002A10AA |. 83C4 04 add esp, 4
002A10AD |. 33C0 xor eax, eax
002A10AF |. 8BE5 mov esp, ebp
002A10B1 |. 5D pop ebp
002A10B2 \. C3 ret
3.for循环结构反汇编代码分析
for(int i = 1; i<=10; ++i)
{
printf("%d",i);
}
(1)禁用优化情况下的for循环反汇编代码(0x43字节)
00C51000 /$ 55 push ebp
00C51001 |. 8BEC mov ebp, esp
00C51003 |. 51 push ecx ; sub esp,4; int i;
00C51004 |. 68 F420C500 push offset 00C520F4 ; /Format = "for ",LF,""
00C51009 |. FF15 A020C500 call dword ptr [<&MSVCR100.printf>] ; \MSVCR100.printf
00C5100F |. 83C4 04 add esp, 4
00C51012 |. C745 FC 01000000 mov dword ptr [local.1], 1 ; i = 1
00C51019 |. EB 09 jmp short 00C51024
00C5101B |> 8B45 FC /mov eax, dword ptr [local.1]
00C5101E |. 83C0 01 |add eax, 1
00C51021 |. 8945 FC |mov dword ptr [local.1], eax ; ++i; i = i+1;
00C51024 |> 837D FC 0A |cmp dword ptr [local.1], 0A
00C51028 |. 7F 14 |jg short 00C5103E ; i > 10 跳转
00C5102A |. 8B4D FC |mov ecx, dword ptr [local.1]
00C5102D |. 51 |push ecx ; /<%d> => [LOCAL.1]
00C5102E |. 68 FC20C500 |push offset 00C520FC ; |Format = "%d"
00C51033 |. FF15 A020C500 |call dword ptr [<&MSVCR100.printf>] ; \MSVCR100.printf
00C51039 |. 83C4 08 |add esp, 8 ; esp = esp + 8
00C5103C |.^ EB DD \jmp short 00C5101B
00C5103E |> 33C0 xor eax, eax
00C51040 |. 8BE5 mov esp, ebp
00C51042 |. 5D pop ebp
00C51043 \. C3 ret ; return 0;
(2)大小最小化优化情况下的for循环反汇编代码(0x27字节)
010C1000 /$ 56 push esi
010C1001 |. 8B35 A0200C01 mov esi, dword ptr [<&MSVCR100.printf>]
010C1007 |. 57 push edi
010C1008 |. 68 F4200C01 push offset 010C20F4 ; /Format = "for ",LF,""
010C100D |. FFD6 call esi ; \MSVCR100.printf
010C100F |. 33FF xor edi, edi
010C1011 |. 59 pop ecx ; add esp,4; esp = esp + 4
010C1012 |. 47 inc edi ; edi = 1; int i = 1;
010C1013 |> 57 /push edi ; /<%d>
010C1014 |. 68 FC200C01 |push offset 010C20FC ; |Format = "%d"
010C1019 |. FFD6 |call esi ; \MSVCR100.printf
010C101B |. 47 |inc edi ; ++i
010C101C |. 59 |pop ecx
010C101D |. 59 |pop ecx ; add esp,8
010C101E |. 83FF 0A |cmp edi, 0A
010C1021 |.^ 7E F0 \jle short 010C1013 ; if(i <=10 ) goto 0140c1013
010C1023 |. 5F pop edi
010C1024 |. 33C0 xor eax, eax
010C1026 |. 5E pop esi
010C1027 \. C3 ret
(3)最大化速度优化情况下的for循环汇编代码
010D1000 /$ 56 push esi
010D1001 |. 57 push edi
010D1002 |. 8B3D A0200D01 mov edi, dword ptr [<&MSVCR100.printf>]
010D1008 |. 68 F4200D01 push offset 010D20F4 ; /Format = "for ",LF,""
010D100D |. FFD7 call edi ; \MSVCR100.printf
010D100F |. 83C4 04 add esp, 4
010D1012 |. BE 01000000 mov esi, 1 ; int i = 1
010D1017 |> 56 /push esi ; /<%d>
010D1018 |. 68 FC200D01 |push offset 010D20FC ; |Format = "%d"
010D101D |. FFD7 |call edi ; \MSVCR100.printf, add esp,8
010D101F |. 46 |inc esi ; ++i
010D1020 |. 83C4 08 |add esp, 8
010D1023 |. 83FE 0A |cmp esi, 0A
010D1026 |.^ 7E EF \jle short 010D1017 ; if( i <=10) goto 010d1017
010D1028 |. 5F pop edi ; i > 10 跳转
010D1029 |. 33C0 xor eax, eax
010D102B |. 5E pop esi
010D102C \. C3 ret
(4)完全优化
001A1000 /$ 56 push esi
001A1001 |. 57 push edi
001A1002 |. 8B3D A0201A00 mov edi, dword ptr [<&MSVCR100.printf>]
001A1008 |. 68 F4201A00 push offset 001A20F4 ; /Format = "for ",LF,""
001A100D |. FFD7 call edi ; \MSVCR100.printf
001A100F |. 83C4 04 add esp, 4
001A1012 |. BE 01000000 mov esi, 1 ; int i = 1
001A1017 |> 56 /push esi ; /<%d>
001A1018 |. 68 FC201A00 |push offset 001A20FC ; |Format = "%d"
001A101D |. FFD7 |call edi ; \MSVCR100.printf, add esp,8
001A101F |. 46 |inc esi ; ++i
001A1020 |. 83C4 08 |add esp, 8
001A1023 |. 83FE 0A |cmp esi, 0A
001A1026 |.^ 7E EF \jle short 001A1017 ; if( i <=10) goto 010d1017
001A1028 |. 5F pop edi ; i > 10 跳转
001A1029 |. 33C0 xor eax, eax
001A102B |. 5E pop esi
001A102C \. C3 ret
4.自增++和自减--语句
(1)加1指令inc
inc 操作符
inc a 相当于 add a,1 //i++ ++i
优点 速度比add指令快,占用空间小
这条指令执行结果影响AF、OF、PF、SF、ZF标志位,但不影响CF进位标志位
(2)减1指令dec
dec 操作符
dec a 相当于sub a,1 //i-- --i
优点 速度比sub指令快,占用空间小
这条指令执行结果影响AF、OF、PF、SF、ZF标志位,但不影响CF进位标志位
(3)用汇编理解前++、前--、后++、后--区别
5.do-while和while 循环结构反汇编代码分析
(1)do-while循环
(2)while循环
(3)for while do-while的区别
十五、浮点指令
1.浮点数的存放方式
01311000 /$ 55 push ebp
01311001 |. 8BEC mov ebp, esp
01311003 |. 51 push ecx
01311004 |. 68 F4203101 push offset 013120F4 ; ASCII "fld",LF
01311009 |. FF15 A0203101 call dword ptr [<&MSVCR100.printf>]
0131100F |. 83C4 04 add esp, 4
01311012 |. D905 08213101 fld dword ptr [1312108] ; float 8.786000
01311018 |. D95D FC fstp dword ptr [local.1]
0131101B |. D945 FC fld dword ptr [local.1]
0131101E |. DC05 00213101 fadd qword ptr [1312100] ; float 1.000000000000000
01311024 |. D95D FC fstp dword ptr [local.1]
01311027 |. 33C0 xor eax, eax
01311029 |. 8BE5 mov esp, ebp
0131102B |. 5D pop ebp
0131102C \. C3 ret
2.st0至st7
80位的两用寄存器
MMX FPU
3.浮点指令
1).FLD类似于 PUSH指令
向st0中放入数据
2).FSTP类似于 POP指令
st0 中的数据取出
3).FADD类似于 ADD指令
格式
fadd memvar //st0 = st0 + memvar
3).FSUB类似于 SUB指令
格式
fsub memvar //st0 = st0 - memvar
5).FMUL 乘法指令
格式
fmul memvar //st0 = st0 * memvar;
6).FDIV 除法指令
格式
FDIV memvar //st0 = st0 / menvar
7)FILD 整数转浮点指令
整数放入st0寄存器
FILD memvar // st0 = (double)memvar
8)CVTTSD2SI 浮点转整数指令
cvttsd2si r32, st0/m32
运用截断处理将st0/m32 中的一个单精度浮点值转换成r32
中的一个有符号的双字整数
and esp, FFFFFFF8(优化对齐)
十六、位移指令
1.逻辑位移指令
(1)SHR 逻辑右移指令
右移一位相当于整除2,用0来补位
(2)SHL 逻辑左移指令
左移一位相当于乘2,用0来补位(有可能会溢出)
2.算术位移指令
(1)SAR 算术右移指令
SAR与SHR指令:
SAR 右移时保留操作数的符号,即用符号位来补足
SHR 右移时总是用0来补足
(2)SAL 算术左移指令
SAL与SHL 功能完全一样
(3)循环位移指令
ROL 循环左移
ROR 循环右移
十七、逻辑运算符
1.或运算
1)逻辑或(C语言中的||)
条件真和假:非零为真,零为假
假假为假
c = a || b
if( c )
{
}
截断原理
2)按位或(C语言中的|)
0x33 00110011
| 0x66 01100110
= 0x77 01110111
OR指令
2.与运算
1)逻辑与(C语言中的&&)
真真为真
c = a && b
if( c )
{
}
截断原理
2)按位与(C语言中&)
0x33 00110011
& 0x66 01100110
= 0x22 00100010
AND指令
3.非运算
1)逻辑取反(C语言中的 !)
假变真 真变假
SETE(SETZ) 取ZF标志位的值保存
SETNE(SETNZ) 将ZF标志位的值取反后保存
2).按位取反(C语言中的~)
~ 0x33 00110011
= 0xcc 11001100
NOT 指令
4.异或运算
1)按位异或(C语言中的^)
1^1 = 0; 0^0 = 0; 相同为0
0^1 = 1; 1^0 = 1; 不同为1
1101
^ 0110
= 1011
XOR 指令
xor eax,eax 将eax置0
不借助第三个变量,将两个数做交换
int a = 5, b = 7;
a = a + b;
b = a - b;
a = a - b;
a = a^b;
b = a^b;
a = a^b;
逻辑运算指令小结:
OR : 按位或运算,有1为1,全0为0。
如:101100
OR 110101
= 111101
AND : 按位与运算,有0为0,全1为1。
如:1011
AND 1101
= 1001
NOT : 取反运算,0变成1,1变成0
如: NOT 1011
= 0100
XOR : 异或运算,相同则为0,不相同为1
如: 1101
XOR 0110
= 1011
十八、字符操作相关指令
1.字符串的比较函数strcmp反汇编分析
VS设置 项目->属性->C/C++ ->优化->启动内部函数->"否"
2.REPNE和SCASB指令
1)SCASB指令
SCASB编译后: SCAS BTYP PTR [EDI]
相当于:
cmp byte prt[edi],al
对标志位的影响相当于sub指令,同时还会修改寄存器EDI的值:
如果标志位DF为0,则 inc EDI;
如果标志位DF为1,则 dec EDI;
2)REPNE指令
repnz scasb 编译后:REPNE SCAS BTYP PTR ES:[EID]
当ECX!=0并且ZF=0时,重复执行后边的指令(SCAS BTYP PTR ES:[EDI]),
每执行一次ECX的值减1
REPNE 和REPNZ 是同一条指令的不同助记符
3)SCASB、SCASW、SCASD指令
SCASB SCAS BTYP PTR [EDI] char s1[0] byte 1
SCASW SCAS WORD PTR [EDI] short s1[0] word 2
SCASD SCAS DWORD PTR [EDI] int s1[0] dword 4
REPNE SCAS BTYP PTR [EDI] 当ECX!=0并且ZF=0、DF=0时,重复执行后面的指令
每次执行一次EDI的值加1,ECX的值减1
REPNE SCAS WORD PTR [EDI] 当ECX!=0并且ZF=0、DF=0时,重复执行后面的指令
每次执行一次EDI的值加2,ECX的值减1
REPNE SCAS DWORD PTR [EDI] 当ECX!=0并且ZF=0、DF=0时,重复执行后面的指令
每次执行一次EDI的值加4,ECX的值减1
(调试时,按F7才能单步执行)
4)实例运用
1.计算字符串长度
2.定位特定字符串位置(索引)
3.在内存中定位一串特征码
小结:
REPNZ/REPNE与SCASB指令结合使用,表示当串未结束(ECX!=0),且当
对应串元素不相同(ZF=0)时,继续重复执行串比较指令
3.REPE/REPZ和CMPSB、CMPSW、CMPSD指令
1)CMPS
cmps byte ptr [edi],byte ptr [esi]
cmps word ptr [edi],byte ptr [esi]
cmps dword ptr [edi],byte ptr [esi]
对标志位的影响相当于sub指令,同时还会修改寄存器EDI和ESI的值:
如果标志DF为0,则edi、esi按相对于大小(byte word dword)递增
如果标志DF为1,则edi、esi按相对于大小(byte word dword)递减
2)REPE/REPZ
repe/repz cmpsb 当ecx!=0并且ZF=1时,重复执行后面的指令
每执行一次ecx的值减1
3)实例运用
比较串是否相等
4.汇编编写字符串比较函数
1)asm_strcmp函数
__declspec(naked) 告诉编译器用纯汇编方式编译函数,不自动添加
寄存器保护和堆栈平衡代码
寄存器入栈保护
维持堆栈平衡
asm_strcmpA/asm_strcmpW
2)STD/CLD指令(DF方向标志位相关)
STD DF = 1
CLD DF = 0
十九、串存储和串的加载指令
1.串存储指令STOSB、STOSW、STOSD
stosb stos byte ptr [edi]
stosw stos word ptr [edi]
stosd stos dword ptr [edi]
相当于:
mov byte ptr [edi],al
mov word ptr [edi],ax
mov dword ptr [edi],eax
rep stosb rep stos byte ptr [edi]
用al的值 填充byte ptr [edi],每次ecx值减1,edi的值增加1
rep stosw rep stos word ptr [edi]
用ax的值 填充word ptr [edi],每次ecx值减1,edi的值增加2
rep stosd rep stos dword ptr [edi]
用eax的值 填充dword ptr [edi],每次ecx值减1,edi的值增加4
定位main函数位置的步骤:
第一步:打开程序,程序启动后停在这里,直接jmp跳转
013012E2 /$ E8 82040000 call 01301769
013012E7 \.^ E9 B3FDFFFF jmp 0130109F
第二步:jmp跳转跟随之后,找到call dword ptr [<&MSVCR100.exit>]退出的代码的位置
013011AA |. FF35 1C303001 push dword ptr [130301C]
013011B0 |. FF35 20303001 push dword ptr [1303020]
013011B6 |. FF35 18303001 push dword ptr [1303018]
013011BC |. E8 3FFEFFFF call 01301000
013011C1 |. 83C4 0C add esp, 0C
013011C4 |. A3 30303001 mov dword ptr [1303030], eax
013011C9 |. 391D 24303001 cmp dword ptr [1303024], ebx
013011CF |. 75 37 jne short 01301208
013011D1 |. 50 push eax
013011D2 |. FF15 84203001 call dword ptr [<&MSVCR100.exit>]
第三步:call dword ptr [<&MSVCR100.exit>]的前一个call就是main函数
013011AA |. FF35 1C303001 push dword ptr [130301C]
013011B0 |. FF35 20303001 push dword ptr [1303020]
013011B6 |. FF35 18303001 push dword ptr [1303018]
013011BC |. E8 3FFEFFFF call 01301000
013011C1 |. 83C4 0C add esp, 0C
2.串载入指令LODSB、LODSW、LODSD
lodsb lods byte ptr [esi]
lodsw lods word ptr [esi]
lodsd lods dword ptr [esi]
相当于:
mov al, byte ptr [esi]
mov ax, word ptr [esi]
mov eax, dword ptr [esi]
rep lodsb rep lods byte ptr [esi]
用byte ptr [esi]的值,填充al,每次ecx值减1,esi的值增加1
rep lodsw rep lods word ptr [esi]
用word ptr [esi]的值,填充ax,每次ecx值减1,esi的值增加2
rep lodsd rep lods dword ptr [esi]
用dword ptr [esi]的值,填充eax,每次ecx值减1,esi的值增加4
二十、循环控制指令
格式: LOOP 标号
loop start/end
功能:
(1)ECX = ECX - 1
(2)ECX != 0,则转移至标号处循环执行
(3)直至ECX = 0,继续执行后面的指令
本指令是用ECX寄存器作为计数器,来控制程序的循环
二十一、条件置位指令
1. (== 比较时)
SETZ(SETE) 取ZF标志位的值保存
2. (!= 比较时)
SETNZ(SETNE) 将ZF标志位值取反后保存
3.SETG ( > 比较时)
setg al
当 ZF == 0 && SF == 0 && OF == 1时 al = 1
4.SETL( < 比较时)
setl al
当SF==1 || OF == 1时 al = 1
5.SETGE(>=比较时)
SETGE 操作数
操作数可以是一个字节的存储单元,可以是一个字节宽度的寄存器
作用: >=时,设定操作数值1,否则为0,一般与cmp指令组合使用
标志位:JGE 对标志的需求 SF=OF时,操作数的值将为1
6.SETGE(<=比较时)
SETLE 操作数
操作数可以是一个字节的存储单元,可以是一个字节宽度的寄存器
作用: <=时,设定操作数值1,否则为0,一般与cmp指令组合使用
标志位:JLE 对标志的需求 ZF=1 || SF != OF 时,操作数的值将为1