Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.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
Stack 为什么push堆栈首先从堆栈指针中减去,然后插入数据?_Stack - Fatal编程技术网

Stack 为什么push堆栈首先从堆栈指针中减去,然后插入数据?

Stack 为什么push堆栈首先从堆栈指针中减去,然后插入数据?,stack,Stack,我想知道为什么push指令先减去数据,然后插入数据 在这个实现中,堆栈指针指向最后一个推送的数据。尽管这通常不是一个问题,但我认为,由于在程序开始时堆栈中没有有效数据,因此首先插入然后减少堆栈指针更有意义 为什么会这样: sub $8,%rsp # subtract 8 from rsp mov reg,(%rsp) # store, using rsp as the address 而不是这个: mov reg,(%rsp) # store, using

我想知道为什么push指令先减去数据,然后插入数据

在这个实现中,堆栈指针指向最后一个推送的数据。尽管这通常不是一个问题,但我认为,由于在程序开始时堆栈中没有有效数据,因此首先插入然后减少堆栈指针更有意义

为什么会这样:

sub  $8,%rsp        # subtract 8 from rsp
mov  reg,(%rsp)     # store, using rsp as the address
而不是这个:

mov  reg,(%rsp)     # store, using rsp as the address
sub  $8,%rsp        # subtract 8 from rsp

他们选择这种操作顺序有什么特别的原因吗?

例如,在32位x86体系结构中,您可以将不同的大小值推入堆栈。无法事先知道要推送的大小值,因此指针无法事先移动,在本例中是在存储之后

假设您有以下代码:

PUSH EAX
PUSH BX
PUSH ECX
如果我们先存储,然后减去,我们得到这个值(假设ESP为100,忽略ESP/SP混合使用可能出现的问题):

查看减法如何将上一个大小始终用于下一个大小。这意味着按下BX将首先导致堆栈中有两个未使用的字节,然后按下ECX将实际覆盖堆栈中BX的值。首先执行减法时,它始终使用推送到堆栈的当前值的大小:

SUB %ESP, 4 // ESP = 96
MOV EAX, (%ESP) // EAX -> 96..99
SUB %SP, 2. // ESP = 94
MOV BX, (%SP) // BX -> 94..95
SUB %RSP, 4 // ESP = 90
MOV ECX, (%RSP) // ECX -> 90..93
现在什么都没有被覆盖,没有差距发生,每个人都很高兴

当然,这是假设堆栈像通常一样向下增长。如果堆栈向上,那么加法将在存储之后进行,以保持地址正确

在x64模式下,它会更简单,因为(据我所知)值总是作为8字节块推送


另外,其他体系结构可能允许不同类型的推送,因此在存储数据之前,在推送上移动指针将导致最通用的操作。

例如,在32位x86体系结构中,您可以将不同的大小值推送到堆栈中。无法事先知道要推送的大小值,因此指针无法事先移动,在本例中是在存储之后

假设您有以下代码:

PUSH EAX
PUSH BX
PUSH ECX
如果我们先存储,然后减去,我们得到这个值(假设ESP为100,忽略ESP/SP混合使用可能出现的问题):

查看减法如何将上一个大小始终用于下一个大小。这意味着按下BX将首先导致堆栈中有两个未使用的字节,然后按下ECX将实际覆盖堆栈中BX的值。首先执行减法时,它始终使用推送到堆栈的当前值的大小:

SUB %ESP, 4 // ESP = 96
MOV EAX, (%ESP) // EAX -> 96..99
SUB %SP, 2. // ESP = 94
MOV BX, (%SP) // BX -> 94..95
SUB %RSP, 4 // ESP = 90
MOV ECX, (%RSP) // ECX -> 90..93
现在什么都没有被覆盖,没有差距发生,每个人都很高兴

当然,这是假设堆栈像通常一样向下增长。如果堆栈向上,那么加法将在存储之后进行,以保持地址正确

在x64模式下,它会更简单,因为(据我所知)值总是作为8字节块推送


另外,其他体系结构可能允许不同类型的推送,因此在存储数据之前,在推送上移动指针是最通用的操作。

@AntonisParagas否,在32位模式下,它只能推送2或4字节的值。我不明白32位x86如何会遇到第二种方法的问题。推16位时,推的操作码不同于推32位时的操作码(立即)。所以CPU确实知道大小。@AntonisParagas,但是减法是基于之前的值进行的。我将添加一个解释。@AntonisParagas添加了解释。@AntonisParagas感谢您的解释,我弄乱了堆栈寻址。@AntonisParagas否,在32位模式下,它只能推送2或4字节的值。我不明白32位x86在第二种方法中会有什么问题。推16位时,推的操作码不同于推32位时的操作码(立即)。所以CPU确实知道大小。@AntonisParagas,但是减法是基于之前的值进行的。我将添加一个解释。@AntonisParagas添加了解释谢谢您的解释,我把堆栈地址弄乱了。