在上一篇博客 程序编码以及数据格局 中咱们给出了一个简单的C程序,然后编译成了汇编代码。咱们看不懂没关系,后边的博客咱们将逐步揭开一些汇编指令的奥秘面纱。本篇博客咱们将对操作数指示符和数据传送指令进行详细的介绍。
1、整数寄存器
上一篇博客咱们讲了在汇编语言中,如下的几个处理器状况是可见的:
一、程序计数器(在 IA32 中一般称为 PC,用 %eip 表明):指示即将履行的下一条指令在存储器中的地址。
二、整数寄存器文件:包含8个命名的方位,能够存储一些地址或许整数的数据。有的用来记录某些重要的程序状况,有的则用来保存暂时数据。
三、条件码寄存器:保存最近履行的管用或逻辑指令的状况信息,它们用来完成操控或数据流中的条件改变,比方用来完成 if 和 while 语句。
四、浮点寄存器:存储浮点数。
这儿咱们要讲的便是第三个整数寄存器,在 32 位 CPU 中包含一组 8 个存储 32 位值的寄存器。这些寄存器用来存储整数数据或指针。下图是 IA32 的整数寄存器:
上述八个寄存器首要功能如下:
%eax,可寄存一般数据,而且可作为累加器运用;
%ebx,可寄存一般数据,而且可用来寄存数据的指针(偏移地址);
%ecx,可寄存一般数据,而且可用来做计数器,常常将循环次数用它来寄存;
%edx,可寄存一般数据,而且可用来寄存乘法运算产生的部分积,或用来寄存输入输出的端口地址(指针);
%esi,可寄存一般数据,还可用于串操作中,寄存源地址,对一串数据拜访;
%edi,可寄存一般数据,还可用于串操作中,寄存意图地址,对一串数据拜访;
%esp,用于寻址一个称为仓库的存储区,经过它来拜访仓库数据;
%ebp,可寄存一般数据,用来寄存拜访仓库段的一个数据区,作为基地址;
在大多数情况下,%eax、%ecx、%edx、%ebx、%esi、%edi等6个寄存器能够看做通用寄存器,对它们的运用没有限制;%esp、%ebp两个寄存器保存着指向程序栈中重要方位的指针,只有依据栈管理的规范常规才干修改这两个寄存器中的值。
这8个寄存器都能够作为16位(字)或32位(双字)来拜访。字节操作指令能够独立的读或许写%eax、%ecx、%edx、%ebx等4个寄存器的2个低位字节,因为%ax、%cx、%dx、%bx这4个16位寄存器又可别离分红ah,al ;bh,bl;ch,cl;dh,dl的8位寄存器。
这儿咱们也只需要有个眼熟就好了,后边咱们将对这个8个寄存器进行详细解说。
2、操作数指示符
咱们知道大多数指令都有一个或多个操作数(operand),指示出履行一个操作中要引证的源数据值,以及放置成果的方针方位。下图是 IA32 支撑的多种操作数格局: 上图咱们能够看出源数据值能够是常数形式给出,或许是从寄存器或存储器中读出。而成果能够寄存在寄存器或存储器中。咱们将不同的操作数分为如下三种类型:
①、当即数(immediate):书写方法是符号后跟一个规范表明的整数,比方52,$0x1F等等。任何能放进一个32位的字里面的数值都能够做当即数。
②、寄存器(register):它表明某个寄存器的内容,能够是8个32位寄存器中的一个(比方%eax),也能够是8个16位寄存器中的一个(比方%ax),还能够是8个单字节寄存器寄存器(比方%al)。上图是用Ea来表明任意寄存器a,用引证 R[Ea]来表明它的值。
③、存储器(memory):它会依据计算出来的地址(一般称为有用地址)来拜访某个存储器方位。咱们将存储器看成一个很大的字节数组,用符号Mb[Addr] 表明对存储在存储器中从地址 Addr 开端的 b 个字节值的引证。上图省掉了下方的 b.
从上图咱们知道,榜首行是当即数,第二行则是寄存器,剩余的全部是存储器。其间最后一行存储器语法 Imm(Eb,Ei,s),表明的是最常用的形式,分为四个部分,
一、Imm 是当即偏移数
二、Eb 是基址寄存器
三、Ei 是变址寄存器
四、s 是比例因子,必须是 1、2、4或8
然后有用地址计算公式为: Imm + R[Eb]+R[Ei]s。比方关于2(%esp,%eax,4)这个操作数来讲,它代表的是内存地址为2+%esp+4%eax的存储器区域的值。
3、数据传送指令
数据传送指令:将数据从一个方位仿制到另一个方位的指令。简单来说便是仿制指令。
将源操作数的值仿制到意图操作数中并掩盖。源操作数指定的值是一个当即数,存储在寄存器或存储器中。意图操作数指定一个方位,要么是一个寄存器,要么是一个存储器地址。在 IA32 中还有一条限制,传送指令的两个操作数不能都履行存储器方位。
将一个值从一个存储器方位仿制到另一个存储器方位需要两条指令:(就和宋丹丹把大象送进冰箱的过程相同)
①、榜首条指令将源值加载到寄存器中
②、第二条指令将该寄存器值写入到意图方位。
下图是许多不同的指令类:
4、MOV 指令
MOV 类由三条指令组成:movb,movw和 movl。指令格局为 [movx S D],表明将源操作数S中的数据仿制到意图操作数D中。三种指令的区别是它们别离是在大小为 1,2和4个字节的数据上进行操作。
这儿举一个简单的比方,比方咱们有一条指令为movl %edx %eax。那么它的履行过程就如下图所示。
上图引证至:www.cnblogs.com/zuoxiaolong…
在指令履行之后,%edx寄存器当中的内容会被仿制到%eax寄存器。数据格局则为四个字节,也便是双字。咱们还能够运用movb和movw去仿制一个字节或许两个字节。
5、MOVS指令
MOVS指令格局为 [movsxy S D],其间x、y为数据格局,S为源操作数,D为意图操作数。x、y的组合有三种,别离是bw,bl,wl,别离表明字节(8位)传送到字(16位),字节(16位)传送到双字(32位),字(16位)传送到双字(32位)。
将较小的源数据仿制到一个较大的数据方位。高位用符号位扩展,即意图方位的一切高位用源值的最高位数值进行填充。
比方关于指令movswl %dx %eax来讲,它的效果如下图所示。
这儿运用了十六进制的整数表明方法。能够看到,movs指令将0x8FFF扩展以后存入%eax寄存器,其间%dx为寄存器%edx的后16位表明。
6、MOVZ 指令
MOVZ 指令和上面的MOVS 指令十分相似。指令格局为 [movzxy S D],其间x、y为数据格局,S为源操作数,D为意图操作数。x、y的组合有三种,别离是bw,bl,wl,别离表明字节(8位)传送到字(16位),字节(16位)传送到双字(32位),字(16位)传送到双字(32位)。
将较小的源数据仿制到一个较大的数据方位。高位用0扩展,即意图方位的一切高位用0进行填充。
比方关于指令movzwl %dx %eax来讲,它的效果如下图所示。
扩展后,方针寄存器%eax的前16位为0而不再是1。
7、push 和 pop 指令
咱们知道 栈 是一个数据结构,能够添加或删去值,遵从“后进先出”的准则。
push:把数据压入栈中,添加数据。
pop:把数据移出栈,删去数据。留意移出的值总是最近被压入而仍然在栈中的值。
栈能够完成为一个数组,总是从数组的一端插入或删去元素。而这一端称为栈顶,在 IA32 中,程序栈寄存在存储器某个区域,如下图所示: 留意因为操作数字节的不同,pushl 是将双字(32位)压入栈中;popl 是移出双字。
将一个双字值压入栈中,首要要将栈指针减4,然后将值写到新的栈顶地址。因而指令 pushl %ebp 等价于下面两条指令:
subl $4,%esp
movl %ebp,(%esp)
上图所示,当 %esp 为0x108,%eax为0x123时,履行指令 pushl %ebp 的效果。首要 %esp 会减4,得到0x104,然后会将 0x123 寄存到存储器地址 0x104处。
将一个双字值从栈顶移出,首要要从栈顶方位读出数据,然后将栈指针加4。因而指令 popl %eax 等价于下面两条指令:
movl (%esp),%eax
addl $4,%esp
上图所示,先从存储器中读取值 0x123,再写到寄存器 %edx中,然后寄存器%esp的值将添加回到0x108。
留意值0x123仍然会保存在存储器0x104中,直到被掩盖(比方被另一条入栈操作掩盖)。无论如何,%esp 指向的地址总是栈顶,任何存储在栈顶之外的数据都认为是无效的。
8、总结
本章首要介绍了操作数指示符,需要咱们了解几种表达式的计算方法。接着介绍了几种数据传送指令,包含MOV,MOVS,MOVZ,PUSH和POP等,总体上来看不难了解,咱们在了解这些指令后,再回头看那些汇编代码,应该会了解很多了。下一篇博客咱们将进一步介绍汇编指令——算术和逻辑操作。