• 汇编学习笔记(2) -- 寄存器(内存访问),数据段和栈


    内存中字的存储
    一个字两个字节
    所以内存中用两个地址连续的内存单元存储一个字
    该字的低位字节存放在低地址内存单元,高位字节存放在高地址内存单元
     
    20000的十六进制是4E20H 高位就是4E,存在地址高一点的地址内存单元中
     
     
    字单元
    由此就有了 字单元: 由两个地址连续的内存单元组成
    将起始地址为N的字单元简称为N地址字单元
    如:地址为2,3的两个内存单元组成的字单元,称之为 2地址字单元
     
    总结:
    任何两个地址连续的内存单元,N号单元和N+l号单元
    可以将它们看成两个内存单元
    也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元
     
     
     
    DS和[address]
    DS是一个寄存器,通常用于存放要访问数据的地址,称为段寄存器
    1 mov bx,1000H
    2 mov ds,bx
    3 mov al,[0]
    将10000H[1000:0]中的数据读到al寄存器中
     
    mov al,[0]
    mov 寄存器名,内存单元地址
    [...]表示一个内存单元,其中0表示偏移地址
    而段地址是8086CPU 自动取ds中的数据为内存单元的段地址
     
    注意,不能直接:mov ds 1000H
    因为8086不支持将数据直接送入段寄存器,只能先送到一个一般的寄存器(如bx),再将bx内容送入ds
     
     
    问题:将al中的数据送入内存单元10000H
    答案:
    1 mov bx,1000H
    2 mov ds,bx   10000H的地址送入ds中
    3 
    4 mov [0],al  [0]是偏移地址,段地址从ds自动获取
    字的传送
    8086是16位结构,有16根数据线
    所以一次可以传输16位数据,即一次传一个字
    例如
    1 mov bx,1000H
    2 mov ds,bx
    3 mov ax,[0]  1000:0处的字形数据送入ax
    4 mov [0],cs  cs中的16位数据送到1000:0处
    例题 执行后,ax,bx,cx的值是多少
    ax = 1123H, bx = 6622H, cx = 8833H
     
     
     
    数据段
    将一组地址连续起始地址是16的倍数 的内存单元 当作专门存储数据的内存空间,从而定义了数据段
    例如:
    将123B0H ~ 123B9H 这段内存单元作为专门存储数据的内存空间
    这段内存就是一个段地址为123BH,长为10个字节的数据段
     
    将123B0H ~ 123B9H定义为数据段,将三个单元的数据累加到al
    1 mov ax,123B
    2 mov ds,ax
    3 mov al,0
    4 mov al,[0]
    5 mov al,[1]
    6 mov al,[2]
    栈是一种具有特殊访问方式的存储空间。
    特殊处在于:最后进入这个空间的数据,最先出去
     
    入栈:将一个新的元素放到栈顶
    出栈:从栈顶取出一个元素
     
    栈顶的元素总是最后入栈
    需要出栈时,又最先被从栈顶取出
     
    操作规则:LIFO(先进后出)
     
     
     
    可以将一段内存当作栈来使用
     
     
    指令:
    push 入栈
    push ax:将寄存器ax中的数据送入栈中
     
    pop 出栈
    pop ax 从栈顶取出数据送入ax
    8086中入栈和出栈都是以字为单位进行(8086是16位,酷睿是64位)
     
     
    1 mov ax,0123H
    2 push ax
    3 mov bx,2266H
    4 push bx
    5 mov cx,1122H
    6 push cx
    7 pop ax
    8 pop bx
    9 pop cx
    注意,字形单元用两个单元存放,高地址单元存放高8位,低地址单元存放低8位
     
     
    SS:SP
    任意时刻,SS:SP指向栈顶元素
    段寄存器SS 存放栈顶的段地址
    寄存器SP 存放栈顶的偏移地址
     
    执行push,pop时,cpu从SS和SP中得到栈顶的地址
     
     
    push ax执行过程
    1 SP = SP - 2
    2 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶
     
    将10000H ~ 10005H 这段空间作为栈,初始状态栈为空
    则SS:SP指向 栈空间最高地址单元 下一个单元(100006H)
     
    由于SS:SP在任意时刻指向栈顶,而栈为空时 栈中无元素 也就没有栈顶
    所以SS:SP 只能指向 栈的 最底部单元 下面的单元 (栈的顺序可以理解为地址小的在上面)
    该单元的偏移地址为 栈最底部的 字 单元 的 偏移地址 +2
     
    栈最底部字单元的地址为1000:0004,所以栈空时,SP = 0006H
     
     
    pop指令执行过程:
     
     
    栈顶超界
    执行push后栈顶超出栈空间
     
    执行pop后栈顶超出栈空间
     
     
    栈空间之外可能是其它重要用途的数据代码等
    而超出栈空间后的 数据会覆盖 原数据
    也就是栈溢出
     
    例题
    1 将10000H~1000FH 这段空间当作栈,初始状态栈是空的,将AX、BX、DS中的数据入栈。
    1 mov ax,1000H
    2 mov ss,ax        设置栈的段地址,ss=1000H,不能直接向段寄存器ss中送入数据,所以用ax中转。
    3 mov sp,0010H     设置栈顶的偏移地址,因栈为空,所以sp=0010H。
    4 push ax
    5 push bx
    6 push ds
     
    2 在10000H处写入字型数据2266H
     1 mov ax,1000H
     2 mov ds,ax
     3 mov ax,2266H
     4 mov [0],ax
     5 
     6 mov ax,1000H
     7 mov ss,ax
     8 mov sp,2   执行push时,cpu会SP=SP-2
     9 
    10 mov ax,2266H
    11 push ax
    由于push,pop执行时只修改SP,所以栈顶变化范围为0~FFFFH
     
     
    栈段
    我们可以将长度为N(N≤64KB)的一组
    地址连续、起始地址为16的倍数的内存单元,当作栈空间来用
    从而定义了一个栈段
     
    比如,我们将10010H~1001FH 这段长度为16字节的内存空间当作栈来用
    这段空间就可以称为栈段,段地址为1001H,大小为16字节
    使用SS:SP指向我们自定义的栈段
     
    一个栈段最大为64kb
    因为push,pop指令只修改sp,栈段变化范围为0~FFFFH,所以有65536个字节,即64kb
     
    问题
    如果将10000H~1FFFFH 这段空间当作栈段,初始状态栈是空的,此时,
    SS=1000H,SP=?
    栈最底部的字单元地址为1000:FFFE。
    栈为空,就相当于栈中唯一的元素出栈,出栈后,SP=SP+2。
    加2后SP=10000,数字太大,1不能存入SP,所以SP=0。
     
     
     
    段的总结
    对于数据段,将它的段地址放在DS中,用mov、add、sub等访问内存单元的指令时
    CPU就将我们定义的数据段中的内容当作数据来访问
     
    对于代码段,将它的段地址放在CS中,将段中第一条指令的偏移地址放在IP中
    这样CPU就将执行我们定义的代码段中的指令;
     
    对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中
    这样CPU在需要进行栈操作的时候,比如执行push、pop指令等,就将我们定义的栈段当作栈空间来用。
     
    比如我们将1000OH~1001FH 安排为代码段,并在里面存储如下代码:
     1 mov ax,1000H
     2 mov ss,ax
     3 mov sp,0020H        ;初始化栈顶
     4 mov ax,cs        
     5 mov ds,ax        ;设置数据段段地址
     6 mov ax,[0]
     7 add ax,[2]
     8 mov bx,[4]
     9 add bx,[6]
    10 push ax
    11 push bx
    12 pop ax
    13 pop bx
     
    设置 CS=1000H,IP-0,这段代码将得到执行。
    可以看到,在这段代码中,我们又将10000H~1001FH安排为栈段和数据段。
    10000H~1001FH 这段内存,既是代码段,又是栈段和数据段。
     
    一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是。
    关键在于 CPU中寄存器的设置,即CS、IP,SS,SP,DS的指向
     
    参考: 王爽 - 汇编语言 和 小甲鱼零基础汇编
     
     
  • 相关阅读:
    qt.network.ssl: QSslSocket: cannot call unresolved function SSLv23_client_method
    使用 acl_cpp 的 HttpServlet 类及服务器框架编写WEB服务器程序(系列文章)
    C编译器剖析PDF文档及UCC编译器162.3
    深入浅出NodeJS——数据通信,NET模块运行机制
    看AngularJS
    如何编写高效的jQuery代码
    Express安装入门与模版引擎ejs
    使用SeaJS实现模块化JavaScript开发
    RequireJS 入门指南
    RequireJS
  • 原文地址:https://www.cnblogs.com/ZhouJiaHao/p/13635738.html
Copyright © 2020-2023  润新知