美文网首页
数据段, 代码段, 栈段的一点理解

数据段, 代码段, 栈段的一点理解

作者: yww | 来源:发表于2018-07-09 16:00 被阅读34次

    我们知道, 一个程序要运行, 首先要将程序加载进入内存中, 然后运行其中的代码, 同时, 我们的程序也会在运行过程中, 保存一部分数据到内存中.
    我们知道, 可以运行的代码, 例如求解一个方程组, 都是放在代码段中的
    数据段中则会存放一些初始化数据, 例如我们的已经初始化的全局变量
    而栈段则会存放运行中的堆栈信息, 临时变量等.
    当然还会有堆区等其他区段, 这里暂且忽略.
    对于计算机来讲, 所有的代码和数据都可以2进制形式存放在内存中, 那么对于某一个特定的内存地址, 我们如何辨别这个数据是代码还是普通数据?

    总所周知, cpu 内部有若干寄存器, 有些寄存器是通用寄存器, 可以存放普通的数据, 例如用来存放加法指令的结果.
    而还有些则有自己特定的功能.
    对于代码段来说, cpu 需要知道当前的代码在内存中的哪个位置, 这一点, 就是靠的CS, IP 寄存器(8086 CPU, 下同).
    例如, 当CS 为 0x1000, IP 为 0x0001, 那么下一句代码的位置就在 CS*0x10+IP = 0x100001 这个地址. CS 就是代码段地址, 而IP 则是代码段偏移量, 可以看到, 当前有一个代码段位于 0x10000 处.
    当cpu 需要从内存中读取某个全局变量时, 则会用到另外一个寄存器, DS, 例如我们有一个全局变量位置在 0x20005 处. 我们如果要读取可以使用类似下面的指令

    mov ds, 0x2000; 给ds 寄存器赋值, 相当于 ds=0x2000,实际上没有这个指令, 并不能直接给ds 赋值, 需要使用其他寄存器中转, 类似于 ax=0x2000; ds=ax 这样. 这里为了方便理解, 就这样写了.
    mov ax, [5]; 读取制定内存位置的数据到寄存器中. [5]表示偏移量, 偏移量是相对于ds 来说, 这里就相当于 ax=*((int*)(ds+5))
    

    也就是说, DS 寄存器标识了一个段, 我们这里存在一个段在 0x2000 处.
    同理, 栈也有寄存器, SP 和 SS, SS 表示栈顶, SP 标识偏移量, SS 就标识了一个栈段.

    这里就存在一个问题, 起始我们是可以任意修改这些寄存器的, 也就是说, 何处是代码段, 何处是数据段是我们自己规定的, CPU 并不知道, 它只知道CS:IP 这个地方的数据需要读取出来运行, 而 SS:SP 这个位置, 可以读取一个栈的数据.
    所有的一切, 都只是我们的一厢情愿. 你如果错误的将CS:IP 指向了一个数据段的地址, 那么CPU 运行时可能就直接异常退出了, 同理, 当尝试从代码段读取数据时, 也只会读到一段莫名其妙的数据.CPU 并不会帮你处理这些异常的行为, 一切都在你自己手里.
    还有一个问题, 就是这些寄存器都只有一个起始位置, 并没有一个能表示长度的寄存器, 特别是对于栈段.例如, 我们规定0x30000-0x3000F 保存的是栈中的数据, 0x30010-0x3001F 保存的是代码, 那么如果我们在栈区多次pop, 就有可能跑道代码区里面去了, 就有可能会错误修改代码区数据, 导致程序无法正常运行.

    相关文章

      网友评论

          本文标题:数据段, 代码段, 栈段的一点理解

          本文链接:https://www.haomeiwen.com/subject/lcftpftx.html