先看图如下:这是arm的发动进程。
先对发动前的硬件描绘一下,这样在剖析startup.s的时分就轻松多了。我运用的是smartarm2200开发板,其间CPU芯片运用的LPC2210,没有内部flash(周公太抠门了)。因此提到设置也便是两点:
一,BOOT[1:0]的设置。决定是从内部Memory仍是外部Memory发动。面对抠门的周公,咱只能从外部存储器发动了。无法啊!这也就引发了第二个扩展存储器的设置。
二,bank0、bank1的设置。要是用于调试的话就把ram设成bank0,能够在ram发动,这样能够很简略进行存储器重映射。要是烧flash的话就把flash设成bank0。
因此,咱们在流程图中的道路是一向在最右边走。哦,原来是从0x80000000发动啊!
接下来就开端进入代码了!首要看下图是全体几个文件的联系图。
方才看到运转首地址是0x80000000,那么怎样组织咱们的flash或许ram?记住在单片机中常常有用org 0x800办法就能搞定,咱们在ads中也能够设置RO、RW、ZI和进口点地址一额能够办到。但这只能使用一些很简略的状况,现在面对的要杂乱一点,因此“涣散加载办法”闪亮上台。这儿无妨总结一下ARM链接办法:
(1)simple办法:(三点设置)分别是,Output下:RO(代码基址) RW(数据基址包含ZI)。Layout下:Object/Symble填入startup.o Section填入start(依据实践状况定)Option下:Image Entry Pointer填入地址。
(2)scattered办法:(也要三步)分别是,编写.scf文件;在output下填入该文件;Option下填入进口地址。
下面剖析.scf文件,以mem_b.scf为例。
/************** mem_b.scf文件 *************/
ROM_LOAD 0x80000000//名 地址 规模约束(本比如缺省)
{
ROM_EXEC 0x80000000//片外存储器 地址 规模巨细(本例缺省)
{
Startup.o (vectors, +First) //startup文件中vector段放于最初
* (+RO) //其他模块的代码与只读数据放于此
}
IRAM 0x40000000 //片内RAM 地址 规模巨细(缺省)
{
Startup.o (MyStacks) //startup文件中MyStacks段放于最初
}
STACKS_BOTTOM +0 UNINIT //栈底 地址 不必初始化 规模巨细约束(缺省)
{
Startup.o (StackBottom) //startup文件中MyStackBottom段放于最初
}
STACKS 0x40004000 UNINIT
{
Startup.o (Stacks)
}
ERAM 0x80040000
{
* (+RW,+ZI) //一切的RW与ZI数据置于此,也便是未初始化和初始化的全局变量
}
HEAP +0 UNINIT
{
Startup.o (Heap)
}
HEAP_BOTTOM 0x80080000 UNINIT
{
Startup.o (HeapTop)
}
}
能够用文件的办法调查内存的实践格式,在ARM Linker的Listings选项卡下,选中Image Map复选框。这样编译的时分就会显现内存格式了。
Memory Map of the image
Image Entry point : 0x80000000
Load Region ROM_LOAD (Base: 0x80000000, Size: 0x000005b4, Max: 0xffffffff, ABSOLUTE)
Execution Region ROM_EXEC (Base: 0x80000000, Size: 0x000005b4, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x80000000 0x00000110 Code RO 1 * vectors Startup.o
0x80000110 0x000000a8 Code RO 53 * !!! __main.o(c_a__un.l)
0x800001b8 0x000000dc Code RO 10 .text target.o
0x80000294 0x00000078 Code RO 42 .text main.o
0x8000030c 0x00000008 Code RO 55 .text _no_redirect.o(c_a__un.l)
0x80000314 0x000000a4 Code RO 57 .text stkheap2.o(c_a__un.l)
0x800003b8 0x00000004 Code RO 59 .text use_no_semi.o(c_a__un.l)
0x800003bc 0x00000028 Code RO 61 .text kernel.o(c_a__un.l)
0x800003e4 0x0000000c Code RO 63 .text libspace.o(c_a__un.l)
0x800003f0 0x00000018 Code RO 66 .text exit.o(c_a__un.l)
0x80000408 0x000000fc Code RO 68 .text lib_init.o(c_a__un.l)
0x80000504 0x00000010 Code RO 72 .text rt_fp_status_addr.o(c_a__un.l)
0x80000514 0x00000014 Code RO 70 x$fpl$fpinit fpinit.o(f_a_p.l)
0x80000528 0x00000020 Data RO 43 .constdata main.o
0x80000548 0x00000054 Data RO 74 Region
obj.o
0x8000059c 0x00000018 Data RO 75 ZISection
obj.o
Execution Region IRAM (Base: 0x40000000, Size: 0x00000400, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x40000000 0x00000400 Zero RW 2 MyStacks Startup.o
Execution Region STACKS_BOTTOM (Base: 0x40000400, Size: 0x00000004, Max: 0xffffffff, ABSOLUTE, UNINIT)
Base Addr Size Type Attr Idx E Section Name Object
0x40000400 0x00000004 Zero RW 4 StackBottom Startup.o
Execution Region STACKS (Base: 0x40004000, Size: 0x00000000, Max: 0xffffffff, ABSOLUTE, UNINIT)
Base Addr Size Type Attr Idx E Section Name Object
0x40004000 0x00000000 Zero RW 6 Stacks Startup.o
Execution Region ERAM (Base: 0x80040000, Size: 0x00000060, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x80040000 0x00000060 Zero RW 64 .bss libspace.o(c_a__un.l)
Execution Region HEAP (Base: 0x80040060, Size: 0x00000004, Max: 0xffffffff, ABSOLUTE, UNINIT)
Base Addr Size Type Attr Idx E Section Name Object
0x80040060 0x00000004 Zero RW 3 Heap Startup.o
Execution Region HEAP_BOTTOM (Base: 0x80080000, Size: 0x00000000, Max: 0xffffffff, ABSOLUTE, UNINIT)
Base Addr Size Type Attr Idx E Section Name Object
0x80080000 0x00000000 Zero RW 5 HeapTop Startup.o
Load Region LR$$Debug (Base: 0x00000000, Size: 0x00000000, Max: 0xffffffff, ABSOLUTE)
Execution Region ER$$Debug (Base: 0x00000000, Size: 0x00000000, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000000 0x00000010 Dbug RW 9 .debug_abbrev Startup.o
0x00000010 0x000003ec Dbug RW 19 .debug_abbrev target.o
0x00000000 0x0000014c Dbug RW 18 .debug_frame target.o
0x0000014c 0x00000058 Dbug RW 52 .debug_frame main.o
0x000001a4 0x0000003c Dbug RW 54 .debug_frame __main.o(c_a__un.l)
0x000001e0 0x0000004c Dbug RW 56 .debug_frame _no_redirect.o(c_a__un.l)
0x0000022c 0x00000094 Dbug RW 58 .debug_frame stkheap2.o(c_a__un.l)
0x000002c0 0x00000044 Dbug RW 60 .debug_frame use_no_semi.o(c_a__un.l)
0x00000304 0x00000058 Dbug RW 62 .debug_frame kernel.o(c_a__un.l)
0x0000035c 0x00000044 Dbug RW 65 .debug_frame libspace.o(c_a__un.l)
0x000003a0 0x0000004c Dbug RW 67 .debug_frame exit.o(c_a__un.l)
0x000003ec 0x0000007c Dbug RW 69 .debug_frame lib_init.o(c_a__un.l)
0x00000468 0x0000004c Dbug RW 71 .debug_frame fpinit.o(f_a_p.l)
0x000004b4 0x0000004c Dbug RW 73 .debug_frame rt_fp_status_addr.o(c_a__un.l)
0x00000000 0x00000074 Dbug RW 7 .debug_info Startup.o
0x00000074 0x0000007c Dbug RW 12 .debug_info target.o
0x000000f0 0x00000108 Dbug RW 35 .debug_info target.o
0x000001f8 0x000000e4 Dbug RW 31 .debug_info target.o
0x000002dc 0x00000540 Dbug RW 15 .debug_info target.o
0x0000081c 0x00000110 Dbug RW 27 .debug_info target.o
0x0000092c 0x00000090 Dbug RW 45 .debug_info main.o
0x000009bc 0x00000134 Dbug RW 49 .debug_info main.o
0x00000000 0x0000009c Dbug RW 8 .debug_line Startup.o
0x0000009c 0x000000b8 Dbug RW 11 .debug_line target.o
0x00000154 0x000000f8 Dbug RW 14 .debug_line target.o
0x0000024c 0x00000064 Dbug RW 26 .debug_line target.o
0x000002b0 0x00000050 Dbug RW 30 .debug_line target.o
0x00000300 0x00000050 Dbug RW 34 .debug_line target.o
0x00000350 0x00000078 Dbug RW 44 .debug_line main.o
0x000003c8 0x000000a4 Dbug RW 48 .debug_line main.o
0x00000000 0x000002c0 Dbug RW 17 .debug_loc target.o
0x000002c0 0x00000064 Dbug RW 51 .debug_loc main.o
0x00000000 0x00000190 Dbug RW 13 .debug_macinfo target.o
0x00000190 0x00000078 Dbug RW 29 .debug_macinfo target.o
0x00000208 0x0000004c Dbug RW 33 .debug_macinfo target.o
0x00000254 0x000001f0 Dbug RW 37 .debug_macinfo target.o
0x00000444 0x00000190 Dbug RW 47 .debug_macinfo main.o
0x00000000 0x00000128 Dbug RW 16 .debug_pubnames target.o
0x00000128 0x00000064 Dbug RW 28 .debug_pubnames target.o
0x0000018c 0x00000058 Dbug RW 32 .debug_pubnames target.o
0x000001e4 0x00000084 Dbug RW 36 .debug_pubnames target.o
0x00000268 0x00000020 Dbug RW 46 .debug_pubnames main.o
0x00000288 0x00000028 Dbug RW 50 .debug_pubnames main.o
================================================================================
Image component sizes
Code RO Data RW Data ZI Data Debug
612 140 0 1032 8356 Object Totals
708 0 0 96 860 Library Totals
================================================================================
Code RO Data RW Data ZI Data Debug
1320 140 0 1128 9216 Grand Totals
================================================================================
Total RO Size(Code + RO Data) 1460 ( 1.43kB)
Total RW Size(RW Data + ZI Data) 1128 ( 1.10kB)
Total ROM Size(Code + RO Data + RW Data) 1460 ( 1.43kB)
================================================================================
****************************************************************************
一般的可履行程序都包含代码段、数据段。也能够简略的看作由两部分组成:RO段和RW段。RO段一般包含代码段和一些常量,在运转的时分是只读的。而RW段包含一些全局变量和静态变量,在运转的时分是能够改动的(读写)。假如有部分全局变量被初始化为零,则RW段里还包含了ZI段。
RO: Read Only 代码段
RW: Read Write 已初始化的全局变量
ZI: Zero Init 未初始化的全局变量
由于RO段是只读的,在运转的时分不能够改动,所以,在运转的时分,RO段能够驻留在Flash里(当然也能够在SDRAM或许SRAM里了)。而RW段是能够读写的,所以,在运转的时分有必要被装载到SDRAM或许SRAM里。
在用ADS编译的时分,是需求设置RO BASE 和RW BASE的,用过ADS的应该都清楚这点。经过RO BASE 和RW BASE的设置,告知链接器(linker)该程序的开端运转地址(RO BASE)和 RW段的地址 (RW BASE)。假如一个程序只要RO段,没有RW段,那么这个程序能够彻底在Flash里运转,不需求用到SDRAM 或许 SRAM。假如包含RW段和RO段,那么该程序的RW段有必要在被拜访曾经被复制到SDRAM 或许SRAM里去,以确保程序能够正确运转。下面这个图说明晰一个程序履行前(load view)和履行时(execute view)的状况。从图中能够看到,整个程序在履行前始放在ROM里的,在履行的时分,RW段被复制到了RAM里的适宜方位去。
程序一开端总是存储在ROM/Flash里边的,其RO部分既能够在ROM/Flash里边履行,也能够转移到速度更快的RAM中去;而RW和ZI这两部分是有必要转移到可写的RAM里去。所谓使用程序履行环境的初始化,便是完结必要的从ROM到RAM的数据传输和内容清零。
不同的东西链会供给一些不同的机制和办法协助用户完结这一步操作,主要是跟链接器(Linker)相关。下面是在ARM开发东西环境ADS下,一种常用存储器模型的直接完成:
LDR r0, = |Image
Limit| ;得到RO段末的下一字节的地址 ,ROM中的RW的开端地址
LDR r1, = |Image
Base| ;得到RAM中的RW段的初始地址
LDR r3, = |Image
Base| ;全局变量的初始地址
CMP r0, r1 ;
BEQ LOOP1
LOOP0
CMP r1, r3 ;是否到RAM中的RW段的末地址,假如没到,则一向将ROM(FLASH变 量与数据段复制到RAM中
LDRCC r2, [r0], #4;[R0]=[R1]
STRCC r2, [r1], #4 ;
BCC LOOP0
LOOP1
LDR r1, = |Image
Limit| ; LOOP1与LOOP2履即将ZI初始化为0
MOV r2, #0
LOOP2
CMP r3, r1
STRCC r2, [r3], #4 ;
BCC LOOP2
在ADS里,有一些预先界说了的变量能够用(linker defined symbol)。鄙人面的完成里,用到了几个预界说的变量:
Image
Base 该变量指定了RO段的 BASE
Image
Limit 该变量指定了RO段的 Limit
Image
Base 该变量指定了RW段的 BASE
Image
Limit 该变量指定了RW段的 Limit
Image
Base 该变量指定了ZI段的 BASE
Image
Limit 该变量指定了ZI段的 Limit
注:详细能够参阅ADS Linker Guide
Image
Limit 减 Image
Base 等于RO段的巨细
Image
Limit 减 Image
Base 等于RW段的巨细
Image
Limit 减 Image
Base 等于ZI段的巨细
(Image
Limit 减 Image
Base)
+ (Image
Limit 减 Image
Base)
= 等于整个程序的巨细
注:ZI段始包含在RW段里边的。