汇编-一个函数调用的例子

汇编-寄存器及主要指令

寄存器

可以分为四类:

  • 数据寄存器

    • EAX(Accumulator)

      • 可用于乘除,输入输出等操作,他们的使用频率很高。EAX还通常用于存储函数的返回值。
    • EBX(Base Register)

      • 作为存储器指针来使用,用来访问存储器。
    • ECX (Count Register)

      • 在循环和字符串操作时,用来控制循环次数;在移多位时,要用CL来指明移位的位数。
    • EDX (Data Register)

      • 在进行乘除运算时,作为默认操作数参与运算,也可用于存放I/O的端口地址。
  • 地址寄存器:

    • 变址(ESI,EDI)
      • 分别作为“原地址指针”和“目的地址指针”
    • 指针(ESP,EBP)
      • 栈帧顶,栈帧底
  • 段寄存器:ES CS SS DS FS GS

    • 内存单元的物理地址,由段寄存器的值和一个偏移量组合,组成一个大的内存地址。
    • CS:代码段
    • DS:数据段
    • ES:附加段
    • SS:堆栈段
    • FS:附加段
    • GS 附加段
    • 融合变址寄存器,在很多字符串操作指令中,DS:ESI指向源串,ES:EDI指向目标串。
  • 指令寄存器 EIP(下一步执行的代码); 标志寄存器 EFlags

指令

  • 数据传送指令:
    • MOV 目的操作数,源操作数
    • XCHG 寄存器A ,寄存器B 交换
    • PUSH 寄存器,POP 寄存器 把寄存器的操作数压入堆栈或从堆栈取出到寄存器
    • PUSHF,POPF (标志寄存器出入栈)
    • PUSHA,POPA 这两个指令的作用是把通用寄存器压栈出栈。寄存器的入栈顺序依次是:EAX,ECX,EDX,EBX,ESP(初始值),EBP,ESI,EDI.出栈相反。
    • LEA,LDS,LES 取地址到寄存器
  • 位运算指令:
    • ADN,OR,XOR,NOT,TEST
    • SHR,SHL,SAR,,SAL 算数移动和逻辑移动
    • ROR,ROL,RCR,RCL 循环位移
  • 算数运算指令:
    • ADD ADC 加法
    • SUB SBB 减
    • INC EDC 自增 自减
    • NEG 自反
    • MUL IMUL 乘
    • DIV IDIV 除
  • 流程控制指令
    • CMP 比较op1与op2的值
    • JMP 跳转指定地址
    • LOOP 循环指令
    • CALL RET 子程序点用,返回
    • INT IRET中断调用及返回
    • REP REPE REPNE 重复前缀指令
  • 条件转移命令
    • JXX:当特定条件成立则跳往指定地址
      • Z为0
      • G大于
      • L小于
      • E等于
      • N相反
  • 字符串操作指令集
    • MOVSB MOVSW MOVSD字符串传送指令(B字节,W字,D双字)
    • CMPSB CMPSW CMPSD 字符串比较指令
    • SCASB,SCASW字符串搜索指令
    • LODSB,LODSW,STOSB,STOSW字符串载入或驻存指令

一个程序调用的例子

C语言程序

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
int add(int x,int y)
{
int z=0;
z=x+y;
return z;
}
void main()
{
int n=0;
n=add(1,3);
printf("%d\n",n);
}

汇编

一个例子:

  • main
1
2
3
4
5
6
7
8
9
10
11
12
void main()
***********
int n=0;
0041140E mov dword ptr[n],0
n=add(1,3);
00411415 push 3 //
00411417 push 1 // 参数入栈后ESP抬高(值变小,往低地址拓展)
00411419 call add(411096h) //EIP入栈,ESP抬高,跳转到函数入口地址
0041141E add esp,8 //add完之后恢复栈帧
00411421 mov dword ptr[n],eax //函数返回的结果存储在eax中,此时把结果赋值给n
printf("%d\n,n");
}
  • add(int x,int y)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int add(int x,int y)
{
********栈空间分配******
004113A0 push ebp //将主函数栈底EBP入栈,ESP抬高(将原来的栈底入栈,准备指向新的栈底)
004113A1 mov ebp,esp //将ebp和esp都指向栈顶,目前栈里是空的,esp=ebp
004113A3 sub esp,0CCH //0CCH由编译器确定,esp向上抬高CCH,栈成型
********初始化*********
004113A9 push ebx //用于保存现场, ebx作为内存偏移指针使用,esp抬高
004113AA push esi //用于保存现场, esi是源地址寄存器,esp抬高
004113AB push edi //用于保存现场, edi是目的指针寄存器,esp抬高
004113AC lea edi,[ebp-0CCH] //将当前栈顶地址装入EDI
004113B2 mov ecx,33h //设置计数器数值
004113B7 mov eax,0CCCCCCCCh
004113BC rep stos dword ptr es:[edi] //循环,将栈区的数据都初始化为CCH,每次将edi+1
********执行函数体******
int z=0
004113BE mov dword ptr[z],0 //将z初始化为0
004113C5 mov eax,dowrd ptr[x] //将x赋值给eax
004113C8 add eax,dword ptr[y] //将寄存器eax的值加y
004113CB mov dword ptr[z],eax //将eax的值赋值给z
004113CE mov eax,dword ptr[z] //将z的值放到eax
********恢复到主函数*******
004113D1 pop edi; //恢复寄存器值
004113D2 pop esi; //恢复寄存器值
004113D3 pop ebx; //恢复寄存器值
004113D4 mov esp,ebp; //栈顶指向之前的栈底,上面的栈帧不要了
004113D6 pop ebp; //恢复寄存器值
004113D7 ret ; //根据返回地址,恢复EIP值,相当于popEIP
}