0%

汇编期末复习

汇编期末复习的一些碎碎念

概念

算数逻辑移位

  • 逻辑移位:不考虑符号位,空位补零
  • 算术移位:有符号的
    • 正数与逻辑移位相同
    • 负数补码:高位补1低位补0,符号位要跟着一起移动

32位浮点数编码

32=1符号位+8指数+23有效数字

  • 符号位:0正1负
  • 指数:阶码(2的幂次数),是移码,$M=2^{n-1}-1=127$
  • 有效数字:小数点后面的,小数点前是1

注意进制转换

操作数

  1. 双操作数——(目的 源)
    MOV ADD LEA
  2. 单操作数——可能是目的/源/目的+源
    INC PUSH CALL
  3. 无操作数
    NOP CLC HLT

寄存器

  • eax:累加器,加法乘法指令的缺省寄存器
    • 32位寄存器
    • ax是低16位
    • al是低8位,ah是高8位
  • ebx:基地址寄存器,在内存寻址时存放基地址
  • ebp:基址指针,栈底
  • esp:栈顶指针,栈顶是低地址,压入数据越多,esp越小
  • eip:指示下一条运行指令的地址
  • ecx:计数器

指令

数值

  • sub eax, 1==dec eax:减1,与cmp eax, 1以及add eax, 0xFFFFFFFF不同是因为标志位
  • cmp eax, ebx:通过减法运算来影响标志位
  • test eax, ebx:通过与运算来影响标志位,
    • 通常用来测试寄存器是否为空
  • test和and的关系类似cmp和sub
  • sal|sar算术移位,shl|shr逻辑移位
  • add|sub eax, ebx结果保存在eax,即计算eax=eax+ebx

跳转

  • jmp:无条件跳转
  • je:jump when equal,ZF=1时(零标志位)
  • jge:jump when greater or equal
  • jne:jump when not equal
  • jnz:jump when not zero
  • call 函数地址 : 将函数地址的下一条地址压入栈,将函数内操作的第一个地址放入EIP,汇编语言CALL和RET指令:调用一个过程 (biancheng.net)
  • ret把之前call放进堆栈中的地址弹回EIP

传输

  • lea op1, op2:将op2的有效地址传输到op1(寄存器)
  • mov op1, op2只允许一个为寄存器

堆栈

  • push eax:将eax压入栈,esp-=4

others

  • loop op==dec ecx+jnz op
    • 先ecx–
    • 再判断ecx是否为0,不为0则跳转

寻址

  • 寄存器寻址
    寄存器在CPU内部,不需要执行系统总线周期,快
  • 立即数寻址
    立即数-操作数在指令代码中,只能是源操作数
  • 存储器寻址
    CPU需要访问内存,此时的指令中要给出操作数的内存地址
    1. 直接寻址
      使用位移量EA,变量名称实质上是符号位移量
      [偏移的字节][变量名]
    2. 寄存器间接寻址
      EA直接由地址指针寄存器:SI, DI, BX, BP中获得
      [寄存器]
    3. 基址寻址&变址寻址
      偏移量=地址指针寄存器(4个中的1个)中的内容+指令中的位移量
      基址-BX/BP, 变址-SI/DI
    4. 基址变址寻址
      偏移量=基址指针寄存器+变址寄存器+指令中的位移量

函数调用

  • cdecl:C的默认,所有参数从右到左依次入栈,手动清栈。不会要求调用者传递多少参数,可用于传递不定参数
  • stdcall:C++ 的标准调用方式:所有参数从右到左依次入栈,自动清栈
  • fastcall:使用寄存器传递函数参数
  • 函数的返回值一般在寄存器eax
  • 函数传参顺序:从右到左

大端小端

大端更自然

1字=16比特

碎碎念

32位类型:(unsigned)int, float

16位:short

push 对esp,ebp,4字节=32位

push ecxadd esp, 0xFFFFFFFC对esp的作用相同

汇编指令对操作数的要求(寄存器、立即数、地址)

  • mov 只允许一个为存储器寻址
    • [eax]是寄存器间接寻址,属于存储器寻址,表示将eax中的内容作为地址,去相应地址中找数据
    • [1000H]是直接寻址,表示去1000H这个位置找数据
  • add和sub
    • 源操作数(2nd)可以为通用寄存器、内存单元、立即数
    • 目的操作数(1st)可以为通用寄存器、内存单元
  • lea 作用是把源操作数的地址放进目标操作数中,源操作数必须是内存操作数,目标操作数只能是16位通用寄存器,因为有效地址是16位

函数开辟栈帧的指令是push ebp、mov ebp,esp;

关闭:mov esp,ebp、pop ebp

2push+1call,esp减4减4减4

x-FFFFFFFF==x+1

例题分析

题:C语言条件跳转中a<b对应的汇编的汇编代码是(A)

  • A. mov eax, [a]; cmp eax, [b]; jge XXX;
  • B. mov eax, [a]; cmp eax, [b]; jl XXX;
  • C. mov eax, [a]; cmp eax, [b]; jle XXX;
  • D. mov eax, [a]; cmp eax, [b]; jg XXX;

解:jge是当大于等于时跳转。C语言中if(a<b)换句话说就是a>=b时才跳转。

题:F是函数

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
F:
push ebp;
mov ebp, esp;
sub esp, 4;
mov eax, [ebp + 8];
cmp eax, 1;
jg ELSE;
mov eax, 1;
jmp END;
ELSE:
sub eax, 1;
push eax;
call F;
add esp, 4;
mov [esp], eax;
mov eax, [ebp + 8];
sub eax, 2;
push eax;
call F;
add esp, 4;
add eax, [esp];
END:
mov esp, ebp;
pop ebp;
ret;

解:

  • 函数的调用方式是_cdecl

    • 观察ret
      • ret 8结束时自动清理堆栈,是stdcall或fastcall
      • ret没有修改堆栈,需函数结束后手动清理
  • 函数F有1个参数

    • call之前push的次数就是参数的个数
  • 还原成C代码

    1
    2
    3
    4
    5
    int F(int arg0){
    if(arg0<=1)
    return 1;
    return F(arg0-1)+F(arg0-2);
    }