【问题标题】:Assembly - How to modify stack size?装配 - 如何修改堆栈大小?
【发布时间】:2016-04-05 07:34:49
【问题描述】:

我是汇编编程的新手,我正在使用使用内存堆栈的推送和弹出指令。 那么,堆栈默认大小是多少,如何修改它以及它的大小限制是多少?

【问题讨论】:

  • 堆栈大小通常取决于您使用的操作系统、CPU、环境和构建工具 - 指定这些有助于人们回答您的问题。
  • @PaulR 操作系统:Windows CPU:CORE i5
  • @AhmadNaoum:你的意思是“x86”CPU。
  • 如果您遇到问题(不太可能在具有典型工作负载和编译器尾递归优化的现代操作系统上),您可以根据需要分配尽可能多的 RAM,并将其用作堆栈。跨度>

标签: windows assembly x86


【解决方案1】:

堆栈大小取决于很多因素。 这取决于你从哪里开始堆栈,你有多少内存,你正在使用什么 CPU 等等。 您使用的 CPU 不称为“Windows CPU”。 如果您要指定使用的 CPU,请详细指定该 CPU 的名称,以及非常重要的 CPU 架构。在这种情况下,您可能使用的是 x86 架构。

这是 x86 架构的内存映射:


All addresses Before 0X100000 - Free
0x100000 - 0xc0000 - BIOS
0xc0000 - 0xa0000 - Video Memory
0xa0000 - 0x9fc00 - Extended BIOS data area
0x9fC00 - 0x7e00 - Free
0x7e00 - 0x7c00 - Boot loader
0x7c00 - 0x500 - Free
0x500 - 0x400 - BIOS data area
0x400 - 0x00 - Interupt vector table

在 x86 中,堆栈信息由两个寄存器保存:


    Base pointer (bp): Holds starting address of the stack
    Stack pointer (sp): Holds the address in which next value will be stored

这些寄存器在不同的模式下有不同的名称:


                            `Base pointer           Stack pointer`
    16 bit real mode:       bp                     sp
    32 bit protected mode:  ebp                    esp
    64 bit mode:            rbp                    rsp

当你建立一个堆栈时,堆栈指针和基指针获得相同的地址。

堆栈设置在基指针寄存器中指定的地址。
您可以在内存中空闲且堆栈向下增长的任何位置设置堆栈。

每次你“push”一些东西到堆栈上时,值都存储在堆栈指针指定的地址(与开头的基指针相同),堆栈指针寄存器递减。

每次从堆栈中“弹出”某些内容时,堆栈指针寄存器指定的地址中存储的值将存储在程序员指定的寄存器中,并且堆栈指针寄存器递增。

在 16 位实模式下,您“推送”和“弹出”16 位。所以每次你“push”或“pop”时,堆栈指针寄存器都会递减或递增0x02,因为每个地址都保存8位..

在 32 位保护模式下,您“推送”和“弹出”32 位。所以每次“push”或“pop”时,堆栈指针寄存器都会递减或递增 0x04,因为每个地址都包含 8 位。

您必须根据要“推送”多少个值在正确的位置设置堆栈。

如果您继续“推动”您的堆栈不断向下增长,并且在某个时间点您的堆栈可能会覆盖某些内容。因此,明智的做法是将堆栈设置在内存中的一个地址中,该地址有足够的空间让堆栈向下增长。

例如:
如果您将堆栈设置在 0x7c00,就在引导加载程序下方并且您“推送”了太多值,您的堆栈可能会在某个时间点覆盖 BIOS 数据区域,这会导致很多错误。

您现在应该对堆栈及其大小有了一个基本的了解。

【讨论】:

    【解决方案2】:

    无论加载(“加载器”)您的程序到内存中,并将控制权传递给它,都会确定堆栈在内存中的位置,以及堆栈有多少可用空间。 p>

    它通过加载堆栈指针的简单技巧来实现,通常在调用/跳转到您的代码之前使用 MOV ESP, ... 指令。然后您的程序使用提供的堆栈区域。

    如果您的程序使用过多,它将写入超出分配的堆栈区域的末尾。这是一个程序错误,因为结束后的内存可能被分配用于应用程序中的其他目的。当该内存被使用时,在该其他内存上写入可能会改变程序行为(例如,“错误”),并且找到该错误的原因可能很困难(人们假设堆栈不会损坏程序数据,反之亦然反之亦然)。

    如果您的应用程序想要使用更大的堆栈,通常您所要做的就是分配自己的区域,足够大以满足您的目的,然后执行 MOV ESP,...您自己将堆栈设置到所选位置。如何分配区域取决于您运行的执行环境。 (你需要遵守 ESP 约定:必须是 4 的倍数,应该初始化到缓存行的底部,通常用于初始化到虚拟内存页面的底部)。

    “切换”堆栈以保存加载器提供的 ESP 的旧值并在将控制权返回给加载器/调用者/OS 之前将 ESP 恢复到该旧值通常是一个好主意。同样,您应该释放不再使用的扩展堆栈空间。

    如果您事先知道所需的堆栈空间量,此方案将起作用。在实践中,这很难“猜测”(如果您的代码具有深度嵌套的递归算法,这可能是不可能的)。所以你可以选择一个比你需要的更大的数字(ick),或者当程序清楚它需要更多时,你可以使用有组织的方法来切换堆栈。 有关更多讨论,请参阅How does a stackless language work?

    【讨论】:

      猜你喜欢
      • 2018-06-29
      • 2018-09-13
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      • 2017-09-22
      相关资源
      最近更新 更多