- 一上电的时候,首先运行的是片内固化的ROM程序,片内ROM直接映射到CPU地址空间中,CPU上电后首先运行ROM程序
- 片内ROM固化的程序会从设定的启动存储器(如:flash/SD等)中读取我们烧写的程序,并拷贝到烧写的程序头部信息描述的内存地址上(链接地址)
- 对于6ULL/157之类性能较强劲的芯片,是怎么运行程序的呢?
- lid.imx的头部指定片内ROM程序要将led.bin拷贝到内存中的哪个地址、拷贝多长
- 对于157也是类似的操作
- 头部信息的地址是链接时指定的(这是程序运行时应该位于的地址)
- 无论6ull还是157,程序运行之前都有片内ROM程序将其读取到内存中的指定地址;但是不要认为读取程序到内存的指定地址这个操作是理所当然得,很多芯片并没有那么强大的片内ROM(如:F103),需要我们程序本身实现该拷贝功能。
- JZ2440支持多种启动方式:Nand/Nor Flash
- Nand启动时,Nand前4k程序会被读入内存,然后从内存中开始运行;当我们程序大于4K时,则我们程序本身就需要从Nand上读取程序到内存中指定位置(利用前4k自动读入内存的程序来操作)
- 所以说,一个程序在运行之前位于它应该位于的地方是理所当然的
- 6ULL/157已经由片内ROM将程序拷贝到它们应该位于的地方(加载地址),但我们也可以修改其应该位于的地方(链接地址)与片内ROM拷贝到的地方(加载地址)不一致,从而可以将其从原地址(加载地址)再次拷贝到目的地址(链接地址)上
- 记住,链接地址和加载地址是不一样的;加载地址是烧写在存储器中的头部信息里的地址,在编译时由相应工具(mkimage)指定;而链接地址则是在链接时由链接脚本指定,隐含于程序本身
- 指定链接地址要先于指定加载地址
- 当加载地址设置与链接地址相同时,可以不需要再次进行代码重定位
- 链接完成后得到bin文件,其中bin文件的程序还有的就是链接地址;bin文件再添加头部信息从而指定加载地址
- 如果不进行重定位,会发生什么事?
- 全局变量的地址位于链接地址上,不进行重定位将会导致数据错乱
- 所以基于地址的函数调用将错误(使用函数指针的方式调用)
- 字符串保存在rodata段,也位于链接地址上,所以不能使用字符串
- 单个const字符,编译器可能直接优化为立即数,所以可以使用
- 凡是涉及内存操作的,都可能需要进行重定位
- 一个程序,至少可以分为这几段:
- 代码段(RO-CODE):就是程序本身,不会被修改
- 可读可写的数据段(RW-DATA):有初始值的全局变量、静态变量,需要从ROM上复制到内存
- 只读的数据段(RO-DATA):可以放在ROM上,不需要复制到内存
- BSS段或ZI段:
- 初始值为0的全局变量或静态变量,没必要放在ROM上,使用之前清零就可以
- 未初始化的全局变量或静态变量,没必要放在ROM上,使用之前清零就可以
- 初始值为0的全局变量或静态变量,没必要放在ROM上,使用之前清零就可以
- 局部变量:保存在栈中,运行时生成
- 堆:一块空闲空间,使用malloc函数来管理它,malloc函数可以自己写
- 代码段(RO-CODE):就是程序本身,不会被修改
- 保存在ROM上的全局变量的值,在使用前要复制到内存,这就是数据段重定位。
- 想把代码移动到其他位置,这就是代码重定位。