【滴水基础】1.汇编语言(中) |
您所在的位置:网站首页 › 汇编语言dword › 【滴水基础】1.汇编语言(中) |
【滴水基础】1.汇编语言(中) 十、内存 寄存器位于cpu之中,如8个32/64位的通用寄存器,存储数据较少。为此,引入内存。 ---每个程序都会有自己独立的4G内存空间(os分配) ---这个4G内存是假的(不是真正的内存,而是映射),是空头支票 ---1Byte=8bit;1KB=1024Byte;1M=1024kb;1GB=1024MB 内存地址:在内存中存储/读取数据,需要用到内存地址,是一种32位编号。 ---八个十六进制,一块内存对应8bit,即1Byte==2个十六进制字符 ---min:0000 0000,对应十进制:0 ---max:FFFF FFFF,对应十进制:16^8 ---对应的GB大小:16^8Byte=16^8/1024KB=16^8/1024/1024MB=4GB (1)立即数写入内存(MOV指令) ---如:将32位内存写满,需要使用dword (2)寄存器写入内存 ---但是之前1块内存的大小为1Byte=8bit,要存储32bit的立即数,需要4块内存(注意:是连续分配的内存) ---在堆栈中编号间隔4位 ---在内存中,编号间隔8*4*4位 ---在CPU的进程中,间隔编号的大小不同 ---猜测是每个指令占用的内存不同,所以每行程序的执行地址间隔也不同 ---将寄存器的内容存入内存(32位) ---换成16位 ---换成8位 ---注意:AH和AL都存储在堆栈中的低位 (3)内存写入寄存器 ---如果内存中存在寄存器ESP/EBP,就使用SS:[] ---否则使用ds:[] (4)内存写入内存 ---在汇编中,一般不允许内存到内存(可以使用MOVS指令) ---但是可以内存到寄存器,再从寄存器到内存 十一:内存地址的五种形式 C语言在汇编中的显示 ---先在关键函数处按F9下断点,再按F5开始调试。 ---接着,Alt+8出现反汇编窗口,或点击查看-->提示窗口->Disassembly: ---可以看到这里将堆栈中EBP的前32位空间,存储立即数2 ---return 0:eax xor eax,为0,并且将0存储入eax ---一般eax存储的都是函数调用的结果(在这之前应该将原来eax的值存储入堆栈,在调用函数结束后,将堆栈中的原eax的值赋值给eax寄存器) ---这里缺少了ss:[],是不标准的写法 ---内存地址的表示形式:不一定是内存编号,可以是寄存器,也可以是寄存器的四则运算等等 (1)[立即数] ---读取内存的值/向内存中写入数据 (2)[reg]: reg为寄存器,可以是八个通用寄存器的1个 ---读取内存的值 ---向内存中写入数据 (3)[reg+立即数] ---读取内存的值 ---向内存中写入 (4)[reg+reg*[1,2,4,8]] ---注意,只能为1,2,4,8,因为堆栈中的地址之间间隔4 ---读取内存的值 ---反正EAX的移动距离只能是4的倍数,如这里2*4=8(下移2个堆栈) ---向内存中写入数据 (5)[reg+reg*[1,2,4,8]+立即数] ---读取内存 ---向内存中写入数据 十二:数据的存储模式 ---1个内存块(编号)是8bit,但是在堆栈内存中,一个堆栈编号是32bit ---所以1个堆栈内存=4个连续的内存块 ---那么,数据的存储在内存中是从高位开始存储还是低位存储 Mov word ptr ds:[0000 0000],0x1A2C ---这里从0000 0000开始,但是word有16位,1个内存地址不够存 ---就从0000 0000开始占2个内存地址(Dword就是四个) ---0x1A2C中,1A是数据高位,2C是数据低位 ---那么,数据的高位、低位在内存中是如何存储的? ---可以发现,上图是小端模式存储 ---arm的cpu(手机)的存储模式多为大端存储 ---X86的cpu(电脑) 的存储模式多为小端存储,但是不是绝对的 ---如:mov dword ptr ds:[0000 0000],1A2C3E4F ---大端模式 ---小端模式 #程序内存地址的查看 ---内存地址的查看,只能看堆栈中已经分配的地址 ---查看19D008的内存 ---查看一个字节,用db ---发现数据的低位是21 ---后面的43、65、87分别是08、09、0A、0B的1byte的内存低位 ---以2byte的形式查看 ---以4byte的形式查看,发现和堆栈的表现形式一样 ---向内存中写入4byte数据,观察存储形式 ---以byte查看,发现内存的低位44=数据的低位 ---此电脑的存储方式是小端存储 #总结 ---数据的存放:寄存器、内存 ---数据的存储方式:小端存储 ---数据的存储:以补码的形式存储 ---无符号数:原码=反码=补码;有符号数:补码=反码+1 十三:常用的汇编指令 #相关符号 ---r:通用寄存器,如r8为8位通用寄存器 ---imm:立即数,如imm8位8位立即数 ---m:内存,如m8位8位内存 #简单指令 (1):MOV指令(不能内存到内存) (2):ADD指令 (3):SUB指令 ---前面的寄存器减去后面的 ---将结果存储到前面的寄存器 (4):AND指令 ---两者都为1时才为1 (5)OR指令 ---只有存在1个1,就为1 (6)XOR指令 ---两个不一样(一公一母)才为1 (7)NOT指令 ---对EDX取反 #较复杂的指令 ---EDI(destination index):目的地址寄存器,存储目的地址的内存编号 ---ESI(source index):源地址寄存器,存储源地址的内存编号 (1)MOVS指令(从内存到内存移动数据) ---简写:MOVSB ---注意:执行完后,EDI、ESI的值+或者-1/2/4(根据复制的数据大小判断) ---同理: ---MOVS word ptr ES:[EDI],word ptr DS:[ESI] //简写:MOVSW ---MOVS dword ptr ES:[EDI],dword ptr DS:[ESI] //简写:MOVSD ---注意:EDI、ESI的值+或者-根据EFL(32标志寄存器)的DF来判断 ---DF(方向位),在EFL寄存器中的第十位 ---根据byte、word、dword来判断加减的数据的大小 ---将19FF78的值复制到19FF7C中去 ---单步步过,ESI\EDI的值为 ---执行MOVS指令 ---发现ESI/EDI+4,且DF=0 (2)STOS指令(将AL/AX/EAX的值存储到EDI指定的内存单元) ---EDI所指向的内存要用ES ---根据DF的值,来判断指向STOS命令后EDI的加减 ---STOS byte ptr es:[EDI] //STOSB ---STOS word ptr es:[EDI] //STOSW ---STOS dword ptr es:[EDI] //STOSD ---执行后,只将EAX中的最低位赋值给了EDI指向的内存地址 ---EDI的值+1 ---缺点:只能1次将EAX复制到内存(1次最多4byte) (3)REP指令:计数寄存器 ---根据ECX(计数寄存器),遍历执行,每次ECX-1 ---执行rep后,ecx循环3次,应该是将[esi,esi+12]的数据复制到[edi,edi+12]的堆栈中去 ---ecx变为0 ---edi指向的堆栈发现增加了3个dword的地址 ---这里是根据DF来判断,如果DF=1,则就是向上增加堆栈 ---将EAX的值连续赋值给堆栈 ---这里将EAX赋值给[edi,edi+4*4] 十四:堆栈相关指令 什么是堆栈? ---操作系统在程序启动时分配,和数据结构的堆栈无关 ---查看程度的核心:查看堆栈 ---查看exe程序被分配的内存 ---查看FS,可以看出OS分配了多少的内存 ---这里是336000 ---查看这块内存,336000为指向SEH的指针(SHE是啥啊) ---从19D000开始,从1A000结束 ---在堆栈中查看(堆栈在使用是从后往前使用,我的理解是:将分配的内存压入堆栈,最后面的内存就在最上面,就最先使用) ---如果程序超出了堆栈,会导致堆栈溢出 ---栈底是:19FFFC,19FFFC+4=19A000 ---栈顶是19D000 #如何查看当前进程的堆栈使用情况? ---ESP(stack pointer):栈顶指针寄存器,记录当前程序使用的堆栈 ---[19FFFC,19FF78]是当前程序使用的堆栈 ---[19FF74, 19D000]是后面程序使用的堆栈 ---ESP向上移动8位 ---向下移动8位 ---注意:单纯的移动数据是无法改变ESP ---SUB/ADD的缺点:在修改堆栈之后,还要进行ESP的修改 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |