打印

关于ARM7启动代码startup.s

[复制链接]
6561|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
husion|  楼主 | 2010-9-2 15:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
;中断向量表
Reset
        LDR     PC, ResetAddr
        LDR     PC, UndefinedAddr
        LDR     PC, SWI_Addr
        LDR     PC, PrefetchAddr
        LDR     PC, DataAbortAddr
        DCD     0xb9205f80
        LDR     PC, [PC, #-0xff0]
        LDR     PC, FIQ_Addr
ResetAddr           DCD     ResetInit
UndefinedAddr       DCD     Undefined
SWI_Addr            DCD     SoftwareInterrupt
PrefetchAddr        DCD     PrefetchAbort
DataAbortAddr       DCD     DataAbort
Nouse               DCD     0
IRQ_Addr            DCD     0
FIQ_Addr            DCD     FIQ_Handler
ResetInit
;Initial the extenal bus controller
;初始化外部总线控制器,根据目标板决定配置
        LDR     R0, =PINSEL2
    IF :DEF: EN_CRP
        LDR     R1, =0x0f814910
    ELSE
        LDR     R1, =0x0f814914
    ENDIF
        STR     R1, [R0]
        LDR     R0, =BCFG0
        LDR     R1, =0x10001460   
        STR     R1, [R0]
        LDR     R0, =BCFG1
        LDR     R1, =0x1000ffef
        STR     R1, [R0]
        LDR     R0, =BCFG2
        LDR     R1, =0x1000ffef
        STR     R1, [R0]
;        LDR     R0, =BCFG3
;        LDR     R1, =0x2000ffef
;        STR     R1, [R0]
        
        BL      InitStack               ; Initialize the stack 初始化堆栈
        BL      TargetResetInit         ; Initialize the target board 目标板基本初始化
                                        ; Jump to the entry point of C program 跳转到c语言入口
        B       __main
上面是ARM7的启动代码startup.s的一段代码.我跟踪了一下,程序先运行Reset-ResetAddr-ResetInit
但有一个问题当执行完ResetInit里面最后一个函数TargetResetInit(蓝色)后,程序接着运行哪了,我本以为会运行函数,但单步跟踪进去
不是函数,而是一堆汇编指令.
小弟刚学ARM7,请大虾们指点一下,运行完TargetResetInit后,程序接着运行什么?

相关帖子

沙发
sheriff| | 2010-9-2 16:04 | 只看该作者
调用完TargetResetInit之后调用__main,__main应该是编译器的一个库函数,用来初始化变量的。

使用特权

评论回复
板凳
chunk| | 2010-9-2 16:08 | 只看该作者
“ B       __main”的这个__main不是你的main函数?那就不是吧,早晚会走到你的main函数。

你找找编译器带的库的源码吧,有没有什么CRT0.S之类的东东,里边找找有没有和这个__main对应的代码。要不,你让连接器输出一个MAP文件,你的main函数的实际符号可能是_main,一个下线而不是两个的。也可能是什么$$main$$之类的东东,你把这个“ B       __main”直接改成B到你的_main(也可能$$main$$)也行。

你非要弄清楚这个__main?你的C源码中有没有带初始值的全局变量?比如

int a = 0x5a;
int main()
{
    .........
}

这个a肯定是在SRAM中了,SRAM中的那个字节怎么就刚好是0x5A呢?这和__main之中的一堆代码有关系没??

慢慢折腾吧。

使用特权

评论回复
地板
husion|  楼主 | 2010-9-2 16:21 | 只看该作者
还有,我按F7运行程序到LDR     PC, UndefinedAddr这一行,程序跳到main()函数,我再按F7程序到LDR     PC, UndefinedAddr这一行,程序变成全速运行.难道在LDR     PC, ResetAddr以下下面这些代码:
        LDR     PC, UndefinedAddr
        LDR     PC, SWI_Addr
        LDR     PC, PrefetchAddr
        LDR     PC, DataAbortAddr
        DCD     0xb9205f80
        LDR     PC, [PC, #-0xff0]
        LDR     PC, FIQ_Addr
都不执行了?

使用特权

评论回复
5
hotpower| | 2010-9-2 17:44 | 只看该作者
这个启动文件肯定有问题。程序执行到BC _main

使用特权

评论回复
6
husion|  楼主 | 2010-9-2 19:37 | 只看该作者
to hotpower:
    可这个是周立功的代码,在开发板上可以运行通过!

使用特权

评论回复
7
armmage| | 2010-9-2 19:42 | 只看该作者
HOT大 有点武断了  我看过好几种ARM7启动代码 包括ZLG的ARM7送的启动代码都有
B       __main
这个跳转时没问题的 关键是__main不是自己定义的函数 而是 ADS自带的库函数 (不知道你用的是ADS编译器不)__main中所做的事初始化 你的 RO RW ZI三个区 (你用的是简单加载模式)然后跳转到你定义的主函数。具体过程好像是这样  时间长了记得有点模糊 不好意思·····

使用特权

评论回复
8
armmage| | 2010-9-2 19:48 | 只看该作者
弱弱的建议下  启动代码看明白后根据自己需要改改 RO RW ZI区的加载代码 或者 你用分散加载功能时 代码自己写 这个是我学S3C44B0X时看到的比较完整的启动代码 (话说比ZLG送的ARM7启动代码详尽)
其实裸奔ARM7最好把启动过程整透彻 对以后学习更有帮助 当然如果你是出了WINCE其他不玩的高人也就免了

使用特权

评论回复
9
husion|  楼主 | 2010-9-2 19:59 | 只看该作者
to armmage:
   谢谢回复.
   你看看我4楼的问题!

使用特权

评论回复
10
hotpower| | 2010-9-2 20:02 | 只看该作者
我一般不喜欢用模板。
启动代码keil都有自带。
目标板的初始化一般在main的开始。

使用特权

评论回复
11
husion|  楼主 | 2010-9-2 20:08 | 只看该作者
还有我用ADS1.2编译器

使用特权

评论回复
12
airwill| | 2010-9-2 20:29 | 只看该作者
to: 4 楼
仔细看看后面的代码就明白了嘛

        LDR     PC, SWI_Addr
        LDR     PC, PrefetchAddr
        LDR     PC, DataAbortAddr
        DCD     0xb9205f80
        LDR     PC, [PC, #-0xff0]
        LDR     PC, FIQ_Addr

这些应该是中断服务程序的入口嘛, 都是中断服务里执行的第一条指令.
在进入 main() 前不需要运行的

使用特权

评论回复
13
armmage| | 2010-9-2 21:09 | 只看该作者
LDR     PC, SWI_Addr
        LDR     PC, PrefetchAddr
        LDR     PC, DataAbortAddr
        DCD     0xb9205f80
        LDR     PC, [PC, #-0xff0]
        LDR     PC, FIQ_Addr
恩啊 我来华丽的解释下······
SWI_Addr 是程序跳软中断 SWI_Addr应该是个汇编语言的label 就像ResetInit一样 标签功能
LDR PC 标签 语句其实作用就是跳到标签处执行 像goto吧

还有 你贴上来的启动代码不全啊  如果你用的ARM7是从地址0开始启动执行的 那么
Reset 上面应该有 程序段的定义
比如
        AREA        init,        CODE,        READONLY
        ENTRY
Reset
init 是段名(貌似叫域名····记不清了)
这个什么名的 因为有ENTRY属性 可以在ADS的ARM linker设置中有定义
说的我自己都晕了······  其实就是Reset被定义为程序启动要执行的第一个指令 的 标签
而后面跟随的几个 LDR PC 标签  就是ARM7的异常跳转地址 没出现异常当然程序不会执行这里

话说很少看到研究启动程序的人(我身边都是高人 不屑看这个)你真想弄明白 最好看下ARM的汇编指令和体系结构之类的书 还有个好办法就是 AXD调试环境下 把编译后的启动代码都抄下来(我抄了5张A4纸)然后很多你看上去很迷惑的东西 一下就明了了

使用特权

评论回复
14
sheriff| | 2010-9-2 22:36 | 只看该作者
还有,我按F7运行程序到LDR     PC, UndefinedAddr这一行,程序跳到main()函数,我再按F7程序到LDR     PC, UndefinedAddr这一行,程序变成全速运行.难道在LDR     PC, ResetAddr以下下面这些代码:
        LDR     PC,  ...
husion 发表于 2010-9-2 16:21

LDR     PC, ResetAddr是一条加载PC的指令,其实就是一条程序跳转指令,所以它后面的指令当然不能顺序执行了。它后面的也都是加载PC的程序跳转指令,这个应该叫做异常向量表,当发生异常的时候(软中断、数据中止或IRQ等)程序会跳转到异常向量表相应的入口。

使用特权

评论回复
15
xinzha| | 2010-9-2 23:10 | 只看该作者
__main是ARM提供的库函数,里面做了段加载以及初始化等功能,而实际上完全可以跳过这个函数,前提是你自己确保加载的准确性以及确保bss段等有它所应有的值。
如果能够在代码中把所有的库函数调用去掉,就可以在ads或者rvds环境下去掉库函数的包,把代码尺寸减小1k多。
另外根据lz的描述,只是光标移到了LDR     PC, UndefinedAddr这一行上,而实际并没有执行这句,只是因为指令预取的存在,这条指令只是被预取,在执行上一个跳转的时候就已经被抛弃。

使用特权

评论回复
16
原野之狼| | 2010-9-2 23:21 | 只看该作者
__main是由编译器给你增加的代码  主要功能是建立C语言程序运行的软件环境 具体参阅ARM公司的文档 关于这个问题有详细的描述

使用特权

评论回复
17
husion|  楼主 | 2010-9-3 08:29 | 只看该作者
大虾们一点,明白多了~~

使用特权

评论回复
18
tcc8073| | 2010-9-3 08:36 | 只看该作者
要研究一下启动代码和ARM汇编指令,对启动过程有比较完整的了解的话,这个问题就很容易明白了,别人给你解释你也很难明白到点上,只有你在对启动代码有比较深的了解下问问题,别人给你解释你才会有大的收获.

使用特权

评论回复
19
armmage| | 2010-9-3 09:03 | 只看该作者
过了一晚 这贴还上榜了啊  楼上所言确实 不过我是被人耻笑为--学ARM还看汇编?

使用特权

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

本版积分规则

16

主题

70

帖子

1

粉丝