3. 编写链接脚本控制内存布局

任务目标

在VxWorks BSP开发中,链接脚本(Linker Script)决定了内核镜像各段(代码段、数据段、BSS段等)在目标板内存中的具体放置位置。本案例要求修改链接脚本,将代码段(.text)放置到指定的Flash/ROM区域,将数据段(.data)放置到指定的RAM区域,并确保BSS段紧随数据段之后。

环境与依赖

  • VxWorks 7 或 VxWorks 6.9+ BSP开发环境
  • 目标架构:以ARM Cortex-A9为例(不同架构语法略有差异,但原理相同)
  • 需要修改的文件:BSP目录下的 linkerScript.ld(或 linker.cmd,取决于BSP模板)

关键实现

以下链接脚本将内存划分为两个区域:FLASH(起始地址0x00000000,大小1MB)用于存放代码段和只读数据;RAM(起始地址0x80000000,大小256MB)用于存放可读写数据。通过>FLASH和>RAM指令将各段显式映射到对应内存区域。

/* linkerScript.ld - 控制内存布局 */
ENTRY(_start)

MEMORY
{
    /* 指定内存区域:名称、起始地址、长度 */
    FLASH (rx)  : ORIGIN = 0x00000000, LENGTH = 1M
    RAM   (rwx) : ORIGIN = 0x80000000, LENGTH = 256M
}

SECTIONS
{
    /* 代码段:放置在FLASH区域 */
    .text :
    {
        *(.text*)
        *(.rodata*)
        *(.got*)
    } > FLASH

    /* 数据段:放置在RAM区域 */
    .data :
    {
        __data_start = .;
        *(.data*)
        __data_end = .;
    } > RAM

    /* BSS段:紧随数据段之后,仍位于RAM */
    .bss :
    {
        __bss_start = .;
        *(.bss*)
        *(COMMON)
        __bss_end = .;
    } > RAM

    /* 堆栈区域:放置在RAM末尾 */
    .stack (NOLOAD) :
    {
        __stack_start = .;
        . = . + 0x10000;  /* 64KB栈空间 */
        __stack_end = .;
    } > RAM
}

编译与集成

  1. 将上述脚本内容替换BSP中原始的链接脚本文件。
  2. 在BSP的 config.h 或 Makefile 中确认链接脚本路径被正确引用(通常通过 LDSCRIPT 变量指定)。
  3. 重新编译BSP:make clean && make(或使用Workbench的Build菜单)。

验证方法

编译完成后,通过以下方式验证内存布局是否符合预期:

  • 检查map文件:编译生成的 vxWorks.map 文件中,查看 .text 段的起始地址应位于 0x00000000 附近(FLASH区域),.data 段的起始地址应位于 0x80000000 附近(RAM区域)。
  • 查看符号地址:在map文件中查找 __data_start 和 __bss_start 的地址,确认它们均落在RAM区域内。
  • 运行验证:将镜像烧录到目标板后,在VxWorks shell中执行 lkup 命令查看内核模块加载地址,或使用 d 命令检查指定内存地址的内容,确认代码在Flash中执行、数据在RAM中读写正常。

通过条件:map文件中各段地址与MEMORY指令定义的区域一致;目标板启动后系统正常运行,无内存访问异常。

常见问题

  • 启动时数据段未初始化:若代码段在Flash中而数据段在RAM中,必须在启动代码(sysInit或romInit)中增加将 .data 从Flash拷贝到RAM的步骤(使用 __data_start/__data_end 符号定位),否则RAM中的数据无初始值。
  • 地址溢出:若代码段超过FLASH区域长度(1MB),链接会报错。此时需增大FLASH的LENGTH或优化代码体积。
  • 缓存一致性:若代码在Flash中执行,需确保MMU配置中该区域被标记为可执行且缓存属性正确(通常设为写保护+缓存使能)。