本文最后更新于6 天前,其中的信息可能已经过时,如有错误请留言评论。
一、.bss段
与 .data段
的启动初始化机制解析
- 两种段的区别与特性
段名 | 用途 | 是否占ROM空间 | 是否占RAM空间 | 初始化方式 |
---|---|---|---|---|
.bss | 未初始化的全局/静态变量 | ❌ 不占ROM | ✅ 占用RAM | 启动时清0(memset) |
.data | 已初始化的全局/静态变量 | ✅ 初值存在ROM | ✅ 占用RAM | 启动时从ROM复制到RAM |
.rodata
与栈变量说明:
.rodata
:只读常量(如const
或static const
),常驻ROM。- 栈变量(局部变量):程序运行时动态分配,位于栈(Stack)中,不占ROM。
二、启动代码初始化原理
在TC275启动流程中,函数 Ifx_C_Init()
完成 .bss
清零与 .data
段的复制。该函数通常由 _Core0_start()
调用:
void _Core0_start(void)
{
...
Ifx_C_Init(); // 初始化 .data 和 .bss 段
...
__non_return_call(core0_main);
}
三、关键函数 Ifx_C_Init()
实现分析
extern uint32 __clear_table[];
extern uint32 __copy_table[];
.bss段
清零操作
while (pTable)
{
pDest = (uint32*)*pTable++; // RAM地址
length = *pTable++; // 字节数
if (length == 0xFFFFFFFF) break;
memset(pDest, 0, length); // 实际逻辑简化为清0
}
.data段
复制操作
while (pTable)
{
pSrc = (uint32*)*pTable++; // ROM地址(初值)
pDest = (uint32*)*pTable++; // RAM地址
length = *pTable++; // 字节数
if (length == 0xFFFFFFFF) break;
memcpy(pDest, pSrc, length); // 实际逻辑简化为内存复制
}
四、这些地址和长度是从哪里来的?
ld链接脚本(Linker Script)中定义的 __clear_table
和 __copy_table
。
.rodata : FLAGS(arl)
{
*(.rodata*)
...
// 清零表(.bss段)
PROVIDE(__clear_table = .);
LONG(ADDR(.bss)); LONG(SIZEOF(.bss));
...
LONG(-1); LONG(-1); // 终止标志
// 复制表(.data段)
PROVIDE(__copy_table = .);
LONG(LOADADDR(.data)); LONG(ADDR(.data)); LONG(SIZEOF(.data));
...
LONG(-1); LONG(-1); LONG(-1); // 终止标志
}
LOADADDR(.data)
:获取段的ROM地址(初值存放地址)ADDR(.data)
:段的RAM运行地址SIZEOF(.data)
:段的大小
五、如何将函数放入 RAM 执行(可执行代码段搬移)
- 用
#pragma section
指定段名
#pragma section ".my_ram_fun" ax
void fast_func(void) { ... }
#pragma section
- 在链接脚本中定义此段及其复制行为
.CPU0.psram_text :
{
. = ALIGN(8);
*(.my_ram_fun*)
} > RAM_PSRAM AT> ROM_FLASH
CORE_SEC(.psram_text) :
{
. = ALIGN(8);
*(.my_ram_fun)
} > RAM_PSRAM AT> ROM_FLASH
上边两段 Linker Script 的写法在表达相似意图——将 .
my_ram_fun段内容链接到 RAM_PSRAM 段,但存在一些关键语法和行为差异。
CORE_SEC(...)
是某些多核支持的链接脚本宏/语法(比如 TI C2000 / Infineon AURIX 系列工具链)中,用于生成核特定的段,并带有访问权限标记(FLAGS(awx)
表示 可读写、可执行)。.CPU1.psram_text1
是普通的段名,自定义的 Section,直接定义而已。
所以,CORE_SEC(...)
通常是编译器工具链扩展语法,用于支持多核链接;而 .CPU1.psram_text1
是标准 GNU Linker Script 的命名段。
- 在
.rodata
段中加入该段对应的 copy_table 项:
LONG(LOADADDR(.CPU0.psram_text));
LONG(ADDR(.CPU0.psram_text));
LONG(SIZEOF(.CPU0.psram_text));
程序启动时就会自动从 ROM 复制此函数到 RAM 中运行。
六、总结:__clear_table
与 __copy_table
的作用
表名 | 功能 | 定义位置 | 启动操作 |
---|---|---|---|
__clear_table | 清零 .bss 段 | Linker Script | 将目标地址内存清0 |
__copy_table | 复制 .data 段等段 | Linker Script | 将数据从 ROM 拷贝到 RAM 初始化 |
七、内存初始化流程图
A[上电复位]
A –> B[执行 _Core0_start()]
B –> C[调用 Ifx_C_Init()]
C –> D[读取 __clear_table]
D –> E[清空.bss段的RAM空间 (memset)]
C –> F[读取 __copy_table]
F –> G[从ROM读取.data初值]
G –> H[拷贝到RAM指定地址]
H –> I[执行 main()]