搜索
bottom↓
回复: 117

问个只要用Cortex-M单片机都会遇到的问题,关于堆栈的!!

  [复制链接]

出0入25汤圆

发表于 2012-4-10 19:36:05 | 显示全部楼层 |阅读模式
下面一段话是看本论坛上的一位大侠说的:
MSP的位置 = 全局变量数+HEAP_SIZE+Stack_Size。
KEIL编译器对RAM的排列方式(地址由低到高):
    1、全局变量(包括已初始化的变量和没初始化的变量);
    2、Heap所占的空间;
    3、主Stack所占空间;

首先,我认为这段话肯定是对的,应该没有问题,,,

可是,我不明白的是:编译器根据下面两段代码,就能知道我定义的存储区是堆栈吗???
Stack_Size      EQU     0x0200;

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp   


Heap_Size       EQU     0x000;

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit


SPACE伪指令是汇编语言中用于定义内存空间的,可是,编译器怎么知道我定义的Stack_Mem存储区是栈空间呢???难道是根据这个存储区的名字叫:Stack_Mem来判断的吗???

出0入25汤圆

 楼主| 发表于 2012-4-10 19:55:56 | 显示全部楼层
本帖最后由 XIVN1987 于 2012-4-10 19:57 编辑

发完帖子就发现,自己问了一个愚蠢的问题:

AREA    STACK, NOINIT, READWRITE, ALIGN=3

AREA    HEAP, NOINIT, READWRITE, ALIGN=3

出0入0汤圆

发表于 2012-4-11 10:18:26 | 显示全部楼层
这个问题一点也不愚蠢啊,反倒是红色的两个名字会愚弄人呢!是时候揭开它们的假面具了。
STACK, HEAP只是两个section的名字。程序就是由各种代码和数据section组成的,最后由链接器排开并生成一个映像文件。这两个名字没有特殊的法力,很有欺骗性啊。不信的话,你把它改成你和你女朋友的名字也可以的!
不是因为名字叫"STACK", "HEAP"就人如其名了。事实上,关键的一句是
__initial_sp (顶格写的,而且必须顶格写)
这个标号,它最终会被链接器解析成这个名为STACK的section结束后的地址。往下看向量表的定义,第一条就是
__Vectors                DCD                __initial_sp
这才是确定了MSP的初始值为__initial_sp

堆也是一样,"HEAP"这个名字并不能赋予这个区神奇的力量,而是看前呼后拥的"__heap_base"和"__heap_limit",它们这两个标号最后变成两个地址,可想而知,就是堆的起止范围!
在启动文件的最后有一个汇编例程,用于和C语言库对接,才初始化了HEAP。

说句题外话,在MDK中的确有些名字是可以有特殊功能的,比如
AREA    |.ARM.__at_0x02FC|, CODE, READONLY
这里的"|.ARM.__at_0x02FC|"也是个名字,不过它指定了地址。这是MDK的特有功能。不过,往往成事不足败事有余,建议还是不要招惹它。

出0入0汤圆

发表于 2012-4-11 10:49:38 | 显示全部楼层
http://infocenter.arm.com/help/i ... 0475c/CHDJHFGB.html

Defining __initial_sp, __heap_base and __heap_limit
One of several methods you can use to specify the initial stack pointer and heap bounds is to define the following symbols:
__initial_sp
__heap_base
__heap_limit.
You can define these symbols in an assembly language file, or by using the embedded assembler in C.
For example:
__asm void dummy_function(void)
{
    EXPORT __initial_sp
    EXPORT __heap_base
    EXPORT __heap_limit

__initial_sp EQU STACK_BASE
__heap_base EQU HEAP_BASE
__heap_limit EQU (HEAP_BASE + HEAP_SIZE)
}
The constants STACK_BASE, HEAP_BASE and HEAP_SIZE can be defined in a header file, for example stack.h, as follows:
/* stack.h */
#define HEAP_BASE 0x20100000  /* Example memory addresses */
#define STACK_BASE 0x20200000
#define HEAP_SIZE ((STACK_BASE-HEAP_BASE)/2)
#define STACK_SIZE ((STACK_BASE-HEAP_BASE)/2)
Note
This method of specifying the initial stack pointer and heap bounds is supported by both the standard C library (standardlib) and the micro C library (microlib).


http://infocenter.arm.com/help/i ... 0475c/CJAGBBEG.html


Stack pointer initialization and heap bounds
The C library requires you to specify where the stack pointer begins. If you intend to use ARM library functions that use the heap, for example, malloc(), calloc(), or if you define argc and argv command-line arguments for main(), the C library also requires you to specify which region of memory the heap is intially expected to use.
The region of memory used by the heap can be extended at a later stage of program execution, if required.
You can specify where the stack pointer begins, and which region of memory the heap is intially expected to use, with any of the following methods:
Define the symbol __intial_sp to point to the top of the stack. If using the heap, also define symbols __heap_base and __heap_limit.


出0入25汤圆

 楼主| 发表于 2012-4-11 14:05:18 | 显示全部楼层
bluelucky 发表于 2012-4-11 10:18
这个问题一点也不愚蠢啊,反倒是红色的两个名字会愚弄人呢!是时候揭开它们的假面具了。
STACK, HEAP只是两 ...


首先,非常感想您的回复,您说的都是对的,我验证过,把section的名字从STACK改为其他的字符串,堆栈的分配照样进行,并且是正确的。。也就是,如您所说:STACK只是一个很简单的section name,没有什么特殊的含义或是神奇的力量,HEAP也一样。。。


但是,我想说的是:您回答的问题,并不是我问的问题,,,
我问的问题是,我在startup.s文件中写下了如下代码:
Stack_Size      EQU     0x0200;

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

很显然,编译器知道我要定义一个512字节的Section,此Section的名字叫STACK,并且应该把这个Section放到RAM里面去。。。

可是,链接器并不知道我定义的这个Section是用来当堆栈用的啊,至少我没告诉连接器或是编译器,这个Section是用来当堆栈使用的;或者说:我不知道我是怎么告诉链接器的。。。

既然连接器不知道这个Section是用来当堆栈使用的。。那么,连接器怎么知道一定要把这个Section放到所有全局变量的后面去呢???连接器完全可以把这个Section随便放一个地方啊,比如,从0x20000000处分配一块512字节的RAM内存给名字叫做STACK的Section。。。可是,我们知道,连接器没有这么做,它总是把这个Section放到所有的全局变量后面去,显然,这是因为连接器知道上面的代码定义的那个Section是用来当栈使用的,,

可是,我是怎么在代码里面告诉连接器,名字叫STACK的Section是要用来当堆栈的呢???

仔细看看上面那一堆的代码,既然STACK只是一个名字,一个很普通的名字,那么好像有点特殊的就只剩下“__initial_sp”了,
再看下面的一段代码:
                EXPORT  __initial_sp
                EXPORT  __heap_base
                EXPORT  __heap_limit

“__initial_sp”竟然需要EXPORT,也就是说:编译器或者库函数可以使用这个“字符串”,看来这个东西确实比较特殊。。。。
我在Keil的Help里面查找了一下__initial_sp,果然查到了不少东西,可是我现在看不太懂帮助里面说的都是些什么,我还在努力的看,,,感觉应该就是__initial_sp 使得连接器知道,前面定义的那个RAM中的Section是用来当作堆栈用的,,,

当然,我还没看太懂——英语比较差,,我再看看,看懂了我再发上来,,,

出0入25汤圆

 楼主| 发表于 2012-4-11 14:17:06 | 显示全部楼层
shangdawei 发表于 2012-4-11 10:49
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0475c/CHDJHFGB.html

Defining __initi ...


One of several methods you can use to specify the initial stack pointer and heap bounds is to define the following symbols:
__initial_sp
__heap_base
__heap_limit.



The C library requires you to specify where the stack pointer begins.


仔细研读这几句话,我认为,他们的意思是说:我们需要定义几个符号来把堆栈的地址和边界告诉库函数!!!


所以,您这段话依然不是回答我问题的答案。。。

我具体问的问题是什么,您可以看一下6楼的帖子。。。。


简单来说:连接器是怎么知道要把名字叫做STACK的Section放到所有全局变量的后面去的,难道连接器知道这个Section是要当作栈存储区来使用的???
那链接器又是怎么知道的呢???

出0入0汤圆

发表于 2012-4-11 14:27:46 | 显示全部楼层
内存布局在Linker的Scatter文件中指定。

出0入25汤圆

 楼主| 发表于 2012-4-11 14:41:59 | 显示全部楼层
dr2001 发表于 2012-4-11 14:27
内存布局在Linker的Scatter文件中指定。

下面是MDK下的一个完整的Scatter文件的内容:
LR_IROM1 0x00000000 0x00004000  {    ; load region size_region
  ER_IROM1 0x00000000 0x00004000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00000800  {  ; RW data
   .ANY (+RW +ZI)
  }
}


很显然,这里面并没有特别指明堆、栈的相关的任何信息。。。

出0入0汤圆

发表于 2012-4-11 14:51:48 | 显示全部楼层
不知是谁强加给了你这样的概念,好像链接器与C语言要有某种默契似的。事实上,链接器并不关心哪段地址要做栈,也并没有什么告诉链接器”我是栈,我要特殊照顾“的代码。或者你也可以理解为链接器不知道栈是何许人也。链接器只是要把各个输入sections定位并产生映像文件,栈和堆都是普通的sections,在链接器看来一视同仁,与汇编代码中定义的其它AREAs,以及C语言中的全局变量,静态全局变量,静态局部变量都是平起平坐。
栈空间不一定要放在全局变量后头,就算碰巧被链接器放在后面也是巧合,也可能因为它在.s文件中定义,刚好.s文件被最后处理。不信的话,你可以仿照栈区的定义方式再定义个"Stack2"什么的,靠在栈区的后面定义,然后只要在程序中引用它以避免它被当作死代码而被链接器删除,你可以在生成的.map文件中看到它的位置是在STACK后面。
全局变量是C语言中的术语,除此之外,还有静态全局变量,静态局部变量,与在链接器看来全局变量有相同的身份
不知“MSP的位置 = 全局变量数+HEAP_SIZE+Stack_Size”这句话是在什么上下文里说出来的,不能断章取义地了解,有可能它刚好在解释一个程序中安排栈区的方式而已。

出0入0汤圆

发表于 2012-4-11 14:56:33 | 显示全部楼层
补充一句,你也可以把栈空间理解成一个全局数组变量,如果按C语言的说法的话,你完全可以在C语言中以
"extern unsigned int Stack_Mem[];"
的方式定义并直接操作栈区,就如同它只是在C中定义的全局数组变量一般。
当然,这只是为了说明问题,千万不要随意写它,否则可能破坏栈中的内容,造成不可预知的错误!

出0入25汤圆

 楼主| 发表于 2012-4-11 15:32:03 | 显示全部楼层
本帖最后由 XIVN1987 于 2012-4-11 15:33 编辑
bluelucky 发表于 2012-4-11 14:51
不知是谁强加给了你这样的概念,好像链接器与C语言要有某种默契似的。事实上,链接器并不关心哪段地址要做 ...


"栈和堆都是普通的sections,在链接器看来一视同仁,与汇编代码中定义的其它AREAs,以及C语言中的全局变量,静态全局变量,静态局部变量都是平起平坐。栈空间不一定要放在全局变量后头,就算碰巧被链接器放在后面也是巧合"

您这个观点我实在不敢同意。我记得我看过一篇文章,这篇文章的大致意思是:
在ARM中:堆是向上增长的,而栈是向下增长的,之所以把栈放在内存的最后面,把堆放在内存的倒数第二位置。那是有科学依据的:
比如:在栈向下增长溢出的时候,如果程序里面恰好堆分配的使用的空间比较少而没有增长到堆的最顶端(这种情况应该是非常非常常见的,因为谁都不会把堆分配的正好够程序用,肯定都是有盈余的),那么,栈多占用的RAM空间也不会覆盖到全局变量或者堆中的内容,从而,即使溢出也不会使得程序崩溃,从而增加程序的健壮性。。。


而像您说的:堆栈就当作普通的Secton进行处理,可以放在RAM里面的任何位置,这个观点我还是第一次见到。。。我感觉,您这个观点十有八九是错的,当然,我也不是特别懂,希望高人指点一下。。。。

出0入0汤圆

发表于 2012-4-11 15:45:18 | 显示全部楼层
以前有些AVR和8/16位机的编译器的确是这样做的,它们有固定的内存划分策略。不过MDK中不这样。比如,你可以看它在构建成功时统计的内存使用量,这是把栈空间算在里面的。未用到的内存不会用于当栈溢出时的备用。栈指针的起始地址也不是内存末尾,更何况有些单片机还有一止一块内存,彼此地址并不连续。
如果确实难以置信,只要再在栈区定义的后面定义个类似的AREA,并且在生成的map文件中查看就可以验证了。
另外,如果是有操作系统的,每个任务都有自己的栈,更谈不上把栈放在最后,以便溢出时还有得救这种想法了。

出0入0汤圆

发表于 2012-4-11 15:45:23 | 显示全部楼层
个人理解, 栈/堆可以在任意位置, 重要的是预设的大小.
最好是先变量, 接着堆, 最后栈, 如

KEIL编译器对RAM的排列方式(地址由低到高):
    1、全局变量(包括已初始化的变量和没初始化的变量);
    2、Heap所占的空间;
    3、主Stack所占空间;

出0入25汤圆

 楼主| 发表于 2012-4-11 15:53:34 | 显示全部楼层
bluelucky 发表于 2012-4-11 15:45
以前有些AVR和8/16位机的编译器的确是这样做的,它们有固定的内存划分策略。不过MDK中不这样。比如,你可以 ...

关于栈会不会被MDK特意放到所有全局变量的后面去,我认为可以另开一帖请教一下高人,看他们怎么说。。。。

我马上另发一帖,搞清楚这个问题。。。

如果这个问题不搞清楚,那么我这个帖子问的问题也就没有意义了。。。

出0入0汤圆

发表于 2012-4-11 15:59:22 | 显示全部楼层
XIVN1987 发表于 2012-4-11 14:41
下面是MDK下的一个完整的Scatter文件的内容:
LR_IROM1 0x00000000 0x00004000  {    ; load region size ...

没有指明的话,那么就是按照某种链接器默认的顺序进行排列。比如.o文件的名称,比如出现在linker参数列表中的顺序,etc。
Linker不会对Section的名字进行任何特殊处理。

出0入0汤圆

发表于 2012-4-11 16:01:55 | 显示全部楼层
For 12L,
bluelucky说的内容是正确的,至少在arm-none-eabi-gcc和MDK/RVCT上都是这样的。
如果你用其它的编译系统,那么有可能有区别。

出0入25汤圆

 楼主| 发表于 2012-4-11 16:04:50 | 显示全部楼层
dr2001 发表于 2012-4-11 16:01
For 12L,
bluelucky说的内容是正确的,至少在arm-none-eabi-gcc和MDK/RVCT上都是这样的。
如果你用其它的 ...


请问,您是在哪一个资料上看到的这方面的知识,可以推荐一下吗??我也想看看,学习一下。。

出0入0汤圆

发表于 2012-4-11 16:06:27 | 显示全部楼层
详情参考MDK所带的RVCT的链接器手册。
如果有任何特殊的地方,手册中都会写。

出0入25汤圆

 楼主| 发表于 2012-4-11 16:09:18 | 显示全部楼层
dr2001 发表于 2012-4-11 16:06
详情参考MDK所带的RVCT的链接器手册。
如果有任何特殊的地方,手册中都会写。 ...

谢谢,那我仔细看一看。。。

出0入0汤圆

发表于 2012-4-11 16:14:33 | 显示全部楼层
我做了实验,发现我用的MDK版本,连接器是按名字的字母顺序排序的!
比如,如果依照Stack的定义方式再定义一个名为"RSec"的AREA(汇编中的AREA到了连接器中就是section),它会被放在Stack的前面。如果名字是"TSec",它就会被放在Stack的后面。
注意,为了防止连接器把新定义的AREA当作无用区删掉,可以在向量表中找一个没有用到的向量,把新定义的section里面的名字填到一个向量中。
例如,
                AREA    TSec, NOINIT, READWRITE, ALIGN=3
TSec_Mem      SPACE   128
然后找一个保留的向量,改为
                DCD     TSec_Mem
构建它,然后查看map文件,可以发现类似
    STACK                                    0x10003510   Section     2816  startup_lpc177x_8x.o(STACK)
    TSec                                     0x10004010   Section      128  startup_lpc177x_8x.o(TSec)
    TSec_Mem                                 0x10004010   Data         128  startup_lpc177x_8x.o(TSec)
    __initial_sp                             0x10004010   Data           0  startup_lpc177x_8x.o(STACK)
的文字。在这里,显然栈是放在了TSec的前面

说句题外话,你甚至可以在连接器控制文件(.sct文件)中按自己的意志指定每个section的位置

出0入0汤圆

发表于 2012-4-11 16:16:53 | 显示全部楼层
dr2001理解的比我深刻,我只在RVCT上知道是这样的,dr2001告诉我们GCC也是这样处理的。我估计IAR也是这样,链接器并不会给不同的高级语言和特定的二进制接口开小灶

出0入0汤圆

发表于 2012-4-11 16:28:35 | 显示全部楼层
学习,楼上高手好多,呵呵。

出0入25汤圆

 楼主| 发表于 2012-4-11 16:31:14 | 显示全部楼层
bluelucky 发表于 2012-4-11 16:14
我做了实验,发现我用的MDK版本,连接器是按名字的字母顺序排序的!
比如,如果依照Stack的定义方式再定义 ...

多谢大侠的耐心指教,我试了一下,果然如大侠所说,我把HEAP的section name改成了THEAP,结果堆被放在了栈的后面去了,,,

看来,链接器真的不会对堆栈Section特殊照顾。。。

实验截图如下:






感谢大侠,这个帖子的问题解决了,,,谢谢大侠!!!解开了我心中很久的疑惑。。。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-4-11 16:43:03 | 显示全部楼层
强力
虽然我这个小码农没看太懂 呵呵

出0入0汤圆

发表于 2012-4-11 16:47:39 | 显示全部楼层
给力
听君一席话,再翻RVCT书...

出0入0汤圆

发表于 2012-4-11 16:47:47 | 显示全部楼层
恭喜,终于拨开迷雾了!连接器不知道还有栈这个东东
事实上,不同的工具链有自己的变量排布方式,根据实验,我发现MDK的似乎是先放.data区,然后是.bss区,接下来按字母序(ASCII码)排列各个Sections。全局变量(严格地说是静态生命期的变量,还包括静态全局变量与静态局部变量)通常都在.data与.bss区,而栈的区常常被命名为"STACK",所以造成它们在栈前面的现象。倘若定义了其它的区,字母序比栈区的大,并且指定了静态生命期变量在这些区里,那么它们就在栈的后面了。
很多8/16位单片机的编译器,尤其是AVR的一些编译器,的确是按楼主的说法排布内存的,那是因为它们太专用了,为特定的某款型号生成代码。而ARM只是架构,有太多半导体公司生产ARM芯片,编译器不可能再作类似的假设,而是按一般的计算机来处理

出0入25汤圆

 楼主| 发表于 2012-4-11 16:59:46 | 显示全部楼层
bluelucky 发表于 2012-4-11 16:47
恭喜,终于拨开迷雾了!连接器不知道还有栈这个东东
事实上,不同的工具链有自己的变量排布方式,根据实验 ...


呵呵,其实主要还是您和dr2001两位大侠的耐心指点,我才能搞清楚这个东西。。。

现在想起来了,我在12楼回复中说的堆栈布局的”科学依据“,好像就是看AVR单片机的文章知道的,感觉很合理,所以就牢记下来了。。。

出0入0汤圆

发表于 2012-4-11 21:14:28 | 显示全部楼层
讨论得挺透彻的,学习了。

出75入4汤圆

发表于 2012-4-11 22:54:46 | 显示全部楼层
对存储器的分步以前基本不太关心。现在知道一些了

出870入263汤圆

发表于 2012-4-16 22:25:09 | 显示全部楼层
bluelucky大侠是正确的,我先后使用过ADS和EWARM,都证明bluelucky是对的。
楼主误把建议性内存布局理解为强制性内存布局,还把巧合理解为必然,然而一切都被bluelucky击碎,精彩!
影响内存布局的后台的BOSS是连接器的配置文件,也叫分散加载文件,不管是MDK还是EWARM,都是如此。
连接器并没有像楼主认为的那些潜规则。

出870入263汤圆

发表于 2012-4-16 22:28:34 | 显示全部楼层
bluelucky 发表于 2012-4-11 16:47
恭喜,终于拨开迷雾了!连接器不知道还有栈这个东东
事实上,不同的工具链有自己的变量排布方式,根据实验 ...

不错!句句关键!

出0入0汤圆

发表于 2012-4-16 22:50:58 | 显示全部楼层
果断穿要裤子啊,这贴,,加紧学习了要

出0入0汤圆

发表于 2012-4-16 22:57:13 | 显示全部楼层
bluelucky大侠好强!这些资料是哪里看到的
头像被屏蔽

出0入0汤圆

发表于 2012-4-21 09:03:13 | 显示全部楼层
COOL !

出0入25汤圆

 楼主| 发表于 2012-4-21 09:28:55 | 显示全部楼层
本帖最后由 XIVN1987 于 2012-4-21 09:30 编辑
armok 发表于 2012-4-21 09:03
COOL !


惭愧惭愧,,,bluelucky大侠的裤子被我给冒领了。。。。

出0入0汤圆

发表于 2012-4-21 10:01:53 | 显示全部楼层
分析得非常好。我是来收藏的

出0入0汤圆

发表于 2012-4-21 11:05:47 | 显示全部楼层
bluelucky 发表于 2012-4-11 16:16
dr2001理解的比我深刻,我只在RVCT上知道是这样的,dr2001告诉我们GCC也是这样处理的。我估计IAR也是这样, ...

IAR,需要指定ICF文件(当然可以使用IAR自带的默认ICF),而ICF文件,我们可以自由控制栈的位置,想放在哪里就放在哪里……一般ICF文件,是由芯片厂家提供。
比MDK更加容易控制段的位置

出0入0汤圆

发表于 2012-4-21 15:01:45 | 显示全部楼层
详细看了贴子,受益匪浅呀

出0入0汤圆

发表于 2012-4-22 09:15:28 | 显示全部楼层
恭喜恭喜,是楼主问题题得好,当然要穿上裤子啦

出0入0汤圆

发表于 2012-4-29 20:14:40 | 显示全部楼层
三楼的解释,我会了!

出0入0汤圆

发表于 2012-5-2 14:13:11 | 显示全部楼层
XIVN1987 发表于 2012-4-11 15:32
"栈和堆都是普通的sections,在链接器看来一视同仁,与汇编代码中定义的其它AREAs,以及C语言中的全局变 ...

可以断点续传吗?

出0入0汤圆

发表于 2012-5-2 21:42:29 | 显示全部楼层
楼主的思维慎密,bluelucky实践加理论出真知。确实值得学习

出0入0汤圆

发表于 2012-5-8 20:15:42 | 显示全部楼层
真的有点“久旱逢甘露"的感觉,这些天我被启动文件的问题困扰,看了这讨论,明朗了很多了~~~~~~

出0入0汤圆

发表于 2012-6-2 13:19:41 | 显示全部楼层
我也明白了!!!

出0入0汤圆

发表于 2012-6-3 20:47:49 | 显示全部楼层
虽然一点都看不懂,不过可以慢慢积累,,感谢中

出100入143汤圆

发表于 2012-6-5 12:17:21 | 显示全部楼层
解释的透彻啊

出0入0汤圆

发表于 2012-6-8 16:08:50 | 显示全部楼层
讨论深入精彩,学习

出0入0汤圆

发表于 2012-6-9 00:37:36 | 显示全部楼层
感动大侠们的无私与耐心,更敬佩bluelucky的谦逊人品。
致敬&学习(我学到的不只是知识,更重要的是为人之品)。

出0入0汤圆

发表于 2012-6-10 16:11:59 | 显示全部楼层
学习,mark

出0入0汤圆

发表于 2012-8-5 17:01:33 | 显示全部楼层
刚开始看STM32的启动文件,博大精深啊,受教了

出0入0汤圆

发表于 2012-9-14 16:05:36 | 显示全部楼层
楼上高手好多,呵呵。

出0入0汤圆

发表于 2012-9-15 00:05:31 | 显示全部楼层
果断 MARK

出0入0汤圆

发表于 2012-11-12 22:34:54 | 显示全部楼层
不错的资料

出0入0汤圆

发表于 2012-11-12 22:51:34 | 显示全部楼层
似懂非懂,看来还得收藏了多看几遍

出0入0汤圆

发表于 2012-11-29 22:48:36 | 显示全部楼层
COOL!学习

出0入0汤圆

发表于 2012-11-30 13:20:48 | 显示全部楼层

学习,mark学习,

出0入0汤圆

发表于 2012-11-30 14:14:53 | 显示全部楼层
刚看到此贴,bluelucky 真是高手,正在研读其写的《Cortex-M3权威指南》

出0入0汤圆

发表于 2012-12-1 01:37:05 | 显示全部楼层
这样的解释让人理解清晰,mark

出0入0汤圆

发表于 2012-12-6 20:48:11 | 显示全部楼层
MARK下来慢慢学习

出0入0汤圆

发表于 2012-12-8 07:18:40 | 显示全部楼层
COOL, MARK!                  

出0入0汤圆

发表于 2012-12-8 08:59:30 | 显示全部楼层
最近在看汇编~ 挺好的帖子

出0入0汤圆

发表于 2012-12-8 09:10:38 | 显示全部楼层
mark         

出0入0汤圆

发表于 2012-12-9 10:31:52 | 显示全部楼层
其实 是按照数据空间的名字进行排序的。
全局变量的默认区域是.data段
或者.bbs段
注意有一个句点。
剩下的才是 Statck heap等。
是按照 首字母的顺便安排的。

出0入0汤圆

发表于 2012-12-14 16:10:05 | 显示全部楼层
最近正在学习启动文件,受益匪浅啊!!不过还有些问题没搞明白!要继续努力哈

出0入0汤圆

发表于 2012-12-16 14:30:44 | 显示全部楼层
为什么既要有“堆”又要有“栈”呢?
它们有何区别?

出0入0汤圆

发表于 2012-12-16 15:32:13 | 显示全部楼层
堆是用来申请内存空间用的。例如malloc函数free函数。
栈是调用函数用的。
不过我们一般直接使用全局变量,不会申请内存。所以你不用了解堆的概念。
你要是会dos 编程就更加明白堆和栈的概念。

出0入0汤圆

发表于 2012-12-16 16:23:54 | 显示全部楼层
本帖最后由 sun_changdong 于 2012-12-16 16:26 编辑
liugu 发表于 2012-12-16 15:32
堆是用来申请内存空间用的。例如malloc函数free函数。
栈是调用函数用的。
不过我们一般直接使用全局变量, ...


楼上的太厉害了!
我一直没搞明白这个问题!
谢谢了!

但是为什么程序里还要写“堆”的部分呢?

出0入0汤圆

发表于 2012-12-16 21:28:25 | 显示全部楼层
这是C语言运行环境要求的。必须要有堆的空间。
因为C语言环境要防止万一有人使用malloc函数。
一些习惯在pc上编程的人,就习惯使用malloc函数。
一些只在单片机上玩的人,反倒不习惯使用malloc函数,因为单片机的ram空间有限。
但现在的arm 似乎又不在乎ram空间了,呵呵

出0入0汤圆

发表于 2012-12-17 14:22:04 | 显示全部楼层
liugu 发表于 2012-12-16 21:28
这是C语言运行环境要求的。必须要有堆的空间。
因为C语言环境要防止万一有人使用malloc函数。
一些习惯在pc ...

那这两个空间在分配上有没有什么特别需要注意的地方呢?
谢谢!

出0入0汤圆

发表于 2012-12-18 09:53:37 | 显示全部楼层
吐槽一下,我不认为MDK要求在程序中划分栈空间(确定栈顶位置)是个好方法,原因很简单,这个空间并非最佳大小,过小的确点:不能充分使用RAM,栈空间到RAM末尾的一段无法使用,如果因栈空间过小而导致栈溢出,则相当无语;过大则会导致链接失败,如果链接不报错则更加讨厌:初始栈指针直接超界,上电就挂掉。

出0入0汤圆

发表于 2012-12-20 19:33:57 来自手机 | 显示全部楼层
不错支持的好帖子

出0入0汤圆

发表于 2012-12-20 20:36:20 来自手机 | 显示全部楼层
这种好贴子要顶!

出0入0汤圆

发表于 2012-12-21 08:34:23 | 显示全部楼层
bluelucky 发表于 2012-4-11 14:51
不知是谁强加给了你这样的概念,好像链接器与C语言要有某种默契似的。事实上,链接器并不关心哪段地址要做 ...

理解的超透彻!佩服啊

出0入0汤圆

发表于 2014-1-12 14:26:23 | 显示全部楼层
准备睡个回笼觉。突然发现宋岩大师,膜拜下。想来学stm32半个学期了。过年回家,好好消化下。

出0入0汤圆

发表于 2014-1-13 16:38:40 | 显示全部楼层
受教了,给力。

出0入0汤圆

发表于 2014-7-28 15:28:23 | 显示全部楼层
标记精华。。。

出0入0汤圆

发表于 2014-7-28 18:38:59 | 显示全部楼层
Mark,学习!

出0入0汤圆

发表于 2014-7-29 11:50:06 | 显示全部楼层
#在这里快速回复#mark

出0入0汤圆

发表于 2014-7-29 12:32:11 | 显示全部楼层
bluelucky说的对,什么堆啊,栈啊,说白了,就是一个全局变量么,不过我这里想问的是  标号 __heap_base 和 Heap_Mem ,是同一个值吗   

出0入0汤圆

发表于 2014-9-11 12:31:08 | 显示全部楼层
学习学习,虽然帮不上忙,但是可以看看啊

出0入0汤圆

发表于 2014-9-11 16:05:48 | 显示全部楼层
我觉得bluelucky说的关键性有一点:

“如果是有操作系统的,每个任务都有自己的栈,更谈不上把栈放在最后,以便溢出时还有得救这种想法了 “,因为看起楼主还是在以前八位机的思维,而ARM严格来说已经不算是小MCU了,它有能力作为一个OS,所以编译器对他的行为也会有所改变,就好像父母对待小孩在小的时候的要求和长大后的要求是不一样的!!

出0入0汤圆

发表于 2014-9-15 15:22:01 | 显示全部楼层
分析的很好
关于STM32  MSP  PSP的空间分配切换  希望高手指点
还有就是启动过程 RW ZI  BSS段数据如何从flash到内存 以及如何让程序在内存运行

出0入0汤圆

发表于 2014-9-15 15:22:39 | 显示全部楼层
bluelucky 发表于 2012-4-22 09:15
恭喜恭喜,是楼主问题题得好,当然要穿上裤子啦

分析的很好
关于STM32  MSP  PSP的空间分配切换  希望高手指点
还有就是启动过程 RW ZI  BSS段数据如何从flash到内存 以及如何让程序在内存运行

出0入0汤圆

发表于 2014-9-15 15:23:02 | 显示全部楼层
相当精彩的讨论

出0入0汤圆

发表于 2015-1-14 09:46:44 | 显示全部楼层
STM32F4 有CCM RAM空间,不知道将栈分配到哪里是否可行。程序运行会不会快点。

出0入0汤圆

发表于 2015-1-14 15:02:33 | 显示全部楼层
正在拜读,宋岩老师的书!mark

出0入0汤圆

发表于 2015-4-6 15:30:11 | 显示全部楼层
太精彩了!

出0入0汤圆

发表于 2015-4-6 19:21:59 | 显示全部楼层
精彩,精华帖不能沉了!

出0入0汤圆

发表于 2015-4-6 20:07:10 | 显示全部楼层
MARK Cortex-M单片机 关于堆栈的相关问题

出0入0汤圆

发表于 2015-4-6 21:08:25 | 显示全部楼层
非常经常的技术研究贴,学习了

出0入0汤圆

发表于 2015-4-6 21:31:23 | 显示全部楼层
很好的东西,先收藏了。以后研究。

出0入0汤圆

发表于 2015-6-18 23:49:54 | 显示全部楼层
谢谢楼上几位大神,先收了,慢慢看

出0入0汤圆

发表于 2015-6-19 21:59:09 | 显示全部楼层
先看看

出0入0汤圆

发表于 2015-6-19 23:39:50 | 显示全部楼层
好帖子,先收藏了,再慢慢学习

出0入0汤圆

发表于 2015-6-20 21:31:04 | 显示全部楼层
MARK                        

出0入0汤圆

发表于 2015-6-23 10:25:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2015-6-30 20:56:00 | 显示全部楼层
关于堆栈的问题,学习了

出0入0汤圆

发表于 2015-6-30 22:17:33 | 显示全部楼层
bluelucky 发表于 2012-4-11 10:18
这个问题一点也不愚蠢啊,反倒是红色的两个名字会愚弄人呢!是时候揭开它们的假面具了。
STACK, HEAP只是两 ...

很专业啊,学习了。

出0入0汤圆

发表于 2016-2-23 10:05:06 | 显示全部楼层
谢谢大侠们的讨论,暂时不太懂,先收藏了,留待以后学习

出0入0汤圆

发表于 2016-2-24 10:36:02 | 显示全部楼层
学习了,不过看不太懂
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 23:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表