⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 缓冲溢出原理.doc

📁 介绍缓冲溢出的原理
💻 DOC
📖 第 1 页 / 共 5 页
字号:
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>stack),堆栈乱写(scribble the stack),堆栈毁坏(mangle the stack);</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>术语mung the stack并不使用,因为这从来不是故意造成的.参阅spam?</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>也请参阅同名的漏洞,胡闹内核(fandango on core),内存泄露(memory </span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>leak),优先权丢失(precedence lossage),螺纹滑扣(overrun screw).</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>简<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>介</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>~~~~~~~</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;</span>在过去的几个月中,被发现和利用的缓冲区溢出漏洞呈现上升趋势.例如syslog,</span></pre><pre><span
  lang=EN-US>splitvt, sendmail 8.7.5, Linux/FreeBSD mount, Xt library, at等等.本文试图</span></pre><pre>解释什么是缓冲区溢出<span
  lang=EN-US>, 以及如何利用.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>汇编的基础知识是必需的. 对虚拟内存的概念, 以及使用gdb的经验是十分有益</span></pre><pre>的<span
  lang=EN-US>, 但不是必需的. 我们还假定使用Intel x86 CPU, 操作系统是Linux.</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>在开始之前我们给出几个基本的定义: 缓冲区,简单说来是一块连续的计算机内</span></pre><pre><span
  class=GramE>存区域</span><span lang=EN-US>, 可以保存相同数据类型的多个实例. C程序员通常和字缓冲区数组打交道.</span></pre><pre>最常见的是字符数组<span
  lang=EN-US>. 数组, 与C语言中所有的变量一样, 可以<span class=GramE>被声明</span>为静态或动态</span></pre><pre>的<span
  lang=EN-US>. 静态变量在程序加载时定位于数据段. 动态变量在程序运行时定位于堆栈之中.</span></pre><pre>溢出<span
  lang=EN-US>, 说白了就是灌满, 使内容<span class=GramE>物超过</span>顶端, 边缘, 或边界. 我们这里只关心动态</span></pre><pre>缓冲区的溢出问题<span
  lang=EN-US>, 即基于堆栈的缓冲区溢出.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>进程的内存组织形式</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>~~~~~~~~~~~~~~~~~~~~</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>为了理解什么是堆栈缓冲区, 我们必须首先理解一个进程是以什么组织形式在</span></pre><pre>内存中存在的<span
  lang=EN-US>. 进程被分成三个区域: 文本, 数据和堆栈. 我们把精力集中在堆栈</span></pre><pre>区域<span
  lang=EN-US>, 但首先按照顺序简单介绍一下其他区域.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>文本区域是由程序确定的, 包括代码(指令)和只读数据. 该区域相当于可执行</span></pre><pre>文件的文本段<span
  lang=EN-US>. 这个区域通常被标记为只读, 任何对其写入的操作都会导致段错误</span></pre><pre><span
  lang=EN-US>(</span><span class=GramE><span lang=EN-US style='font-size:14.0pt;
  font-family:黑体'>segmentation</span></span><span lang=EN-US style='font-size:
  14.0pt;font-family:黑体'> violation</span><span lang=EN-US>).</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>数据区域包含了已初始化和未初始化的数据. 静态变量储存在这个区域中. 数</span></pre><pre><span
  class=GramE>据区域</span>对应可执行文件中的<span lang=EN-US>data-bss段. 它的大小可以用系统调用brk(2)来改变.</span></pre><pre>如果<span
  lang=EN-US>bss数据的扩展或用户堆栈把可用内存消耗光了, 进程就会被阻塞住, 等待有了</span></pre><pre>一块更大的内存空间之后再运行<span
  lang=EN-US>. 新内存加入到数据和堆栈段的中间.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>/------------------\<span style='mso-spacerun:yes'>&nbsp; </span>内存低地址</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>文本<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|------------------|</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>(已初始化)<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>|</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>数据<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>(未初始化)<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>|</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|------------------|</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>堆栈<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>|<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>|<span style='mso-spacerun:yes'>&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>\------------------/<span style='mso-spacerun:yes'>&nbsp; </span>内存高地址</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Fig. 1 进程内存区域</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>什么是堆栈?</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>~~~~~~~~~~~~~</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>堆栈是一个在计算机科学中经常使用的抽象数据类型. 堆栈中的物体具有一个特性:</span></pre><pre>最后一个放入堆栈中的物体总是被最先拿出来<span
  lang=EN-US>, 这个特性通常称为<span class=GramE>后进先处</span>(LIFO)队列.</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>堆栈中定义了一些操作. 两个最重要的是PUSH和POP. PUSH操作在堆栈的顶部加入一</span></pre><pre><span
  class=GramE>个</span>元素<span lang=EN-US>. POP操作相反, 在堆栈顶部移去一个元素, 并将堆栈的大小减<span
  class=GramE>一</span>.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>为什么使用堆栈?</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>~~~~~~~~~~~~~~~~</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>现代计算机被设计成能够理解人们头脑中的高级语言. 在使用高级语言构造程序时</span></pre><pre>最重要的技术是过程<span
  lang=EN-US>(procedure)和函数(function). 从这一点来看, 一个过程调用可</span></pre><pre>以<span
  class=GramE>象</span>跳转<span lang=EN-US>(jump)命令那样改变程序的控制流程, 但是与跳转不同的是, 当工作完成时,</span></pre><pre>函数把控制权返回给调用之后的语句或指令<span
  lang=EN-US>. 这种高级抽象实现起来要靠堆栈的帮助.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>堆栈也用于给函数中使用的局部变量动态分配空间, 同样给函数传递参数和函数返</span></pre><pre><span
  class=GramE>回值也要用到</span>堆栈<span lang=EN-US>.</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>堆栈区域</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>~~~~~~~~~~</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>堆栈是一块保存数据的连续内存. 一个名为堆栈指针(SP)的寄存器指向堆栈的顶部.</span></pre><pre>堆栈的<span
  class=GramE>底部在</span>一个固定的地址<span lang=EN-US>. 堆栈的大小在运行时由内核动态地调整. CPU实现指令</span></pre><pre><span
  lang=EN-US>PUSH和POP, 向堆栈中添加元素和从中移去元素.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>堆栈由逻辑堆栈<span
  class=GramE>帧</span>组成. 当调用函数时逻辑堆栈<span class=GramE>帧</span>被压入<span
  class=GramE>栈</span>中, 当函数返回时逻辑</span></pre><pre>堆栈<span class=GramE>帧被从栈</span>中弹出<span
  lang=EN-US>. 堆栈<span class=GramE>帧</span>包括函数的参数, 函数地局部变量, 以及恢复前一个堆栈</span></pre><pre><span
  class=GramE>帧所需要</span>的数据<span lang=EN-US>, 其中包括在函数调用时指令指针(IP)的值.<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>堆栈既可以向下增长(向内存低地址)也可以向上增长, 这依赖于具体的实现. 在我</span></pre><pre>们的例子中<span
  lang=EN-US>, 堆栈是向下增长的. 这是很多计算机的实现方式, 包括Intel, Motorola,</span></pre><pre><span
  lang=EN-US>SPARC和MIPS处理器. 堆栈指针(SP)也是依赖于具体实现的. 它可以指向堆栈的最后地址,</span></pre><pre>或者指向堆栈之后的下一个空闲可用地址<span
  lang=EN-US>. 在我们的讨论当中, SP指向堆栈的最后地址.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>除了堆栈指针(SP指向堆栈顶部的<span
  class=GramE>的</span>低地址)之外, 为了使用方便还有<span class=GramE>指向帧内固定</span></span></pre><pre>地址的指针叫做<span
  class=GramE>帧</span>指针<span lang=EN-US>(FP). 有些文章把它叫做局部基指针(LB-local base pointer).</span></pre><pre>从理论上来说<span
  lang=EN-US>, 局部变量可以用SP加偏移量来引用. 然而, 当有字被压<span class=GramE>栈</span>和出<span
  class=GramE>栈</span>后, 这</span></pre><pre>些偏移量就变了<span lang=EN-US>. 尽管在某些情况下编译器能够跟踪<span
  class=GramE>栈</span>中的字操作, 由此可以修正偏移</span></pre><pre>量<span lang=EN-US>, 但是在某些情况下不能. 而且在所有情况下, 要引入可观的管理开销. 而且在有些</span></pre><pre>机器上<span
  lang=EN-US>, 比如Intel处理器, 由SP加偏移<span class=GramE>量访问</span>一个变量需要多条指令才能实现.</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>因此, 许多编译器使用第二个寄存器, FP, 对于局部变量和函数参数都可以引用, </span></pre><pre>因为它们到<span
  lang=EN-US>FP的距离不会受到PUSH和POP操作的影响. 在Intel CPU中, BP(EBP)用于这</span></pre><pre><span
  class=GramE>个</span>目的<span lang=EN-US>. 在Motorola CPU中, 除了A7(堆栈指针SP)之外的任何地址寄存器都可以做FP.</span></pre><pre>考虑到我们堆栈的增长方向<span
  lang=EN-US>, 从FP的位置开始计算, 函数参数的偏移量是正值, 而局部</span></pre><pre>变量的偏移量是负值<span
  lang=EN-US>.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>当一个例程被调用时所必须做的第一件事是保存前一个FP(这样当例程退出时就可以</span></pre><pre>恢复<span
  lang=EN-US>). 然后它把SP复制到FP, 创建新的FP, 把SP向前移动为局部变量保留空间. 这称为</span></pre><pre>例程的序幕<span

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -