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