本节主要内容:
1. 寄存器与内存的区别
2. 寄存器,内存
3. 内存修改
老唐语录:
快速算盘叫做寄存器。慢速的称为内存。其实他们的结构差不多,都是定宽的,最重要的一点,寄存器速度非常快,价格非常昂贵,所以在CPU内部。做的数量也很有限。常用的只做了8个:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI。内存速度慢,很便宜,所以数量做的非常庞大。寄存器做的数量非常少,就可以为每个寄存器取个名字。而内存数量太庞大了,没办法给每一个都取上名字,所以只能编号。最后重要的是内存中寄存器的编号是32位的。这也是我们现在的计算机叫32位计算机的主要原因。如果按寄存器的宽度是32位的话,是不对的,因为还有很多寄存器是大于32位的。我们通用的8个是32位的。而内存地址是固定的32位。以前的计算机之所以称为16位计算机,就是因为他的内存单元编号是16位的。
我们学过的指令MOV,能操作寄存器和内存。
所以说,汇编可以用一句话概括:汇编就是在寄存器和寄存器或寄存器和内存之间来回移动数据。就是指数据在内存和寄存器间来回流动,流动的多了,代表程序很复杂,比如office等一些大型软件。
mov eax,0x401000//给eax初始化
MOV也可以改成ADD(加),SUB(减),XOR(异或),OR(或),AND(与)。
后面的操作数为源操作数,前面的操作数为目标操作数,最开始是操作码。
其实ADD……这些也是移动指令:把源加上目标然后移动到目标操作数里面去。
前面表示操作方式,后面表示寄存器和寄存器或寄存器和内存,但是只能出现一个内存。比如:ds:[]里面写个数,表示内存单元。ptr指的是指针point。word是两个字节,还有byte是一个字节,dword是四个字节。
写法:byte/word/dword ptr ds:[32位的数]。
其实[]里面不但可以写具体的一个数,还可以写某一个寄存器的值。
方括号的通用格式:reg+reg*数+立即数,只要这个值算出来指向哪一个内存单元,就是那个内存单元(现在先记住,不要管为什么,后面会讲)。
第一个寄存器叫做BASE寄存器(8个寄存器都可以),第二个寄存器是INDEX也是8个寄存器之一,后面乘一个数scale(1,2,4或8,也就是2的0次方,2的1次方,2的2次方,2的3次方),后面再加一个数(DISP)。
BASE+INDEX*(1,2,4,8)+DISP
可以是有以下五种组合
BASE
INDEX*(1,2,4,8)
DISP
BASE+INDEX×(1,2,4,8)
BASE+INDEX×(1,2,4,8)+DISP
每一种组合都可以。
我们只有把最简单的东西用熟了,才能熟能生巧。
练习:
mov eax,ds:[0x401000+8*eax+eax];这个可以执行吗?
cpu实现了将地址赋给寄存器:LEA指令把方括号里面内存的编号给目标寄存器:load effective address。
当一个值不好确定宽度时,使用dword ptr 或者word ptr,byte ptr,源可以是内存或寄存器,也可以是立即数,但是目标不能是立即数。两方都可以是内存,但是内存只能在一个地方出现。两边的数据宽度要一样。所以指令是由操作码和操作数组成,操作码是表明我想干什么。复杂的指令也是由简单的指令组合而成。
课后理解:
内存同样由许多寄存器组成,但是此寄存器非彼寄存器,速度不及通用寄存器的几十分之一,宽度为8位。见图2-3:
图2-3:内存格式
如图2-3,为了区别内存和cpu内部的寄存器,我们将内存中的寄存器打上“[]”,专业术语称之为“地址”。图中的内存大小从0到0xFFFFffff,也就是说有0xFFFFffff个内存寄存器存在,内存地址从0-0xFFFFffff。
注:此处0xFFFFffff写法为何不写成oxFFFFFFFF?
十六进制不区分大小写,这样写是为了便于识别,我们可以很清楚的看出有8个F。
内存地址的用处是什么?
当用户运行程序时,cpu需要不停地去从存储区取代码和数据,这样非常耗时,于是cpu先将可能用到的代码和数据从存储区全部放入内存,再从内存中取数据和代码。看似多了一个过程,但是从内存中获取比存储区快得多,所以节省了很多时间。
我们如何使用内存地址呢?
我们通过实例来了解。
将32位数0x12345678存入内存中的0x12FFB8地址处:
说明:我们从图2-4可以看出:数值的高位存储在内存地址中的高位。
图2-4:内存存储方式
内存地址的表示方法有哪些?
内存地址的表示方法有很多,除了上图中的表示方法外,还有其他四种表示方法。
以下是内存地址表示方法的组成成员:
·位移(Displacement) - 8位、16位或32位值
·基(Base) - 通用目的寄存器
·索引(Index) - 除ESP外的通用目的寄存器
·比例因子(Scale Factor) - 1,2,4或8
下列五种地址模式为常用组合(图2-3):
·位移
·基
·基 + 位移
·(索引×比例因子)+ 位移
·基 + (索引×比例因子)+ 位移
图2-5:偏移(有效地址)计算
为什么只有五种表示方法,而且比例因子还有限制?
极有可能的原因是(猜测):计算机只识别机器语言,所以我们要将内存地址的表示方法翻译成机器语言才能得到执行。组合越多,翻译起来越麻烦,cpu的技术员们只好订个规矩:只能使用五种表示方法,否则一律不识别。
练习:
用实例表示以上五种组合方式。
1.[0x234791]//vc6不支持
2.[reg]
3.[reg+0x10234]
4.[reg+reg*{1,2,4,8}]
5.[reg+reg*{1,2,4,8}+0x1234]
注:reg表示通用寄存器。
课后疑问:
1. scale可以是其他值吗?
回答:不可以。
2. 如果算出的内存地址结果超过32位会怎样?
回答:如果结果超过32位溢出,则计算机只取32位。
课后总结:
内存的通用格式:reg+reg*数+立即数
课后练习:
练习复杂地址表达形式的操作如: lea eax,[eax +eax*0x02+0x12548]
1. 寄存器与内存的区别
2. 寄存器,内存
3. 内存修改
老唐语录:
快速算盘叫做寄存器。慢速的称为内存。其实他们的结构差不多,都是定宽的,最重要的一点,寄存器速度非常快,价格非常昂贵,所以在CPU内部。做的数量也很有限。常用的只做了8个:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI。内存速度慢,很便宜,所以数量做的非常庞大。寄存器做的数量非常少,就可以为每个寄存器取个名字。而内存数量太庞大了,没办法给每一个都取上名字,所以只能编号。最后重要的是内存中寄存器的编号是32位的。这也是我们现在的计算机叫32位计算机的主要原因。如果按寄存器的宽度是32位的话,是不对的,因为还有很多寄存器是大于32位的。我们通用的8个是32位的。而内存地址是固定的32位。以前的计算机之所以称为16位计算机,就是因为他的内存单元编号是16位的。
我们学过的指令MOV,能操作寄存器和内存。
所以说,汇编可以用一句话概括:汇编就是在寄存器和寄存器或寄存器和内存之间来回移动数据。就是指数据在内存和寄存器间来回流动,流动的多了,代表程序很复杂,比如office等一些大型软件。
mov eax,0x401000//给eax初始化
MOV也可以改成ADD(加),SUB(减),XOR(异或),OR(或),AND(与)。
后面的操作数为源操作数,前面的操作数为目标操作数,最开始是操作码。
其实ADD……这些也是移动指令:把源加上目标然后移动到目标操作数里面去。
前面表示操作方式,后面表示寄存器和寄存器或寄存器和内存,但是只能出现一个内存。比如:ds:[]里面写个数,表示内存单元。ptr指的是指针point。word是两个字节,还有byte是一个字节,dword是四个字节。
写法:byte/word/dword ptr ds:[32位的数]。
其实[]里面不但可以写具体的一个数,还可以写某一个寄存器的值。
方括号的通用格式:reg+reg*数+立即数,只要这个值算出来指向哪一个内存单元,就是那个内存单元(现在先记住,不要管为什么,后面会讲)。
第一个寄存器叫做BASE寄存器(8个寄存器都可以),第二个寄存器是INDEX也是8个寄存器之一,后面乘一个数scale(1,2,4或8,也就是2的0次方,2的1次方,2的2次方,2的3次方),后面再加一个数(DISP)。
BASE+INDEX*(1,2,4,8)+DISP
可以是有以下五种组合
BASE
INDEX*(1,2,4,8)
DISP
BASE+INDEX×(1,2,4,8)
BASE+INDEX×(1,2,4,8)+DISP
每一种组合都可以。
我们只有把最简单的东西用熟了,才能熟能生巧。
练习:
mov eax,ds:[0x401000+8*eax+eax];这个可以执行吗?
cpu实现了将地址赋给寄存器:LEA指令把方括号里面内存的编号给目标寄存器:load effective address。
当一个值不好确定宽度时,使用dword ptr 或者word ptr,byte ptr,源可以是内存或寄存器,也可以是立即数,但是目标不能是立即数。两方都可以是内存,但是内存只能在一个地方出现。两边的数据宽度要一样。所以指令是由操作码和操作数组成,操作码是表明我想干什么。复杂的指令也是由简单的指令组合而成。
课后理解:
内存同样由许多寄存器组成,但是此寄存器非彼寄存器,速度不及通用寄存器的几十分之一,宽度为8位。见图2-3:
图2-3:内存格式
如图2-3,为了区别内存和cpu内部的寄存器,我们将内存中的寄存器打上“[]”,专业术语称之为“地址”。图中的内存大小从0到0xFFFFffff,也就是说有0xFFFFffff个内存寄存器存在,内存地址从0-0xFFFFffff。
注:此处0xFFFFffff写法为何不写成oxFFFFFFFF?
十六进制不区分大小写,这样写是为了便于识别,我们可以很清楚的看出有8个F。
内存地址的用处是什么?
当用户运行程序时,cpu需要不停地去从存储区取代码和数据,这样非常耗时,于是cpu先将可能用到的代码和数据从存储区全部放入内存,再从内存中取数据和代码。看似多了一个过程,但是从内存中获取比存储区快得多,所以节省了很多时间。
我们如何使用内存地址呢?
我们通过实例来了解。
将32位数0x12345678存入内存中的0x12FFB8地址处:
说明:我们从图2-4可以看出:数值的高位存储在内存地址中的高位。
图2-4:内存存储方式
内存地址的表示方法有哪些?
内存地址的表示方法有很多,除了上图中的表示方法外,还有其他四种表示方法。
以下是内存地址表示方法的组成成员:
·位移(Displacement) - 8位、16位或32位值
·基(Base) - 通用目的寄存器
·索引(Index) - 除ESP外的通用目的寄存器
·比例因子(Scale Factor) - 1,2,4或8
下列五种地址模式为常用组合(图2-3):
·位移
·基
·基 + 位移
·(索引×比例因子)+ 位移
·基 + (索引×比例因子)+ 位移
图2-5:偏移(有效地址)计算
为什么只有五种表示方法,而且比例因子还有限制?
极有可能的原因是(猜测):计算机只识别机器语言,所以我们要将内存地址的表示方法翻译成机器语言才能得到执行。组合越多,翻译起来越麻烦,cpu的技术员们只好订个规矩:只能使用五种表示方法,否则一律不识别。
练习:
用实例表示以上五种组合方式。
1.[0x234791]//vc6不支持
2.[reg]
3.[reg+0x10234]
4.[reg+reg*{1,2,4,8}]
5.[reg+reg*{1,2,4,8}+0x1234]
注:reg表示通用寄存器。
课后疑问:
1. scale可以是其他值吗?
回答:不可以。
2. 如果算出的内存地址结果超过32位会怎样?
回答:如果结果超过32位溢出,则计算机只取32位。
课后总结:
内存的通用格式:reg+reg*数+立即数
课后练习:
练习复杂地址表达形式的操作如: lea eax,[eax +eax*0x02+0x12548]