Run-time和Load-time初始化

本文介绍了CCS中Linker选项卡的AutoinitModel设置,包括Run-Time与Load-Time初始化的区别及应用场景。Run-Time初始化在c_int00中进行,适用于有Flash存储的情况;Load-Time初始化则在加载程序同时完成,节省RAM资源。

 

Run-timeload-time初始化

CCSbuild options中的linker选项卡中,Autoinit Model有两个选项:Run-Time AutoinitializationLoad-Time Initialization。本文简单介绍一下这两个选项的区别和用法。

因为这两个选项和.cinit.bss Section有关,所以先简单的介绍一下这两个section相关的知识。从C语言的角度来看的话,.bss section是用来存放C语言中的全局变量的。而.cinit则用来存放全局变量的初始值。例如如果有下面的全局变量buf的话,

short buf[4] = {0x01, 0x02, 0x03, 0x04};

那么buf放在.bss中,而初始值0x01, 0x02, 0x03, 0x04放在.cinit中。.cinit中储存的实际上是一个copy table,它对于每个需要初始化的全局变量,都有一个复制项与之对应,以55x系为例,上面的这段程序产生的复制项为:

00 04 00 12 34 00 00 01 00 02 00 03 00 04 
----- ----------- ------------------------
  1        2                    3     

<!--[if !supportLists]-->1.      <!--[endif]-->复制的word

<!--[if !supportLists]-->2.      <!--[endif]-->复制的目标地址,也就是buf的地址(这里假设为0x1234)

<!--[if !supportLists]-->3.      <!--[endif]-->要复制的数据,也就是初始化数据0x01, 0x02, 0x03, 0x04

那么对于这个.cinit中的copy table具体由谁来完成复制操作呢,这样就有了Load-TimeRun-Time的这两个选择。

先来看看Run-Time Autoinitialization。这段英文的的意思是“运行时初始化”,实际上就是在main函数之前被运行的c_int00中的一段代码完成这个复制工作。我们知道c_int00是用来初始化C语言程序运行所需要的环境的,这个初始化的一部分就是初始化全局变量的初始值。因此在c_int00中初始化全局变量是理所当然的。

然而这样做存在一个问题:.cinit中的copy table只在c_int00中用一次,如果把它放在DSPon chip RAM中的话,实在是太浪费了。因此通常的做法是将.cinit放到flash内存中。假设系统没有flash内存,而是采用的serial boot之类的启动方式,由别的芯片通过McBSPDSP的程序传输到DSP中的话,我们就不得不把.cinit放到RAM中了。如果初始化数据很多的话,显然是非常浪费内存的。为了解决这个问题,可以采用Load-Time Initialization

所谓Load-Time Initialization,就是在将程序loadDSP内存的同时,初始化.bss中的全局变量。我们以55x系列的serial boot为例来解释一下Load-Time Initializationout文件的格式比较复杂,所以通常都是先通过hex5x工具将out文件转化为一个boot table格式的文件,然后通过DSP ROM中的boot程序接收并分析这个boot table完成各个section的初始化工作,最后跳转到c_int00运行。boot table的格式和.cinit中的copy table类似,都有复制个数,目标地址以及需要复制的数据。例如下图是hex5x产生的boot table的格式。

DSP ROM中的serial boot程序一边接收这个boot table的数据一边将数据复制到相应的地址中去。因此如果能将.cinit中的copy table转换到boot table中去的话,就不需要在c_int00中对.cinit进行操作了,也就不需要额外的内存用来储存.cinit了。只要选择了Load-Time Initialization选项,这个工作就都由计算机自动完成了。我们来看看它具体是如何做的。

当以Load-Time Initialization方式对项目进行link的时候,linker会在输出的out文件中的.cinitsection header中添加一个STYP_COPY标签。这个标签会改变hex5x工具对这个section的操作。也就是说当hex5x发现某个section header中有STYP_COPY标签的话,它就把这个section中的数据当作copy table一项一项添加到boot table中去了。因此最终产生的boot table不是将整个.cinit复制到DSP的内存中,而是将.cinit中的每个复制项复制到.bss相应的位置。这样就在boot load的同时完成了全局变量的初始化工作。

 

 

 

### 关于CVI运行代码关闭后出现fatal run-time error错误的原因及解决方案 在使用LabWindows/CVI(简称CVI)开发应用程序时,如果程序在关闭时出现“fatal run-time error”错误,通常是由以下几种原因引起的[^1]: #### 1. 资源未正确释放 程序中可能存在未正确释放的资源,例如文件句柄、动态分配的内存或图形界面组件等。当程序关闭时,这些未释放的资源可能导致运行时错误。确保所有动态分配的资源在程序退出前都被正确释放[^2]。 #### 2. 回调函数未正确清理 如果程序中定义了回调函数(如按钮点击事件、定时器事件等),但在程序退出时未正确注销这些回调函数,可能会导致运行时错误。需要确保在程序关闭前调用适当的函数来注销这些回调[^3]。 #### 3. 全局变量或静态变量未正确初始化或销毁 全局变量或静态变量可能在程序关闭时触发某些操作,例如析构函数或清理函数。如果这些操作依赖于已释放的资源或无效的状态,可能会引发致命错误。因此,需要检查全局变量静态变量的生命周期管理[^4]。 #### 4. 线程未正确结束 如果程序中使用了多线程,并且某些线程在程序关闭时仍未正常结束,可能会导致运行时错误。确保在程序退出前,所有线程都已安全退出[^5]。 #### 解决方案示例代码 以下是一个简单的代码示例,展示如何在程序关闭时正确释放资源清理回调函数: ```c #include <cvirte.h> /* CVI Run-Time Library Header */ #include <userint.h> /* User Interface Library Header */ void CleanupResources(void) { // 确保所有资源被正确释放 CloseAllFiles(); // 假设这是一个自定义函数,用于关闭所有打开的文件 FreeDynamicMemory(); // 假设这是一个自定义函数,用于释放动态分配的内存 } void UnregisterCallbacks(void) { // 注销所有回调函数 UnregisterButtonCallback(buttonID); // 假设buttonID是某个按钮的ID UnregisterTimerCallback(timerID); // 假设timerID是某个定时器的ID } int main(void) { if (LoadPanel(0, "MyPanel.uir", PANEL) < 0) return -1; DisplayPanel(PANEL); while (GetNextEvent() != QUIT_EVENT) ; // 在程序关闭前进行清理操作 CleanupResources(); UnregisterCallbacks(); DiscardPanel(PANEL); return 0; } ``` #### 5. 检查第三方库或插件 如果程序中使用了第三方库或插件,这些库可能在程序关闭时执行某些操作,从而引发错误。需要仔细检查第三方库的文档,确保其提供的资源释放函数在程序退出前被正确调用[^6]。 #### 6. 使用调试工具 可以使用CVI自带的调试工具或第三方调试工具(如Valgrind)来检测程序中的内存泄漏或其他潜在问题。通过这些工具,可以更精确地定位导致“fatal run-time error”的原因[^7]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值