计算机在运行时,需要提供数据的容器;
容器由内存和cpu提供,内存提供的容器比较多;cpu提供的容器较少但其中的数据计算速度快;
cpu提供的容器就是寄存器,寄存器有特定的数据宽度,决定了该寄存器存储数据的范围;
1.常用的32位寄存器
32位通用寄存器还可以拆分来使用;将低16位当做16位寄存器;
一些16位寄存器也可以继续拆分;高8位和低8位分别当做8位寄存器来使用;
2.mov指令
mov 目标操作数,源操作数
作用:拷贝源操作数到目标操作数
注意:
源操作数可以是立即数、通用寄存器、段寄存器、内存单元;
目标操作数可以是通用寄存器、段寄存器、内存单元;
操作数的宽度必须一样;
源操作数和目标操作数不能同时为内存单元;
mov的语法:
3.从内存中读写数据
内存由一段连续的内存单元组成,每个内存单元有8位;
32位机正常的寻址范围为0~FFFFFFFF,也就是4GB;
但这不是确定的,有些内存区域可能被固定无法访问,并且操作系统也可能扩展内存;
数据有3中类型:
字节 ->byte,宽度为8位
字 ->word,宽度为两个字节16位
双字 ->dword,宽度为两个字32位
用指令从内存中读写数据时,需要指明数据的类型
例如:
mov dword ptr ds:[0x0012FF34],0x12345678
4.内存寻址的几种方式
1)[立即数]
从内存中读
执行完后eax中的值为ds:[0x13ff4c]处的值;
mov eax,dword ptr ds:[0x13ff4c]
写:
mov dword ptr ds:[0x13ff4c],0x12345678
取内存编号:
lea指令用来获取内存地址;
有时候,某个内存地址中的值随时可能会变,获取内存地址可以用来追踪该值;
下面的的指令执行后eax的值为13ff4c;
lea eax,dword ptr ds:[0x13ff4c]
2)[reg]
reg表示寄存器,可以是8个通用寄存器中的任意一个;
从内存中读:
相当于 mov eax, dword ptr ds:[0x134ff4c]
mov ecx,0x13ff4c
mov eax, dword ptr ds:[ecx]
写:
mov dword ptr ds:[ecx],0x12345678
获取内存编号:
这里获取的是ecx的值,也就是将内存地址保存在ecx中了;
lea eax,dword ptr ds:[ecx]
3)[reg+立即数]
读:获取内存地址ds:[0x12345678]处的值
mov ecx,0x12345674
mov eax,dword ptr ds:[ecx+4]
4)[reg+reg*{1,2,4,8}]
reg代表任意一个通用寄存器;
{1,2,4,8}代表只能乘以大括号中的其中一个数;
读:
mov eax,12345
mov ecx,2
mov edx,ds:[eax+ecx*4]
5)[reg+reg*{1,2,4,8}+立即数]
读:
mov eax,12345
mov ecx,2
mov edx,ds:[eax+ecx*4+4]
5.堆栈
在程序中,经常需要存放临时数据;但寄存器数量有限,而将临时数据放入内存不方便找到;堆栈就是用来解决这一问题的;
使用堆栈的目的:
1】用于临时存储一些数据;
2】能够记录存储了多少数据;
3】能非常快速找到某个数据;
例如:下面堆栈的实现;越往上内存地址越小(windows中堆栈是往低位拓展的)
1)模拟入栈
ebx保存栈底地址,ebx保存栈顶地址;
空栈时栈底和栈顶相等;
当一个数据入栈时,先将数据存入栈顶前一个单元,再将栈顶的值修改为该单元的内存地址;
mov ebx,0x18ffb0
mov edx,0x18ffb0
mov dword ptr [edx-4],0xaaaaaaaa
sub edx,4
也可以用lea指令来实现
mov ebx,0x18ffb0
mov edx,0x18ffb0
lea edx,dword ptr [edx-4]
mov dword ptr [edx],0xaaaaaaaa
2)从栈中找数据
从栈底读第二个数
mov esi,dword ptr [ebx-4]
从栈顶读第二个数
mov esi,dword ptr [edx+4]
3)出栈
mov esi,dword ptr [edx]
lea edx,dword ptr [edx+4]
4)关于栈的指令
一般情况下,操作系统将寄存器Ebp用来村粗栈底的值;
寄存器Esp用来存储栈顶的值;
入栈指令:push
push 0x666666
push ecx
出栈指令:pop
pop esi