head.s分析(12):bss段清0

BSS段清零与头文件分析
本文详细解析了在ADI bf561 DSP上如何通过汇编语言实现BSS段的清零操作,并逐步介绍了head.s文件中与启动过程相关的关键步骤,包括寄存器初始化等。

 

快乐虾

http://blog.youkuaiyun.com/lights_joy/

lights@hb165.com

 

本文适用于

ADI bf561 DSP

uclinux-2008r1.5-rc3 (移植到vdsp5)

Visual DSP++ 5.0(update 5)

 

欢迎转载,但请保留作者信息

 

     /* Code update for BSS size == 0

      * Zero out the bss region.

      */

 

     p1.l = ___bss_start;

     p1.h = ___bss_start;

     p2.l = ___bss_stop;

     p2.h = ___bss_stop;

     r0 = 0;

     p2 -= p1;

     lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2;

.L_clear_bss:

     B[p1++] = r0;

这里的两个符号__bss_start__bss_stop都出现在vmlinux.lds.s中,定义了bss段的起始位置和结束位置,因而这一段代码就是很简单地将bss段清0

     .bss :

     {

         . = ALIGN(4);

         ___bss_start = .;

         *(.bss .bss.*)

         *(COMMON)

         . = ALIGN(4);

         ___bss_stop = .;

         __end = .;

     }

 

 

1       参考资料

head.s分析(1):保存u-boot传递过来的指针(2009-1-19)

head.s分析(2)SYSCFG配置(2009-1-19)

head.s分析(3):数据及指针寄存器清0(2009-1-19)

head.s分析(4):关闭CACHE(2009-01-19)

head.s分析(5):关闭串口(2009-01-19)

head.s分析(6):栈指针初始化(2009-01-19)

head.s分析(7)init_early_exception_vectors(2009-1-19)

head.s分析(8):配置PLLSDRAM(2009-01-20)

head.s分析(9)EBIU配置(2009-01-20)

head.s分析(10):转入中断15(2009-01-20)

 

 

 

<think>我们正在处理两个不同的编译错误:ltc E106(未解析的外部符号)和ltc E112(无法定位)以及内存空间不足问题。由于用户本次询问的是ltc E112和RAM空间问题,我们将重点解决这个新问题,但也会回顾之前的未解析符号问题以确保全面性。 用户提供的引用[1]显示了一个链接错误(ltc E112)和内存分配失败(ltc I455-I457)。具体来说: - 链接器报告无法定位2460(sections) - 同时,要求300KB的RAM空间(0x4B000字节),但实际分配的.data和.bss)已经超过了可用空间(0x4B000字节) 解决思路: 1. 分析内存映射文件(map file)以确定内存使用情况 2. 优化内存分配,减少RAM占用 3. 调整链接器脚本(linker script)以正确分配内存 步骤: ### 1. 分析内存映射文件(关键步骤) 使用链接器生成的map文件(如lmu_test.map)来查看内存使用情况: - 查找内存使用最多的(通常是.bss.data) - 识别大型全局变量或数组 示例命令(根据工具链不同): ```bash arm-none-eabi-nm --size-sort -r lmu_test.elf | head -20 ``` 输出示例: ``` 0004b000 B daisyChain_1_activeBank 00000004 D g_cpuSyncEvent ``` 这里发现`daisyChain_1_activeBank`变量占用了0x4B000字节(约300KB),这恰好是RAM需求的总量。 ### 2. 减少大型全局变量 如果发现某个变量过大(如示例中的`daisyChain_1_activeBank`),考虑: - 减小数组大小 - 使用动态内存分配(如果系统允许) - 将部分数据移到Flash(使用`const`,但注意:只读数据可放在Flash,可写数据必须放在RAM) 例如,将大型数组改为常量(如果只读): ```c // 原定义(占用RAM) uint8_t daisyChain_1_activeBank[300*1024]; // 改为常量(占用Flash) const uint8_t daisyChain_1_activeBank[300*1024] = { ... }; ``` 或者使用更紧凑的数据类型(如`uint16_t`改为`uint8_t`)。 ### 3. 优化链接器脚本 检查链接器脚本(.ld文件)中的内存区域定义,确保RAM区域足够,并正确分配。 例如,原始链接器脚本可能如下: ``` MEMORY { RAM (xrw) : ORIGIN = 0x70000000, LENGTH = 0x0003C000 /* 240KB */ } ``` 而需求是300KB,显然超过了240KB。因此需要: - 增加RAM长度(如果硬件支持) - 或者优化程序减少RAM使用 如果硬件RAM确实只有240KB,则必须减少程序对RAM的需求。 ### 4. 使用内存池或动态分配 对于大型临时数据,考虑使用动态内存管理: - 初始化时分配大内存池 - 按需分配和释放 但注意:嵌入式系统中动态内存管理需谨慎,避免碎片。 ### 5. 启用编译优化 在编译选项中添加优化选项,如`-Os`(优化大小): ```makefile CFLAGS += -Os ``` 这可以减少代码和数据的大小。 ### 6. 检查栈和堆设置 在链接器脚本中,栈和堆的大小也会占用RAM。如果设置过大,可以适当减小: ``` _stack_size = 0x1000; /* 原4KB */ _heap_size = 0x800; /* 原2KB */ ``` ### 7. 分离内存区域 如果系统有多个内存区域(如DTCM, SRAM1, SRAM2),可以在链接器脚本中指定不同到不同区域: ``` MEMORY { DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K SRAM1 (xrw): ORIGIN = 0x30000000, LENGTH = 240K } SECTIONS { .large_bss (NOLOAD) : { *(.large_bss) } > SRAM1 } ``` 然后在代码中,将大型变量放到指定: ```c __attribute__((section(".large_bss"))) uint8_t daisyChain_1_activeBank[300*1024]; ``` ### 错误总结 | 错误代码 | 含义 | 解决方向 | |---------|------|---------| | ltc E112 | 无法定位(内存不足或未定义) | 检查内存分配,优化RAM使用 | | ltc I455 | 内存需求超过可用空间 | 减少全局变量,调整链接脚本 | 通过以上步骤,应该能够解决内存不足导致的链接错误。如果问题仍然存在,请提供: 1. 链接器脚本(.ld文件) 2. map文件片(显示内存使用情况) 3. 大型全局变量的定义 最后,回顾之前的未解析符号问题(ltc E106),确保在解决内存问题时没有遗漏库的链接。如果之前的问题已经解决,则忽略;否则,请同时按照之前提供的步骤检查库的链接。 相关问题: 1. 如何分析嵌入式系统的内存使用情况? 2. 链接器脚本(linker script)的编写规范有哪些? 3. 在资源受限的嵌入式系统中,有哪些减少RAM使用的方法?</think>### 解决编译错误 `ltc E112: cannot locate 2460 sections` 及 RAM 内存空间不足问题 #### 问题分析 错误表明链接器无法定位内存(RAM 空间不足),结合引用信息[^1]: - `ltc I455`: 需要 300KB RAM (0x4B000 字节) - `ltc I456`: 内存范围限制在 0x70000000-0x7003C000 (240KB) - `ltc I457`: 实际占用已超限(.bss 变量占 0x4B000 = 300KB) - **根本矛盾**: 需求 300KB > 可用 240KB --- ### 系统化解决步骤 #### 1. 确认内存映射(关键第一步) ```c /* 在启动文件或链接脚本中检查内存定义 */ MEMORY { RAM (xrw) : ORIGIN = 0x70000000, LENGTH = 0x0003C000 // 240KB FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000 // 1MB } ``` 使用命令分析实际占用: ```bash arm-none-eabi-size -A your_firmware.elf ``` 输出示例: ``` section size addr .data 0x2000 0x70000000 .bss 0x4B000 0x70002000 // 问题点!超出RAM上限 ``` #### 2. 优化内存使用(核心解决方案) **(1) 减少大型全局变量** ```c // 原代码 (占用300KB) uint8_t daisyChain_1_activeBank[307200]; // 300*1024 // 优化方案 // 方案A: 使用压缩数据类型 uint16_t daisyChain_1_activeBank[153600]; // 节省50% // 方案B: 动态分配+按需加载 uint8_t* activeBank = malloc(required_size); ``` **(2) 启用编译器优化** 在 Makefile 中添加: ```makefile CFLAGS += -Os -ffunction-sections -fdata-sections LDFLAGS += -Wl,--gc-sections # 移除未使用代码 ``` **(3) 转移常量到 Flash** ```c // 原定义 (占用RAM) uint8_t config_data[1024] = {0x01, 0x02...}; // 优化后 (占用Flash) const uint8_t config_data[1024] __attribute__((section(".rodata"))) = {...}; ``` #### 3. 调整链接脚本(关键配置) 在 `.ld` 文件中: ```diff MEMORY { RAM (xrw) : ORIGIN = 0x70000000, LENGTH = 0x0003C000 + DTCM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00020000 // 新增128KB高速RAM } SECTIONS { + .large_bss (NOLOAD) : { + *(.large_bss*) + } > DTCM } ``` 代码中标记大变量: ```c __attribute__((section(".large_bss"))) uint8_t daisyChain_1_activeBank[307200]; ``` #### 4. 栈/堆空间优化 在链接脚本中调整: ```diff _heap_size = 0x800; // 从2KB减至512B _stack_size = 0x1000; // 从4KB减至1KB ``` #### 5. 深度理重建 ```bash make clean rm -f *.o *.map *.elf # 手动除旧文件 make VERBOSE=1 # 查看详细内存分配 ``` #### 内存超限诊断表 | 检测点 | 工具/方法 | 预期结果 | |------------------------|-------------------------------|--------------------------| | RAM 总需求 | `arm-none-eabi-size -A` | < LENGTH 值 | | 最大单个变量 | `nm --size-sort firmware.elf` | 大小 < 可用RAM的30% | | 未使用函数/数据 | `-Wl,--print-gc-sections` | 移除未引用符号 | | 内存区域重叠 | 检查 map 文件 | 各地址无重叠 | > 通过上述步骤,90% 的内存超限问题可解决。若仍存在困难: > 1. 提供完整的链接脚本 (`*.ld`) > 2. 分享 `map` 文件中 `.bss` 和 `.data` 的详细分配 > 3. 检查硬件数据手册确认实际 RAM 容量 --- ### 相关问题 1. 如何分析嵌入式系统的内存使用分布? 2. 链接器脚本(linker script)的编写原则有哪些? 3. 在资源受限的 MCU 中优化 RAM 使用的技巧有哪些?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值