滴水三期:day03.1-内存

一、内存概述

  • 寄存器与内存的区别:

    1. 寄存器位于CPU内部,执行速度快,但比较贵;内存速度相对较慢,但成本较低,所以可以做的很大
    2. 寄存器和内存没有本质区别,都是用于存储数据的容器,都是定宽的(都有最大的存储范围)
  • 计算机常用的计量单位:

    • BYTE 字节 = 8(bit)
    • WORD 字 = 16(bit)
    • DWORD 双字 = 32(bit)
  • 生活中常用的计量单位:

    • 1KB = 1024 BYTE
    • 1MB = 1024 KB
    • 1GB = 1024 MB
  • 计算机的32位和64位内存是什么意思

    • 误区:不是说32位计算机寄存器或者内存的最大宽度为32bit!!而是CPU的最大寻址范围为32bit!其实32位计算机中也有很多寄存器是大于32位的,但是给一个地址让CPU去寻找比如二进制111010101、010101、1、…,只要不超过32位,CPU就可以根据地址来寻找内存活寄存器中编号是这个中的值

    • 为内存编号:寄存器个数比较少,所以可以给每一个寄存器命名,比如eax,bx,ah等。内存的数量特别庞大,无法让每个内存单元都有名字,所以用编号来代替,编号就是地址,每一内存单元都有编号(地址)

    • 编号是怎么编的:32位,可以想成CPU上有32根线路,每根线路有0和1两个种状态,32根线每根线有两种情况,那么32个根线变化一次,可以代表一个值(二进制数),这个值就是一个编号。通过编号,就可以找到对应的内存!这些编号加在一起所有的情况就是能寻找的内存的范围

    • 32位用十六进制表示:可以表示为8个十六进制数,计算机中以字节为最小单位,所以内存中每一个字节单位会有一个编号,即内存中以8bit为一个单位,为其编号。每一个编号对应内存中一个字节,即一个编号中可以存储8个0或者1组合

    • 计算机内存编号一共有多少种可能:0xFFFFFFFF - 0x00000000 + 1 = 0x100000000种可能(也可以用十进制算32位,每一位都有0和1两种可能,组合起来232 = 4,294,967,296种可能),而我们说过一个内存编号对应8位即一个字节BYTE,那么现在算一算计算机可以识别多大的内存呢,先将BYTE化成KB:4,294,967,296 / 1024 = 4,194,304再换算成MB:4,194,304 / 1024 = 4,096;最后化成GB:4,096 / 1024 = 4GB。所以32位计算机能识别出4GB的内存。但是现在由于计算机有些硬件会占用一些内存,所以实际上显示的内存肯定小于4GB,你如果让CPU去找被硬件占用的内存,会找不到。

      image-20211123110408983
    • 同理64位计算机能识别多大的内存:264 = 18,446,744,073,709,551,616(BYTE)。换算成TB为18,446,744,073,709,551,616 / 1024 /1024 /1024 /1024 = 16,777,216(TB)。但是会受到物理硬件的限制,实际能使用的到不了这么大

    • 总结:32位还是64位的计算机由什么决定?跟寄存器的宽度没有关系,而是跟寻址宽度有关系,即CPU能寻找的内存编号的范围,每一个内存编号对应1字节,所以32位计算机能查找的最大内存范围4GB

  • 扩展:32位计算机能识别的内存大小为4GB正确;但是32位计算机能识别的内存最多是4GB是不一定的!!!因为有些操作系统可以打补丁拓展寻址范围。但是一般情况下就是4GB

  • 哪些地址可以访问:任何一个.exe程序在计算机上都有自己独立的4GB空间,但是这个是虚拟的,后面会讲到。我们使用汇编语言如果想访问这个程序的某地址,有些地址是无法访问的,程序不允许访问;那么怎么确定

  • 我们在反汇编窗口、寄存器区域和堆栈窗口,写的和显示的十六进制数都是从高位写到低位,挨着顺序写;但是数据窗口中显示的是反着的,从低位显示到高位。比如我们写十六进制数b6 b3 7c e4,但是在数据窗口中会显示为e4 7c b3 b6。注意因为计算机中以字节为单位,也就是以内存块为单位,两个十六进制数刚好一个字节,所以每两个十六进制数当做一个整体,顺序是不变的,但是字节与字节之间(内存块与内存之间)的循序发生变化。所以**如果数据窗口中显示的数据为60 1a 82 7c,那么我们读到的数应该为7c 82 1a 60!**但是要注意:下图中堆栈一个地址可以表示4字节值,也就是4个内存块用一个地址表示。虽然0019ff74中存的数据要反,但是不能把0019ff78与0019ff74也弄反,因为不管在哪里,地址都是要挨着顺序写的

    image-20211123201829962 image-20211120000129787
  • 插件显示的命令的窗口的使用:

    db 0x0019ff74
    dd 0x0019ff74
    

    d表示数据,b表示byte,后面的0x0019ff74表示内存地址。整命令的意思为为以一个字节为单位显示0x0019ff74地址对应内存块中的值,如果这个地址为栈中的地址,因为下面提到过,堆栈中用0x0019ff74可以表示0x0019ff74到0x0019ff77这四个内存块,所以一个0x0019ff74可以存4字节值,但是其实还是由4块内存存的,此时用此命令显示db 0x0019ff74会显示4字节的内容

    image-20211123201829962

    dd 0x0019ff74显示如下:(注意,如果软件以4字节为一个单位显示数据窗口(跟堆栈一样),那么此时的顺序是不变的,软件自动帮你做反转)

    image-20211123202019220

二、内存地址格式

  • 一般在汇编中,内存编号也用16进制数表示,立即数也有用十六进制的数写。那么我们怎么才能让计算机区分开呢?只要在内存编号的两侧加[],如[0x12345678]就表示一个内存编号,即地址

  • 每个内存单位的宽度为8bit,[编号]称为地址,地址的作用是:当我们想从内存中读取数据或者想向内存中写入数据,首先应该找到要读、写的位置

  • 内存编号是连续的。比如从上到下是[0x00000000]一直连续到[0xffffffff]。也可以从下到上,是自己决定的

    image-20211123111953715

三、内存相关汇编指令

  • 格式:mov dword ptr ds:[0x0012ff34],0x12345678

  • 解释:

    • dword表示要使用的内存大小为4个字节,即要读/写多少;还可以是byte和word等
    • ptr就表示代表后面是一个指针,即后面要跟内存编号(固定写法);
    • DS是段寄存器,32位汇编中段寄存器和内存的属性有关系:如果后面地址直接用数表示,则用DS;如果后面写ESP或者EBP,就写SS;如果EDI的话就用ES。所以32位汇编中段寄存器就是后面内存属性的一个标识。
    • [0x0012ff34]表示后面的立即数存入内存的(起始)地址,如果前面是dword,表示从这个内存地址对应的一字节内存块开始存储(或读取),一共要存储(或读取)4字节内存,即4个内存块(因为一个地址对应一字节大小内存,那么一个编号可能不够存),即从[0x0012ff34]这个单元块开始存(或读),再往高地址存,依次往下,直到占用了4字节的内存,即从[0x0012ff34][0x0012ff37]都是用来存这个指令后面的数值的!
    • 0x12345678就是存入内存的数值,称为立即数。如果立即数的宽度比前面指定的内存宽度大,则从低位开始取,取到指定的宽度,高位多余的部分就被丢弃,比如要写入dword,但是立即数为0x123456789,则最终写入的内存的值为0x23456789,一共4字节
  • 注意:地址编号不要随便写,因为内存是有保护的,并不是所有的内存都可以直接读写。建议写表示栈的地址范围内的地址,即esp到ebp中存的地址之间的地址,一般建议要测试的话esp中存的地址值肯定可以使用

    22D581AD3FABFE925D8A6502EFB2FEAC
  • 我们此时可能有疑问:前面不是说一个地址编号对应一个字节的内存块,但是上面0x0019ff74地址对应的内存中存的数为0x769dfa29,这个值大于一个字节,已经4个字节大小了,怎么能用一个地址编号表示?其实是因为,这里是用0x0019ff74到0x0019ff77来存储后面的4字节的值,但是这四块内存块用一个地址编号0x0019ff74(起始地址)表示,相当于一个用0x0019ff74表示0x0019ff74到0x0019ff77这四个内存块,这样看起来更整洁一些!

  • 我们分开来看:0x0019ff74表示了四个内存块,四个内存块中的值一起显示为0x769dfa29。分开来看:0x0019ff74地址中的值为0x29;0x0019ff75地址中的值为0xfa;0x0019ff76地址中的值为0x9d;0x0019ff77地址中的值为0x76!(因为地址从低到高对应存的数也是从低位到高位,一个字节为一个整体,即小端存储)。所以可以发现OD其实已经帮我们把栈中的数据反过来了,用我们平时读写的顺序显示。这里要和VC6++中的内存分开,VC6++没有帮我们把数据反过来。

四、小作业

练习下面的指令,深刻理解寄存器、内存以及数据的宽度

1.MOV指令
  • MOV r/m8,r8

    mov ah, ch
    mov byte ptr ds:[19FF78], dl
    

    未执行前ah的值为FF,0x0019ff78中的值为0x003cf000;执行两条语句后,eax中的值变为0x001911CC,0x19ff78中的值变为0x003cf050

    image-20211123170632150 image-20211123170906404

  • MOV r/m16,r16

    mov ax,bx
    mov word ptr ds:[0x0019ff74],bp
    

    eax中值变为0019f000;0x0019ff74中的值变为769dff80

    image-20211123172036543
  • MOV r/m32,r32

    mov esp,esi
    mov dword ptr ds:[0x0019ff78],esp
    

    esp中的值变为00401150;0x0019ff78中的值变为0019ff74

  • MOV r8,r/m8

    mov bl,cl
    mov bl,byte ptr ds:[0x19ff74]
    

    ebx中的值变为00306050;ebx中的值变为00306029

image-20211123172608037 image-20211123172728429

  • MOV r16,r/m16

    mov sp,bp
    mov di,word ptr ds:[0x19ff7c]
    
  • MOV r32,r/m32

    mov eax,ecx
    mov esp,dword ptr ds:[0x19ff80]
    
  • MOV r8, imm8

    mov dh,0xaa
    
  • MOV r16, imm16

    mov sp,0xaaaa
    

    esp中的值变为0019aaaa

    image-20211123172823699 image-20211123172916390

  • MOV r32, imm32

    mov ecx,0xaaaaaaaa
    
2.ADD指令
  • ADD AL, imm8

    ADD AL,0x11
    
  • ADD AX, imm16

    ADD AX,0x1111
    

    如果ax中的值与0x1111加完后值大于2字节,则高位部分舍弃,取低位的2字节值

  • ADD EAX, imm32

    ADD EAX,0x10000000
    
  • ADD r/m8, imm8

    ADD al,0x11
    add byte ptr ds:[0x0019ff78],0x11
    
  • ADD r/m16,imm16

    ADD AX,0x1111
    add word ptr ds:[0x0019ff78],0x1111
    
  • ADD r/m32,imm32

    ADD eax,0x12345678
    add dword ptr ds:[0x19ff78],0x11111111
    
  • ADD r/m16, imm8

    add ax,0x11
    add word ptr ds:[0x19ff78],0x11
    

    该怎么加怎么加,加完超过宽度的值,高位舍弃;这是前面的值宽度比后面值宽度大的情况;如果后面的值宽度比前面的容器宽度大,则后面的值在计算前就会舍弃多出来的高位

  • ADD r/m32, imm8

    add edi,0x11
    add dword ptr ds:[0x0019ff78],0x11
    
  • ADD r/m8, r8

    add cl,0x11
    add byte ptr ds:[0x19ff78],0x11
    
  • ADD r/m16, r16

    add cx,0x1111
    add word ptr ds:[0x19ff78],0x1111
    
  • ADD r/m32, r32

    add eax,0x11111111
    add dword ptr ds:[0x19ff78],0x10000000
    
  • ADD r8, r/m8

    add bh,ch
    add bh,byte ptr ds:[0x11]
    
  • ADD r16, r/m16

    add si,di
    add si,word ptr ds:[0x1111]
    
  • ADD r32, r/m32

    add ebx,eax
    add edx,dword ptr ds:[0x10000000]
    
3.SUB指令
  • SUB AL, imm8

  • SUB AX, imm16

  • SUB EAX, imm32

    sub eax,0xabcd1234
    

    如果减出来后是负数,还是从低位到高位去取前面寄存器或者内存的宽度,高位舍弃

  • SUB r/m8, imm8

  • SUB r/m16,imm16

  • SUB r/m32,imm32

  • SUB r/m16, imm8

    sub ax,0x1111
    sub word ptr ds:[0x19ff78],0x1111
    
  • SUB r/m32, imm8

    sub eax,0x1000
    sub dword ptr ds:[0x19ff78],0x1000
    
  • SUB r/m8, r8

  • SUB r/m16, r16

  • SUB r/m32, r32

  • SUB r8, r/m8

  • SUB r16, r/m16

  • SUB r32, r/m32

4.AND指令
  • AND AL, imm8

  • AND AX, imm16

  • AND EAX, imm32

    and eax,0x1a7c7771
    

    自己算的话就先把十六进制换成二进制,再做运算

  • AND r/m8, imm8

  • AND r/m16,imm16

    and si,0x1122
    
  • AND r/m32,imm32

  • AND r/m16, imm8

    and ax,0xf8
    and word ptr ds:[0x19ff78],0xf8
    

    把低位对齐后再同1为1,不同为0做and运算

  • AND r/m32, imm8

  • AND r/m8, r8

  • AND r/m16, r16

  • AND r/m32, r32

  • AND r8, r/m8

  • AND r16, r/m16

  • AND r32, r/m32

5.OR指令

语法和and类似

  • OR AL, imm8
  • OR AX, imm16
  • OR EAX, imm32
  • OR r/m8, imm8
  • OR r/m16,imm16
  • OR r/m32,imm32
  • OR r/m16, imm8
  • OR r/m32, imm8
  • OR r/m8, r8
  • OR r/m16, r16
  • OR r/m32, r32
  • OR r8, r/m8
  • OR r16, r/m16
  • OR r32, r/m32
6. XOR指令

与and类似

  • XOR AL, imm8
  • XOR AX, imm16
  • XOR EAX, imm32
  • XOR r/m8, imm8
  • XOR r/m16,imm16
  • XOR r/m32,imm32
  • XOR r/m16, imm8
  • XOR r/m32, imm8
  • XOR r/m8, r8
  • XOR r/m16, r16
  • XOR r/m32, r32
  • XOR r8, r/m8
  • XOR r16, r/m16
  • XOR r32, r/m32
7.NOT指令

全部取反即可

  • NOT r/m8

  • NOT r/m16

  • NOT r/m32

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值