Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Memory management 在哪里可以找到有关x86处理器中堆栈操作的详细信息_Memory Management_Assembly_X86 - Fatal编程技术网

Memory management 在哪里可以找到有关x86处理器中堆栈操作的详细信息

Memory management 在哪里可以找到有关x86处理器中堆栈操作的详细信息,memory-management,assembly,x86,Memory Management,Assembly,X86,我感兴趣的是使用堆栈的可执行和动态内存分配的布局,以及处理器和内核如何一起管理堆栈区域,比如在函数调用期间和使用基于堆栈的内存分配的其他场景中。另外,堆栈溢出和与此模型相关的其他危险是如何发生的,它们的其他代码执行设计不是基于堆栈的,也没有此类问题。视频或动画会很有帮助。通常(任何处理器,而不仅仅是x86)都有一个ram地址空间,通常程序在较低的内存中,并随着运行而向上增长。假设您的程序是0x1000字节,在0x0000处加载,然后执行0x3000字节的malloc。在这种假设情况下,返回的地址

我感兴趣的是使用堆栈的可执行和动态内存分配的布局,以及处理器和内核如何一起管理堆栈区域,比如在函数调用期间和使用基于堆栈的内存分配的其他场景中。另外,堆栈溢出和与此模型相关的其他危险是如何发生的,它们的其他代码执行设计不是基于堆栈的,也没有此类问题。视频或动画会很有帮助。

通常(任何处理器,而不仅仅是x86)都有一个ram地址空间,通常程序在较低的内存中,并随着运行而向上增长。假设您的程序是0x1000字节,在0x0000处加载,然后执行0x3000字节的malloc。在这种假设情况下,返回的地址将是0x1000,现在较低的0x4000字节正被程序积极使用。更多的Malloc继续以这种方式增长。Free()并不一定会导致消耗量下降,这取决于内存的管理方式以及malloc()和Free()的混合程序

但是堆栈通常是从上到下的。假设0x10000是堆栈指针的起始地址。假设有一个函数有三个32位无符号int变量,并且没有传入任何参数,则需要三个堆栈位置来保存这些变量(假设没有优化减少该要求),因此在函数输入时,堆栈指针减少3*4=12字节,因此堆栈指针更改为0xFFF4,其中一个变量位于地址0xFFF4+0,一个位于0xFFF4+4,第三个位于0xFFF4+8。如果该函数调用另一个函数,则堆栈指针在内存中继续向零移动。当您继续使用malloc()时,您使用的程序内存会向上增长。如果不进行检查,它们将发生冲突,并且进行检查所需的代码成本过高,因此很少使用。这就是为什么局部变量对于优化和其他一些事情是好的,但是不好,因为堆栈消耗通常是不确定的,或者至少分析不是由普通程序员完成的

在诸如x86之类的ISA(指令集体系结构)上,如果可用寄存器数量有限,那么函数通常也需要在堆栈上传递参数。控制在何处以及如何传递和返回内容的规则是由编译器定义和理解的,这不是随机的。无论如何,除了为局部变量留出空间外,函数的一些参数在堆栈上,有时返回值在堆栈上。特别是对于x86,每次函数调用都会导致堆栈向下增长,而函数调用函数则会使情况变得更糟。想想递归可以对堆栈做什么

你有什么选择?使用具有更多寄存器的指令集,并使用使用更多寄存器和更少堆栈的函数调用规范。调用函数时使用较少的参数。使用更少的局部变量。马洛克较少。使用一个好的编译器和一个好的优化器,并在编码时使用易于优化的习惯来帮助优化器

但实际上,要有一个通用的处理器来编写通用的程序,就必须有一个堆栈以及堆栈溢出和/或与堆冲突的可能性

现在,x86的分段内存模型以及MMU通常为您提供了保持程序内存和堆栈彼此远离的机会。还可以使用保护机制,如果堆或堆栈超出其分配的空间,则会发生保护故障。这仍然是程序员的疏忽,但是比起堆栈向下扩展到程序内存空间时出现的随机副作用,更容易知道发生了什么并进行调试。使用这样的保护机制来帮助程序员控制堆栈增长要比在编译器生成的代码中构建一些东西来检查每个函数调用和malloc上的冲突容易得多

求职面试中经常被问到的另一个陷阱是:

int * myfun ( int a ) { int i; i=a+7; return(&i); } int*myfun(int a) { int i; i=a+7; 返回(&i); } 这可能有多种形式,需要理解的是,变量i临时分配在堆栈上,并且仅在函数执行时分配,当函数返回堆栈指针时,释放分配给i的内存,下一个调用的函数可能会很好地破坏该内存。因此,将地址返回到存储在堆栈上的变量是个坏主意。执行类似操作的代码在被检测到之前可能会正常运行数周、数月或数年

现在,即使在基于堆栈的CPU上(例如zylin zpu),这也是可以接受的

int myfun(int a) { int i; i=a+7; 回报(i); } 部分原因是除了使用globals(是的,这个特定的例子不需要额外的变量i,但是假设您的代码足够复杂,您需要这个局部返回变量),第二个原因是在C中,调用代码释放了它在堆栈中的部分。这意味着在x86上,例如,如果调用堆栈上有两个参数的函数,比方说两个4字节整数,则调用代码将堆栈指针向下移动8,并将这两个参数放置在该内存中(sp+0和sp+4),然后,当函数返回时,调用代码是通过向堆栈指针添加8来取消分配这两个变量的代码。因此,在上面使用i并按值返回i的代码中,处理器的C调用约定知道从何处获取返回值,一旦捕获该值,就不再需要保存该值的堆栈内存。我的理解是,帕斯卡,比如说伯兰涡轮帕斯卡,卡莱清理了堆栈。因此,调用者将把这两个变量放在堆栈上,函数是ca int myfun ( int a ) { int i; i=a+7; return(i); }