打印

关于__user_initial_stackheap( )

[复制链接]
9904|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 machunshui 于 2009-10-9 14:03 编辑

1.作用:用于提供编译器的初始化C库函数设置用户程序的堆栈所需要的堆栈信息。
2。__user_initial_stackheap() 返回:
  • r0 中的堆基址
  • r1 中的堆栈基址,即堆栈区中的最高地址
  • r2 中的堆限制
  • r3 中的堆栈限制,即堆栈区中的最低地址。

有单区模型和双区模型。

单区模型:(r0,r1)是单个堆栈和堆区。r1 大于 r0,并忽略 r2 和 r3。

r0--r1这一块内存区域被堆和栈共用,堆从r0向上生长,栈从r1向下生长。

双区模型:(r0, r2)是初始堆,(r3, r1) 是初始堆栈。r2 大于或等于 r0。r3 小于 r1。
堆和栈分别指定了单独的内存区域。

3.如果不使用分散加载文件,则__user_initial_stackheap()必须由用户自己实现。

实现例子:
; User Initial Stack & Heap
                AREA    |.text|, CODE, READONLY

                IMPORT  __use_two_region_memory
                EXPORT  __user_initial_stackheap
__user_initial_stackheap

                LDR     R0, =  Heap_Mem
                LDR     R1, =(Stack_Mem + USR_Stack_Size)
                LDR     R2, = (Heap_Mem +      Heap_Size)
                LDR     R3, = Stack_Mem
                BX      LR

4.使用分散加载可以由用户实现,也可以在分散加载描述文件中定义两个特殊执行区(双区模型,单区模型只定义ARM_LIB_STACKHEAP):        ARM_LIB_HEAP 和 ARM_LIB_STACK(该区具有 EMPTY 属性。),从而使用C库的默认实现,此时,会导致库选择一个使用以下符号值的 __user_initial_stackheap() 实现:Image$$ARM_LIB_HEAP$$Base、Image$$ARM_LIB_HEAP$$ZI$$Limit、Image$$ARM_LIB_STACK$$Base 和 Image$$ARM_LIB_STACK$$ZI$$Limit。这种方式比较方便。

例子:
分散加载文件:
LR_IROM1 0x00000000 0x00008000                                     ;; Load region
{
    ER_IROM1 0x00000000    0x00008000
    {
        vectors.o (VECT, +First)
        init.o (INIT)
        * (+RO)
    }

    RW_IRAM1 0x40000040 0x00001460
    {
        * (+RW,+ZI)
    }                                                           ;; The following declarations select the "two region model" ;
                                                                ;; A default __user_initial_stackheap() will be used        ;
    ARM_LIB_HEAP  0x40001500 EMPTY  0x00000100   {}
    ARM_LIB_STACK 0x40002000 EMPTY -0x00000400   {}
}

在初始化文件中使用||Image$$ARM_LIB_STACK$$ZI$$Limit||作为栈底,

例子:
                IMPORT __use_two_region_memory
                IMPORT  ||Image$$ARM_LIB_STACK$$ZI$$Limit||     ; Import stack limit from scatter-loading file              ;

                ldr     r1, =||Image$$ARM_LIB_STACK$$ZI$$Limit||
               
                mrs     r0,cpsr                             ; Original PSR value                                        ;
                bic     r0,r0,#MODE_BITS                    ; Clear the mode bits                                       ;
                orr     r0,r0,#IRQ_MODE                     ; Set IRQ mode bits                                         ;
                msr     cpsr_c,r0                           ; Change the mode                                           ;
                mov     sp, r1
                sub     r1, r1, #IRQ_STK_SIZE
               
............................                         ;

相关帖子

沙发
阿南| | 2009-10-9 11:42 | 只看该作者
鼓励一下

使用特权

评论回复
板凳
xinjie1023| | 2009-10-9 16:40 | 只看该作者
学习。。。

使用特权

评论回复
地板
itelectron| | 2009-10-9 19:21 | 只看该作者
MARK

使用特权

评论回复
5
itelectron| | 2009-10-9 23:28 | 只看该作者
请楼主帮忙分析下 图

使用特权

评论回复
6
itelectron| | 2009-10-9 23:29 | 只看该作者
;  Enter User Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_USR
                MOV     SP, R0
                SUB     SL, SP, #USR_Stack_Size

                                import main
                            bl   main
                            ldr pc,=0x30000000
stop            bl  stop


                AREA    |.text|, CODE, READONLY

                IMPORT  __use_two_region_memory
                EXPORT  __user_initial_stackheap
__user_initial_stackheap

                LDR     R0, =  Heap_Mem
                LDR     R1, =(Stack_Mem + USR_Stack_Size)
                LDR     R2, = (Heap_Mem +      Heap_Size)
                LDR     R3, = Stack_Mem
;                BX      LR
                END

使用特权

评论回复
7
itelectron| | 2009-10-9 23:33 | 只看该作者
bl   main
ldr pc,=0x30000000

感觉关键是这里 调用主函数 然后返回
在跳到0x30000000
但是我想在main()里

#define DOWNLOAD_ADDRESS        0x30000000   //the download address

void (*run)(void)=(void (*)(void))(DOWNLOAD_ADDRESS);

run();

这种方法怎么也跳不到 0x30000000

使用特权

评论回复
8
itelectron| | 2009-10-9 23:35 | 只看该作者
int main(void)
{
  run();                                                 //use run() in RAM                    
  return 0;
}

使用特权

评论回复
9
liuweifeng168| | 2009-10-21 13:00 | 只看该作者
这个帖子不错。

使用特权

评论回复
10
flashdyc| | 2009-10-22 09:09 | 只看该作者
请问楼主,这个函数是作为系统分配堆、栈的依据还是初始化堆栈的辅助信息?

使用特权

评论回复
11
machunshui|  楼主 | 2009-10-22 11:18 | 只看该作者
本帖最后由 machunshui 于 2009-10-22 11:27 编辑

不是这些功能。
这个函数只是提供已经分配的系统堆栈信息而已。

该函数被__rt_entry()函数中被调用,这些信息用于初始化C库函数。

注意,启动函数中的
LDR     R0, =__main

=__main并非直接跳转到用户程序的main()函数处,而是先:

◇ 将非启动代码的RO和RW执行域代码从加载域地址复制到执行域地址;
  ◇ 将ZI域清零;
  ◇ 跳转到__rt_entry。

然后再跳转到用户的main()函数处.


这个过程中就会调用__user_initial_stackheap() 函数

使用特权

评论回复
12
flashdyc| | 2009-10-22 14:21 | 只看该作者
11# machunshui
请问11楼,如果不是分配的依据,那系统中的堆内存在哪里分配的?

使用特权

评论回复
13
machunshui|  楼主 | 2009-10-22 15:36 | 只看该作者
启动代码里面分配啊,
LS可以看看keil自动生成的启动文件代码或者是zlg的模板中的启动文件

使用特权

评论回复
14
flashdyc| | 2009-10-22 21:47 | 只看该作者
13# machunshui
启动代码?ZLGlpc2210里面除了_user_initial_stack里面包含这堆内存相关内容外其他地方都没有相关说明!

使用特权

评论回复
15
machunshui|  楼主 | 2009-10-22 23:29 | 只看该作者
不管那家的启动代码,在堆栈分配上都玩不出花,
看谁家的都一样.

使用特权

评论回复
16
machunshui|  楼主 | 2009-10-22 23:32 | 只看该作者
如过为学linux在arm上的应用,去看看UBOOT也就罢了.
就看个堆栈分配,
去看UBOOT,本末倒置了.

使用特权

评论回复
17
machunshui|  楼主 | 2009-10-22 23:34 | 只看该作者
13# machunshui
启动代码?ZLGlpc2210里面除了_user_initial_stack里面包含这堆内存相关内容外其他地方都没有相关说明!
flashdyc 发表于 2009-10-22 21:47


随便打开个MDK的自带的ARM7的例子,就可以了,不一定非得看zlg的.

使用特权

评论回复
18
machunshui|  楼主 | 2009-10-22 23:40 | 只看该作者
看看MDK的自带的ARM7的例子中的启动文件,

UND_Stack_Size  EQU     0x00000000
SVC_Stack_Size  EQU     0x00000008
ABT_Stack_Size  EQU     0x00000000
FIQ_Stack_Size  EQU     0x00000000
IRQ_Stack_Size  EQU     0x00000080
USR_Stack_Size  EQU     0x00000400

Stack_Size      EQU     (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
                         FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size)

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

Stack_Top       EQU     Stack_Mem + Stack_Size


;// <h> Heap Configuration
;//   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF>
;// </h>

Heap_Size       EQU     0x00000000

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


以上这段,保留出栈空间和堆空间,

; Setup Stack for each mode

                LDR     R0, =Stack_Top

;  Enter Undefined Instruction Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #UND_Stack_Size

;  Enter Abort Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #ABT_Stack_Size

;  Enter FIQ Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #FIQ_Stack_Size

;  Enter IRQ Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #IRQ_Stack_Size

;  Enter Supervisor Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
                MOV     SP, R0
                SUB     R0, R0, #SVC_Stack_Size

;  Enter User Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_USR
                MOV     SP, R0
                SUB     SL, SP, #USR_Stack_Size

以上,进入各种模式,把为各种模式保留的堆栈的栈顶指针赋给该模式的SP寄存器,
这就实现了,栈的分配

使用特权

评论回复
19
flashdyc| | 2009-10-23 14:47 | 只看该作者
本帖最后由 flashdyc 于 2009-10-23 14:51 编辑

19# machunshui
多谢各位的帮忙,可能是我没描述清楚,我问的是堆内存在哪里设置的,或者是说编译器在哪里进行的堆内存设置,而不是在哪里定义的。楼主的代码我看过了,上面也只是定义了一个堆(名义上)空间,并没有像堆栈SP初始化那样,没有说明哪里对他进行了配置。我完全可以定义一个另外名字的AREA,但我不能随便就说它就是堆内存吧

使用特权

评论回复
20
machunshui|  楼主 | 2009-10-23 16:34 | 只看该作者
堆用于内存的动态分配,
空间保留出来,
堆的信息通过__user_initial_stackheap()提供给系统,
就可以了.

19楼的例子,只是分配的堆空间为0而已,
很多小的嵌入式系统是不需要内存动态分配的.



Heap_Size       EQU     0x100

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

上面的代码分配256字节堆空间.

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

153

主题

3224

帖子

4

粉丝