首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么首先推送减少堆栈指针?

为什么首先推送减少堆栈指针?
EN

Stack Overflow用户
提问于 2019-07-14 21:48:55
回答 2查看 7.2K关注 0票数 3

当某个东西被推拉出来时,我试图理解堆栈是如何工作的,抱歉,如果这个问题听起来很简单的话。

我想从一些超级基本的东西开始,比如8位内存(我知道这会过于简化,但让我们从简单开始吧)

我设计堆栈的方式如下:

SP将首先指向内存中的最高位置: 0xFF。

代码语言:javascript
运行
复制
0xFF:   <- SP

当发出推送命令时,我会将val保存在SP指出的位置,然后减少SP。

代码语言:javascript
运行
复制
0xFE:         <- SP
0xFF:  val

pop命令将首先增加SP,然后将SP所指向的值移到寄存器中。

基本上,我的SP指向堆栈中的第一个可用位置。

然而,这似乎不是它在实际系统中的实现方式。

查看组装手册中的推送指令:

代码语言:javascript
运行
复制
Decrements the stack pointer and then stores the source operand on the top of the stack.

因此,基本上SP指向最新的存储值。

我的问题是:首先减少堆栈指针,难道堆栈的顶部就不能使用了吗?如果我们在保存数据之前先减少指针,那么如何将数据存储到堆栈的第一个位置?

是否有理由这样设计堆栈指针?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-14 23:45:16

减少堆栈指针,然后将源操作数存储在堆栈顶部。

有一些设计方面的考虑(但请放心,我同意这是相对武断的,因为这两种方法都可以发挥作用):

首先,让我们以您的例子为例,看看如果从一开始就将一个2字节的单词推到堆栈上会发生什么。

代码语言:javascript
运行
复制
        0xFF:   <- SP

push.w val2

        0xFD:         <- SP
        0xFE:  val2(hi 8-bits)   # order depends on big/little endian
        0xFF:  val2(lo 8-bits)

值的8位指向SP所指向的位置(第一个可用字节),而其他8位必须位于该地址以下(因为它们不能高于该地址,嗯?). 堆栈指针被保留为一个空闲字节,所以在SP + 1处刚刚推送的值是可访问的。

虽然这是可行的,但另一种选择似乎更合理:

刚才推送的项目位于SP + 0位置。

请记住,加载比存储更常见,所以加载堆栈顶部项的频率可能比存储高。在支持无位移加载的体系结构中,在SP +0访问堆栈顶部时更倾向于加载。(它还支持声称的空间而不是无人声称的空间。)

如果我们想到SP +?作为索赔和无人认领之间的分界,在索赔空间中加入0似乎更实际、更自然。这是因为(在计算机中,与数学不同),零更像是正数之一,而不是一个负数--例如,考虑无符号数,它总是支持零(以及正值)。

我们还需要注意的是,由于微体系结构的原因,内存读取比内存写入慢(读取通常在临界路径上,这限制了最大可能的时钟频率,而写入不是). ,因此,增量后pop (负载)比增量前pop更好,因为增量后的pop可以在并行硬件(数据内存访问)中进行加法,而增量前pop在地址总线和数据存储器读取操作中放置加法器。(当然,为了支持增量后pop,我们需要预减量推送。)

票数 6
EN

Stack Overflow用户

发布于 2019-07-15 07:44:11

为什么首先推送减少堆栈指针?

首先,这取决于CPU类型,堆栈指针是如何工作的。

在6800上,首先写入值,然后减少堆栈指针。

在TMS320F28上,写入值,然后增加堆栈指针。

..。堆栈的顶部不是不能用吗?

请忘记“不可用”这个词。正确的词应该是“使用中”。

请考虑下面的C或Java程序:

代码语言:javascript
运行
复制
int a, b;
a = someFunction();
someOtherFunction();
thirdFunction(a);

您希望将someOtherFunction()的返回值存储在一个变量中,如下所示:

代码语言:javascript
运行
复制
int a, b;
a = someFunction();
a = someOtherFunction();
thirdFunction(a);

这不是一个好主意,因为变量a已经“在使用”了。然而,变量b仍然是“可用的”。

但是,这并不妨碍您覆盖变量a

现在让我们回到堆栈指针,看看局部变量。查看局部变量(而不是push),我们可以更清楚地看到堆栈指针实际上做了什么:

当输入这样的函数时:

代码语言:javascript
运行
复制
void someFunction(void)
{
    int x, y, z;
    ...
    y = 5;
}

..。生成的汇编程序代码首先将堆栈指针减少3(假设一个int需要一个内存位置)。

假设堆栈指针在输入函数之前具有0x73值。这意味着内存位置0.72“不在使用”,而内存位置73...FF“在使用”。

汇编程序代码将堆栈指针的值更改为0x70,并将变量x存储在地址0x70,y存储在地址0x71,z存储在0x72。

堆栈指针的值为0x70,这意味着内存位置70...FF现在“在使用”。

应该清楚的是,内存位置70.72“正在使用”,因为变量xyz都存储在那里。

但是,这并不意味着无法访问(读或写)这些内存位置:指令y=5;将写入内存位置0x71。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57031401

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档