微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 51堆栈的安全(精确)设置

51堆栈的安全(精确)设置

时间:11-28 来源:互联网 点击:

负责分配在全局静态变量空间共享覆盖区,其长度为每个独立的后台函数的私有堆栈之和!


“软堆栈”的提法非常赞同。绝不是一般人所能理解到如此深刻的。其它先不多说,——我还没讲到。但是上面红线部分我有异议:就像后台所有非重入函数的参数传递和局部变量被分配在共享覆盖区一样,其长度应该是占用内存字节数最多的那个函数所占有的区域,其它函数分时共享这个区域。——而不是所有之和。这才是共享、覆盖的操作系统内存管理的方法和意义吧?
还有,私有堆栈之和可能忽略了一件事,所有私有堆栈都是动态意义的,当这个函数未被调用时,它是不活动的,所以它的私有堆栈也不存在(长度等于零),这也是覆盖与共享的前提吧?
我表达的不好,感谢老许是真正懂的、真正讨论问题的人。

同意12楼,说的太好了。这里确实不好得出唯一结论;记得ayb_ice详细论证过,堆栈长度开始为什么是1字节。建议去看看他的帖子。我不能确定唯一结论的理由:
1、?STACK是由编译器自动生成的系统堆栈段,——所有含有PUSH / POP指令操作的函数,都在这个系统堆栈段里享有自己的连续堆栈空间(注意是动态的。)?STACK所指向的系统堆栈段被分配在系统所有其它RAM段的最后面。?STACK肯定是始终指向系统堆栈栈底,连接定位之后就不可移动的;

2、“最后面的”后面还能安排有东西么?冷漠认为编译器不可能出尔反尔,所以认为没有了,所以冷漠说栈顶是IDATA的顶。12楼可以说栈顶是移动的,移动上限是IDATA顶端。冷漠坚决同意。
当然通过设置可以让IDATA的顶不等于0xFF;例如等于0xEE什么的。这是冷漠说话不严格。

?STACK的定位是连接器确定的,和编译器无关。LZ已经举了书上的Keil说明书译文, 连接器是否自动把?STACK定位在IDATA顶端?还是需要人工执行STACK连接命令之后才行?冷漠也有疑问?不太清楚。

S
请你仔细看我的原话,没有理解就不要乱引用
我是说KEIL默认的堆栈长度是1字节<,可以改,只要编译器能分配一个字节的空间,就不会报错>,但其实所有没有被编译器使用的IDATA空间都是堆栈,当然中间的间隙不算

对自己在12楼的话解释一下
关于栈顶的理解其实和LZ是一样的,只是说法稍微不同。
堆栈指针SP的范围,最小叫栈底,最大叫栈顶。SP在栈底和栈顶之间活动。所以本例中,栈顶是IDATA顶端0XFF,这么理解没错。

我12楼这么说,我是这么理解的
因为堆栈指针SP的值是栈顶的地址,所以SP活动,那么栈顶也跟着活动的。(SP指向栈顶)
栈顶的范围:最小值即栈底,最大值即 最大栈顶值。

其实和LZ的意思是一样的。

冷漠有另一观点:

C51对用户来说没有SP的概念,你是C51用户你不是编译器作者,要么你说自己只用汇编,那我们讨论不在一个层次,一定注意不要以汇编的概念来理解C编 译器,?STACK 就是编译器生成的堆栈段,而且我认为这个?STACK 以上编译器不可能分配其它数据段。所以从?STACK以上都是堆栈段,即使有很多不用的空间,也不可能被谁占用,编译器没有让谁用。——这不是汇编语言编 程,程序员无法控制SP的。冷漠才不管它SP在哪。愿意在哪在哪,编译器一定比我做的高明。是吧。小问题,无所谓对错。都不影响使用C51。
关键还是主题。

哈哈, 冷漠同学高深莫测,意识流的运用堪比大师. 好吧, 为了清晰起见, 我替冷漠同学总结一下:

1) "假定项目中有3个汇编程序模块A.a51,B.a51,C.a51,它们当然每个模块都有自己的私有堆栈"
"BL51 A.OBJ,B.OBJ,C.OBJSTACK(?DT?A(50H),B(60H),C(70H))
C51下的公有堆栈指针是?STACK ,而每个模块的私有堆栈指针是STACK,一个公有?STACK里包含一个或者多个私有STACK,?STACK指针由编译器确定分配在 idata 内所有段的最后面"

2) "只有PUSH / POP指令才能操作STACK,硬件自动压入的属于不可控的系统控制栈,STACK根本不指向!2字节压入PC根本不影响STACK指针"

3) "C程序中硬件自动压入的PC在私有STACK指向下面就完成了,用户程序根本看不见的。好像称为系统控制栈内容"

4) " 私有堆栈(每个后台函数的私有STACK,和C编译器中的?STACK是两回事)被编译器分配在RAM低端,从全局静态变量区(包括共享覆盖区)后面开始,即初始SP所指向区域,直到?STACK所指向为结束。

?STACK所指向的是前台堆栈,被编译器默认自动分配在所有段(包括所有私有STACK段)的最后面(RAM高端)——栈顶部分!关键的是从这里开始,直到栈顶,才存在溢出危险。——它是一个独立ISR函数(不是多个后台函数)的堆栈"

5)"对于interrupt 属性函数,C51为其分配中断函数私有堆栈……还有硬件堆栈hardwarestack 的概念"

引用结束.
假设:
有A.obj, B.obj, C.obj 三个模块构成的一个8051单片系统, 使用了一个定时中断, 简单起见, 没有使用 reentrant。其中a调用了b中的函数, b调用了c, c调用了a, 期间有中断,而且没有重新设置过sp。

请问冷漠同学:

1) 按照冷漠同学的解释, 此系统有: 中断函数私有堆栈, abc模块私有堆栈, 还有硬件堆栈hardwarestack. 一共 1+3+1 = 5 个栈
2) 如果不是 5个栈, 这个系统总共有多少个栈? 请给出明确的数字。
3)每个栈是如何操作的? 请给出说明。

冷漠修正一些错误:

1) "假定项目中有3个汇编程序模块A.a51,B.a51,C.a51,它们当然每个模块都有自己的私有堆栈"
"BL51 A.OBJ,B.OBJ,C.OBJSTACK(?DT?A(50H),B(60H),C(70H))
C51下的公有堆栈指针是?STACK ,而每个模块的私有堆栈指针是STACK,一个公有?STACK里包含一个或者多个私有STACK,?STACK指针由编译器确定分配在 idata 内所有段的最后面"
——呵呵,这种概念所长还不如老许理解透彻:一会给你抄抄操作系统的书。highgear是精通555时基的,怎 么可能理解这么深刻的机制?所长从裸奔和汇编的概念出发当然不可能理解。不妨跟老许学学:什么叫软堆栈?如若谁再提出个“软中断”,所长该不会大呼小叫 吧。要不要冷漠给你注明哪本书上写的?你不可能比书作者还高明。
2) "只有PUSH / POP指令才能操作STACK,硬件自动压入的属于不可控的系统控制栈,STACK根本不指向!2字节压入PC根本不影响STACK指针"
3) "C程序中硬件自动压入的PC在私有STACK指向下面就完成了,用户程序根本看不见的。好像称为系统控制栈内容"

——呵呵,硬件自动压入堆栈的PC影响的是?STACK,(幸亏冷漠前面没有写问号,也即SP指针。这称为“Hardwarestack”,别混为一谈,装明白人了。要不要冷漠注明摘自那本书?——你不可能比书作者高明 !!

4) " 私有堆栈(每个后台函数的私有STACK,和C编译器中的?STACK是两回事)被编译器分配在RAM低端,从全局静态变量区(包括共享覆盖区)后面开始,即初始SP所指向区域,直到?STACK所指向为结束。

——冷漠的错误,先说对不起了:“即初始SP所指向区 域,”这句话应该是……“从共享覆盖区后面开始,直到?STACK所指向为结束。”这正是老许说的后台软堆栈区,它是人们汇编语言概念上的堆栈么?别以为 一个STACK命令分配区就认为是堆栈了。看书一点联想里都没有。难怪学不会操作系统。要不要我贴张图讲得更清楚一点,文章出处当然就是P640啦,再回 家好好看看这一段。你不可能比书作者还高明。

待续……
TACK所指向的是前台堆栈,被编译器默认自动分配在所有段(包括所有私有STACK段)的最后面(RAM高端)——栈顶部分!关键的是从这里开始,直到栈顶,才存在溢出危险。——它是一个独立ISR函数(不是多个后台函数)的堆栈"

5)"对于interrupt 属性函数,C51为其分配中断函数私有堆栈……还有硬件堆栈hardwarestack 的概念"

引用结束.

哈哈, 冷漠同学概念混乱, 从头到尾含糊其辞。冷漠同学既不敢明确回答有多少个栈, 也不敢***具体详细*** 的解释stack的原作过程。

我先把这里 stack 的具体化一些,以免误解引申:
*) stack 操作是指影响 8051 sp 的操作, 如函数调用, push/pop.
*) sp 的活动区域为 stack 区。
这样, 计算机软件算法的 stack 就不在此例。(呵呵, 在我面前卖弄 软件stack和软中断, 如同卖弄bios 一样可笑)。

我下面会把 ?stack 和 stack, 什么“私有模块栈“ 讲解清楚。 我不会比书作者还高, 但 keil 会。
书作者的问题是没有讲清楚, 而冷漠的问题是不清楚却胡说八道。

我先给出keil 关于 bl51 stack 的说明, 对照 p640, 认真的看看, 就会知道原委.

http://www.keil.com/support/man/docs/bl51/bl51_stack.htm

■Use of the STACK directive to locate the ?STACK segment is typically not required.
■The STACK directive is typically used with assembly programs that have several stack segments.
■Use extreme caution when using the STACK directive. Improper use may result in a target program that crashes or that corrupts DATA and IDATA variables.

keil 从头到尾没有提出 "私有堆栈" (private stack) 的概念, 冷漠同学硬生生造出了很多的“术语“。

在讲解 "私有堆栈" 来龙去脉前, 还是请冷漠明确的说明有多少个涉及硬件栈指针的stack ? 2个, 3个还是 5个?

“模块私有栈“:
这个术语在徐爱钧编著P640里以及 keil 的网站里都没有, 显然是冷漠杜撰的, 如同"递归可重入“

Bl51 stack 命令参数看似可以设定一个”模块私有栈”, 其实这个stack 命令参数的作用是为了汇编模块,而且是需要重新设置 sp 的汇编模块。 C 程序不需要关心 sp, 更不鼓励用户设置 sp. 只有汇编不得不这么做。汇编不得不自己设置 sp,不得不自己控制push/pop.

假设某个第三方的汇编模块里改写 sp (由于特殊的应用),此人为了通用,没有直接设置 sp 为一个固定值,而是提供了一个sp地址的命名名称, 如?ID?MEASURE,以便可以让最终用户在连接时由 linker 为?ID?MEASURE确定地址 。模块结构大致如下:
?ID?MEASURE segment idata
rseg?ID?MEASURE
ds1

mov SP, #?ID?MEASURE

Linker 在连接时,可以自动也可以手工用 stack参数设定?ID?MEASURE的具体位置, 并可以保留若干字节(8086 汇编里经常有这种需求,为了不污染原来的stack). 这种 sp 被更改所产生的数据区域, 徐爱钧的书以及 keil 称为栈段(stack segment), 没有称为 "模块私有栈".

因此, 只要模块中没有设置 sp, 那么就不会有stack segment, 也就是冷漠所说的“模块私有栈".

而 ?stack 仅仅是一个命名名称,作用是在startup 初始化sp,即:
mov sp, #?stack - 1
?stack 的值在连接时确定, 此外,别无特殊意义。当在某个模块里重设sp 后,其后所有的栈活动(call, interrupt, push, pop,ret,reti)都会从新栈点开始。
.
.
.

结论:
a) 如果程序中, 用户没有重新设置 sp, 而且排除另一个概念---计算机软件算法中的栈, 那么
*) 不存在所谓的“模块私有栈“, 不论有多少模块
*)只有一个涉及sp 的栈,没有其他的乱七八糟的栈

b) 如果程序员在程序中多次设置 sp, 这些sp的活动数据区被称为 stack segment, 而不是一个独立的“stack"

如果对上述内容不能理解,请仔细阅读链接中的内容
http://www.keil.com/support/man/docs/bl51/bl51_stack.htm

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top