Mengzelev's Blog

汇编语言复习笔记(二)

Word count: 1,257 / Reading time: 5 min
2018/08/30 Share

数据传送

数据传送指令

格式: mov S(源操作数), D(目标操作数)

mov    一般传送指令

movs    符号扩展传送

movz    零扩展传送

push    压栈,等价于sub+mov

pop    退栈,等价于mov+add

按源操作数的长度加上b,w,l后缀,分别表示1、2、4字节。(movz,movs需要双后缀)



leal与movl的区别

指令后缀、操作数长度、目标寄存器宽度必须要一致!!

操作数类型

  • 立即数 Imm    整型常量,加$前缀,e.g.$233, $0x66FFCC
  • 寄存器 Reg    加%前缀,e.g.%eax,%ebx,%esp
  • 存储器 Mem    寻址操作


不能在一条指令里实现存储器到存储器的传送!!要实现存储器间的传送必须经过寄存器。

寄存器



所有寄存器都可以单独读取低16位

只有%eax,%ecx,%edx,%ebx可以读取低8位(x字辈)

地址运算指令

格式: leal S,D

S是复杂寻址地址形式的表达式,将表达式表示的值写入D,其中D一定是寄存器

用途:

  • 直接计算地址的值 e.g.p=&x
  • 执行简单的算数运算

leal与mov操作的区别:
leal不会对寻址表达式解引用

e.g.

//R[%edx]=x
movl 7(%edx,%edx,4),%eax    //R[%eax]=M[5x+7]
leal 7(%edx,%edx,4),%eax    //R[%eax]=5x+7

算术和逻辑操作

看表



※使用时也需要根据操作数长度添加后缀

特殊操作

imull    带符号乘法指令,只有一个操作数时,另一个乘数隐含在%eax中,乘积的高32位放入%edx,低32位存入%eax

idivl    带符号除法指令,只有一个操作数时,%edx-%eax为被除数,操作数为除数,商存入%eax,余数存入%edx

还有无符号版本mull和divl

cltd 符号扩展指令,将%eax中的数符号扩展至%edx成为64位,经常用于idivl的准备工作



关于imul

操作数个数 格式 操作 结果存放
1 imul src src*R[%eax],完全乘法(自己取的名字) %edx-%eax
2 imul src dst src*dst,高位截断,只保留低位 dst
3 imul reg src imm R[reg]=src*imm,只保留低位 reg

具体还是看老师ppt截图吧(侵权删)



条件控制指令

比较与测试



cmp和test指令实际上是用减法和按位与操作实现的。

注意两个操作数的先后顺序与实际是相反

条件置位指令setX

setX指令根据相应的条件标志位将某一位置0或置1。

有符号数的大小关系用greater/less表示,无符号数的用above/below表示。



条件跳转指令jmpX

基本同setX



间接跳转:跳转的目标是从寄存器或存储器中读取的,e.g.jmp *%eax表示跳转至R[%eax]存储的地址位置

跳转地址分为绝对地址相对地址(PC-relative addressing)

绝对地址即4个字节直接指定的目标地址。

PC-relative addressing

程序计数器的值是跳转指令后的那条指令的地址,而非跳转指令本身的地址

实际跳转到的地址=下一条指令的地址+右边的操作数(小端补码表示)

e.g.

804828f:    74 05                je         XXXXXXX
8048291:    e8 1e 00 00 00         call    80482b4
XXXXXXX=0x8048291+0x05=0x8048296

条件传送指令cmovX

满足某个条件时执行mov操作

※必须与cmp操作连用,比较的不是cmov指令的两个操作数而是cmp的两个操作数



条件分支语句的编译

if-else语句通常按goto方式执行

一般翻译思路为:

if (test-expr) 
    then-statement
else
    else-statement

会被翻译为

if(!test-expr)
    goto false
then-statement
goto done
false:else-statement
done:

可以参考下图中示例:



循环控制语句

do-while循环

一般循环语句都最终翻译成do-while的形式

do
    body-statement
while(test-expr)

会被翻译为

loop:
    body-statement
    if(test-expr) goto loop;


while循环

while(test-expr)
    body-statement

会被翻译为

if(!test-expr) goto done;
loop:
    body-statement
    if(test-expr) goto loop;
done:

for循环

for(init-expr; test-expr; update-expr)
    body-statement

会被翻译为

init-expr;
if(!test-expr) goto done;
loop:
    body-statement
    update-expr
    if(test-expr) goto loop;
done:

switch语句

跳跃表

跳跃表是一个数组,其中每个下标i对应一个代码段的地址

好处:执行一个switch语句的时间和case的数量无关
跳跃表一般被存放在内存的某个位置,可以调用gdb查看

一大波截图预警




作业二的教训


1.几个指令的名称对应功能要背熟

2.确定数据类型:确定长度+有无符号

3.别忘了指针也是一种数据类型

4.jmp指令的第二个操作数是小端补码表示

5.模拟汇编控制流就是要把代码拆分成简单语句(注意运算优先级)

6.分清andladdl

7.补充C代码的时候就不要再写8x这样意义不明的东西了,是8*x啊老兄

CATALOG
  1. 1. 数据传送
    1. 1.1. 数据传送指令
    2. 1.2. 操作数类型
    3. 1.3. 寄存器
    4. 1.4. 地址运算指令
  2. 2. 算术和逻辑操作
    1. 2.1. 看表
    2. 2.2. 特殊操作
    3. 2.3. 关于imul
  3. 3. 条件控制指令
    1. 3.1. 比较与测试
    2. 3.2. 条件置位指令setX
    3. 3.3. 条件跳转指令jmpX
    4. 3.4. PC-relative addressing
    5. 3.5. 条件传送指令cmovX
    6. 3.6. 条件分支语句的编译
  4. 4. 循环控制语句
    1. 4.1. do-while循环
    2. 4.2. while循环
    3. 4.3. for循环
  5. 5. switch语句
    1. 5.1. 跳跃表
  6. 6. 作业二的教训