汇编基础

汇编基础

十月 25, 2019

什么是汇编

汇编是一种低级语言,直接描述/控制CPU的运行,反映底层原理。CPU只能理解二进制机器码,而人需要用高级语言来帮助开发,高级语言写好后都会经过”编译”过程翻译成机器码(01串)然后给CPU执行,而汇编就是机器码的指令一对一翻译过来,比机器码高级一点,既能反映底层原理,又比机器码易读的一种语言。

汇编分类

按汇编风格:

(1) Intel汇编,被Microsoft Windows/Visual C++采用。
(2) AT&T汇编,被GNU/Gas采用。(Gas也可使用Intel汇编风格)
两者只是符号系统有所不同,含义大同小异。

按CPU体系:

(1) IBM PC汇编(Intel汇编),IBM最早推出PC机,后来很多体系都与它兼容。
(2) ARM汇编。
两者互不兼容。

寄存器

CPU只能运算,无法储存数据,数据一般储存在内存中,CPU要从内存中读取数据再进行计算。但是因为CPU运算速度远快于从内存读取数据的速度,每次运算都去内存中寻址后读取数据再运行就会明显拖慢速度,为了避免速度被拖慢,CPU自带有一级缓存和二级缓存,但是CPU从缓存中读取数据的速度依然不够快,而且数据在缓存中储存位置也不固定,每次读取也需要寻址,还是会拖慢速度。所以CPU有了寄存器(Register),用来储存最常用的数据,而且每个寄存器一般有规定储存某一种常用数据,CPU就优先从寄存器读取数据,由寄存器和内存进行数据交换。CPU的位数其实就是指CPU中寄存器的位数,32位CPU中寄存器就是32位(4字节)。
x86常用寄存器(都为32位):
EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP,EIP。
其中前6个都是通用寄存器,不指定用途,但在以前这些寄存器有被指定用途,现在在使用习惯上这些用途也被保留了下来,但不强行要求。ESP,EBP和EIP有专门用途,ESP用来储存栈指针(指示栈顶位置),EBP用来储存基址指针(指示子程序或函数调用的基址),通常用[EBP+立即数]来获取上层函数传入的参数,用[EBP-立即数]来访问当前函数的局部变量,EIP用来指向程序下一条要执行的命令的地址。EAX, EBX, ECX, EDX的两位低字节可独立使用,两位低字节中的两个字节也可以独立使用,例如如四字节EAX的后两位低字节是EX,两字节的EX中前一字节为AH,后一字节为AL。且寄存器大小写不敏感。

常用标志位(标志寄存器)

CF 进位标志,加法进位或减法借位时置1,否则置0;
PF 奇偶标志,反映操作结果中”1”的数量,若有偶数个”1”则置1,奇数个则置0;
AF 辅助进位标志,当第3位(半字节)出现进位或借位时AF=1,否则AF=0;
ZF 零标志,运算结果为0则置1,否则置0;
SF 符号标志,当运算结果为负数,即最高位为1时置1,否则置0;
OF 溢出标志,进行算数运算的结果值超出了8位或者16位的表示范围则置1,否则置0(正数相加得到负数,或者负数相加得到正数;符号位进位^数据最高位进位);
TF 陷阱标志,为调试程序设的,设置TF=1时CPU处于单步执行指令的模式,设置TF=0时正常执行程序;
DF 方向标志,用来控制数据串操作指令的步进方向,当设置DF=1时,将以递减顺序对数据串中的数据进行处理。当设置DF=0时,递增。

内存

程序运行时操作系统会为其分配一段内存供其使用。

Heap(堆)

堆是用户主动从内存中申请的空间,从低地址往高地址增长,堆的空间必须手动释放或者由垃圾回收机制来释放,不会随着程序运行自行释放,即使程序已经不会再用到这段空间。

Stack(栈)

栈是函数运行产生的临时分配内存区域,从高地址向低地址增长,每调用一个函数都会为其分一段内存称为一个帧,函数结束之后自动释放。

常用汇编指令

汇编指令一般的结构是 操作码 目的操作数, 源操作数,比如mov eax,0x1,也有只有一个操作数或是没有操作数的指令(一般是有默认的隐含操作数),比如inc eax,让eax的值+1,相当于add eax, 0x1,0x1相当于源操作数默认没有写出来。

目的操作数可以被读取或者写入,源操作数只能被读取,也就是说指令不会改变源操作数的值。

push

将数据压入栈中,然后栈顶下移。这条指令会先按照将要要压入栈中的数据类型所占的内存大小将ESP的值减小,然后将值写入ESP指向的地址。

call

用于调用函数,在栈中新建一个帧,将call指令后面一条指令的地址压入栈中,然后将EIP指向call的地址,程序就掉头去执行call的地址位置的指令,从而实现函数调用。

ret(retn)

结束当前函数,回收当前函数的帧,程序回到上层函数运行。从栈中将call指令下一条指令的地址取出给EIP,调用的函数结束程序回到上层函数。

mov

mov EAX,n 表示将n写入EAX寄存器中。
mov EAX,[ESP+4] 表示将ESP的值加上4,然后把这个值当作地址,取该地址的值写入EAX,中括号即表示取值。

pop

取出最近一个压入栈中的值写入指定位置。
pop EAX 表示将栈中最近一个压入的值取出写道EAX寄存器中,而且还会回收栈中该数据的空间回收,即让ESP增大。

add(加),sub(减),xor(异或),inc(自增),dec(自减)

add a,b 表示将a和b相加并将结果写入a中,a可以是寄存器或内存单元,b可以是寄存器,内存单元也可以是数据。
sub,xor指令同理。
inc a 表示将a的值+1,dec同理。

shl(左移)和shr(右移)

cmp

cmp a,b
两值比较。(将两个值相减,仅改变标志位,不返回结果)

test

test a,b
测试(两值作与运算,仅改变标志位,不返回结果),常用test a,a指令来测试a是否为0。

跳转指令

指令 条件 相反指令
JMP 直接跳转
JC CF==1 JNC
JZ(JE) ZF==1 JNZ(JNE)
JS SF==1 JNS
JO OF==1 JNO
JNP(JPO) PF==0 JP
JA(JNBE) 无符号大于 JNA(JBE)
JNAE(JB) 无符号小于 JAE(JNB)
JG(JNLE) 有符号大于 JNG(JLE)
JNGE(JL) 有符号小于 JGE(JNL)
JP 奇偶位置位 JNP
JPE 奇偶位相等 JPO