keil5编译出现段重复报错:.\Objects\JjProject.sct(7): error L6235E: More than one section matches sele...如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!
  
📌 特别说明: 文中部分技术问题来源于真实生产环境及网络公开案例,均经过精挑细选与系统化整理,并结合多位一线资深架构师和工程师多年实战经验沉淀,提炼出多种经过验证的高可行性解决方案,供开发者们参考与借鉴。
  
欢迎 关注、收藏并订阅本专栏,持续更新的干货内容将与您同行,让我们携手精进,技术跃迁,步步高升!

📢 问题描述

问题来源:https://ask.csdn.net/questions/xxx

问题描述:keil5编译出现段重复报错:.\Objects\JjProject.sct(7): error L6235E: More than one section matches sele…如何解决?

📣 请知悉:如下方案不保证一定适配你的问题!

  如下是针对上述问题进行专业角度剖析答疑,不喜勿喷,仅供参考:

✅️问题理解

根据题主提供的图片信息,您遇到的是Keil5编译器中的链接器脚本错误L6235E

.\Objects\JjProject.sct(7): error L6235E: More than one section matches selector - cannot all be FIRST/LAST.
错误分析:

这个错误表明在您的散布加载描述文件(Scatter-loading Description File,即.sct文件)中,存在多个内存段选择器冲突的问题。具体来说:

  1. FIRST/LAST选择器冲突:在链接器脚本中,有多个内存段都使用了FIRSTLAST属性,但同一类型的选择器在同一个加载域中只能有一个
  2. 内存段重复定义:可能存在相同的内存段被多次定义或引用
  3. 段属性配置错误:在+RO+RW+ZI等属性设置中出现了冲突
问题根本原因:

STM32项目中的内存映射配置错误,导致链接器无法正确分配代码和数据到指定的内存区域。

✅️问题解决方案

方案一:检查并修复.sct文件
; 正确的STM32散布加载文件示例
; JjProject.sct

; 定义加载域 - ROM区域
LR_IROM1 0x08000000 0x00080000  {
    ; 执行域 - FLASH区域  
    ER_IROM1 0x08000000 0x00080000  {
        *.o (RESET, +First)         ; 确保只有一个FIRST
        *(InRoot$$Sections)
        .ANY (+RO)                  ; 所有只读代码和常量
        .ANY (+XO)                  ; 执行代码
    }
    
    ; 执行域 - RAM区域
    RW_IRAM1 0x20000000 0x00020000  {
        .ANY (+RW +ZI)              ; 读写和零初始化数据
    }
}

; 如果有其他特殊内存区域(如CCM RAM)
LR_IRAM2 0x10000000 0x00010000  {
    RW_IRAM2 0x10000000 UNINIT 0x00010000  {
        .ANY (+ZI)                  ; 仅零初始化数据
    }
}
方案二:使用Keil5默认内存配置

如果自定义配置有问题,可以先使用Keil5的默认配置:

步骤1:删除或重命名当前.sct文件
# 将JjProject.sct重命名为JjProject.sct.bak
步骤2:在Keil5中重新配置内存
  1. 右击项目 → Options for Target
  2. 选择Linker选项卡
  3. 取消勾选Use Memory Layout from Target Dialog
  4. Target选项卡中重新配置内存映射
步骤3:STM32典型内存配置
// 在Target选项中设置
ROM1: 
    Start: 0x08000000
    Size:  0x80000      // 512KB Flash

RAM1:
    Start: 0x20000000  
    Size:  0x20000      // 128KB RAM
方案三:手动修复具体错误

基于您的错误信息,重点检查第7行附近的代码:

; 错误示例(需要修复)
LR_IROM1 0x08000000 0x00080000  {
    ER_IROM1 0x08000000 0x00080000  {
        *.o (RESET, +First)     ; 第一个FIRST
        *.o (STARTUP, +First)   ; 错误:第二个FIRST - 这里会报错
        .ANY (+RO)
    }
}

; 正确修复后
LR_IROM1 0x08000000 0x00080000  {
    ER_IROM1 0x08000000 0x00080000  {
        *.o (RESET, +First)     ; 只保留一个FIRST
        *.o (STARTUP)           ; 移除+First属性
        .ANY (+RO)
    }
}
方案四:使用图形化配置工具
// 使用STM32CubeMX重新生成项目配置
// 1. 打开STM32CubeMX
// 2. 选择对应的STM32芯片型号
// 3. 配置外设和时钟
// 4. 生成Keil5项目
// 5. 使用生成的.sct文件替换当前文件
方案五:完整的调试步骤
// 1. 备份当前项目
// 2. 清理编译输出
#include "stm32f4xx.h"

// 3. 创建最小化的.sct文件进行测试
LR_IROM1 0x08000000 0x00020000  {    ; 减小ROM大小进行测试
    ER_IROM1 0x08000000 0x00020000  {
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
    }
    RW_IRAM1 0x20000000 0x00005000  { ; 减小RAM大小进行测试
        .ANY (+RW +ZI)
    }
}

// 4. 逐步增加内存大小和功能模块

✅️问题延伸

1. STM32内存映射深入理解
STM32内存空间
Flash存储器区域
0x08000000-0x080FFFFF
SRAM区域
0x20000000-0x2001FFFF
外设区域
0x40000000-0x5FFFFFFF
Cortex-M4系统区域
0xE0000000-0xFFFFFFFF
代码段 .text
常量段 .rodata
数据段 .data
BSS段 .bss
堆栈 Stack/Heap
2. 散布加载文件语法详解
; 加载域语法
LoadRegion_Name base_address max_size [attributes] {
    ; 执行域语法  
    ExecRegion_Name base_address [attributes] [max_size] {
        ; 输入段描述
        module_selector(section_selector, [attributes])
        .ANY (+RO)      ; 任意只读段
        .ANY (+RW)      ; 任意读写段
        .ANY (+ZI)      ; 任意零初始化段
    }
}

; 常用属性说明
; +First      - 必须放在执行域开始位置
; +Last       - 必须放在执行域结束位置  
; +RO         - 只读属性(代码和常量)
; +RW         - 读写属性(已初始化数据)
; +ZI         - 零初始化属性(未初始化数据)
; +XO         - 执行代码属性
; UNINIT      - 不初始化属性
3. 常见的段属性冲突场景
; 场景1:多个FIRST冲突
*.o (RESET, +First)     ; 第一个FIRST
*.o (STARTUP, +First)   ; 错误:重复的FIRST

; 场景2:段地址重叠
ER_IROM1 0x08000000 0x00080000 { }
ER_IROM2 0x08040000 0x00080000 { }  ; 错误:地址重叠

; 场景3:大小超出限制  
RW_IRAM1 0x20000000 0x00020000 {
    .ANY (+RW +ZI)      ; 如果实际需要超过128KB就会出错
}
4. 高级内存配置技巧
; 支持多Bank Flash的配置
LR_IROM1 0x08000000 0x00100000 {
    ; Bank1: 引导代码
    ER_IROM1 0x08000000 0x00080000 {
        *.o (RESET, +First)
        bootloader.o (+RO)
    }
    
    ; Bank2: 应用代码  
    ER_IROM2 0x08080000 0x00080000 {
        application.o (+RO)
        .ANY (+RO)
    }
    
    ; 快速访问RAM
    RW_IRAM1 0x20000000 0x00020000 {
        critical_data.o (+RW +ZI)
        .ANY (+RW +ZI)
    }
    
    ; CCM RAM(仅数据,不能执行代码)
    RW_IRAM2 0x10000000 UNINIT 0x00010000 {
        buffer.o (+ZI)
    }
}

✅️问题预测

1. 内存不足问题预测
可能出现的问题:
  • 代码量增长导致Flash空间不足
  • 全局变量过多导致RAM空间不足
  • 堆栈溢出导致程序异常
预防措施:
// 内存使用监控代码
#include "stm32f4xx.h"

// 获取堆栈使用情况
uint32_t get_stack_usage(void) {
    extern uint32_t _estack;    // 栈顶地址
    uint32_t stack_top = (uint32_t)&_estack;
    uint32_t current_sp;
    
    __asm volatile ("mov %0, sp" : "=r" (current_sp));
    return stack_top - current_sp;
}

// 获取堆使用情况  
uint32_t get_heap_usage(void) {
    extern uint32_t _heap_start;
    extern uint32_t _heap_end;
    
    return (uint32_t)&_heap_end - (uint32_t)&_heap_start;
}

// 在主函数中监控
int main(void) {
    // 初始化代码...
    
    while(1) {
        uint32_t stack_used = get_stack_usage();
        uint32_t heap_used = get_heap_usage();
        
        // 发送到调试串口或存储
        printf("Stack used: %lu bytes\n", stack_used);
        printf("Heap used: %lu bytes\n", heap_used);
        
        HAL_Delay(1000);
    }
}
2. 多核心处理器适配问题
预测场景:
  • 从单核STM32迁移到双核STM32H7系列
  • 需要为不同核心分配独立的内存区域
解决方案:
; STM32H7双核内存配置示例
; Cortex-M7核心配置
LR_IROM1 0x08000000 0x00100000 {
    ER_IROM1 0x08000000 0x00100000 {
        *.o (RESET, +First)
        m7_code.o (+RO)         ; M7专用代码
        .ANY (+RO)
    }
    
    ; M7专用RAM
    RW_IRAM1 0x20000000 0x00020000 {
        m7_data.o (+RW +ZI)
    }
}

; Cortex-M4核心配置  
LR_IROM2 0x08100000 0x00100000 {
    ER_IROM2 0x08100000 0x00100000 {
        m4_code.o (+RO)         ; M4专用代码
    }
    
    ; M4专用RAM
    RW_IRAM2 0x30000000 0x00048000 {
        m4_data.o (+RW +ZI)
    }
}

; 共享内存区域
LR_SHARED 0x38000000 0x00010000 {
    RW_SHARED 0x38000000 UNINIT 0x00010000 {
        shared_data.o (+ZI)     ; 核心间通信数据
    }
}
3. 编译器版本兼容性问题
可能的问题:
  • Keil5升级后语法变化
  • ARM编译器版本差异导致的链接错误
  • 新版本对内存对齐要求更严格
预防措施:
// 版本兼容性检查
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6000000)
    // ARM Compiler 6.x 配置
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wpadded"
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 5000000)  
    // ARM Compiler 5.x 配置
    #pragma push
    #pragma anon_unions
#endif

// 内存对齐属性
typedef struct {
    uint32_t data1;
    uint16_t data2;
    uint8_t  data3;
} __attribute__((packed)) DataStruct_t;

#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6000000)
    #pragma clang diagnostic pop
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 5000000)
    #pragma pop
#endif

✅️小结

问题核心:

您遇到的L6235E错误是由于Keil5链接器脚本中的段选择器冲突导致的,主要原因是在.sct文件中多个内存段使用了相同的FIRSTLAST属性。

关键解决步骤:
  1. 立即解决方案:检查JjProject.sct文件第7行附近,确保只有一个段使用+First属性
  2. 标准化配置:使用STM32典型的内存映射配置模板
  3. 工具辅助:利用STM32CubeMX重新生成项目配置
  4. 逐步调试:通过最小化配置逐步定位问题
最佳实践要点:
  • 唯一性原则:每个加载域中FIRSTLAST选择器必须唯一
  • 地址对齐:确保内存段地址按照ARM Cortex-M的要求对齐
  • 大小合理:内存段大小不能超过芯片的实际硬件限制
  • 备份策略:修改前务必备份工作版本的配置文件
紧急处理建议:

如果急需解决,建议先删除当前的.sct文件,让Keil5使用默认的内存配置,然后重新编译。这样可以快速恢复编译功能,后续再优化内存布局。

代码审查要点:
  • 检查是否有重复的+First+Last属性
  • 验证内存地址范围是否与STM32芯片手册一致
  • 确认代码段和数据段的大小在合理范围内

这个问题虽然看起来复杂,但按照系统化的方法排查,通常可以快速解决。关键是理解STM32的内存架构和Keil5链接器的工作原理。

  希望如上措施及解决方案能够帮到有需要的你。

  PS:如若遇到采纳如下方案还是未解决的同学,希望不要抱怨&&急躁,毕竟影响因素众多,我写出来也是希望能够尽最大努力帮助到同类似问题的小伙伴,即把你未解决或者产生新Bug黏贴在评论区,我们大家一起来努力,一起帮你看看,可以不咯。

  若有对当前Bug有与如下提供的方法不一致,有个不情之请,希望你能把你的新思路或新方法分享到评论区,一起学习,目的就是帮助更多所需要的同学,正所谓「赠人玫瑰,手留余香」。

🧧🧧 文末福利,等你来拿!🧧🧧

  如上问题有的来自我自身项目开发,有的收集网站,有的来自读者…如有侵权,立马删除。再者,针对此专栏中部分问题及其问题的解答思路或步骤等,存在少部分搜集于全网社区及人工智能问答等渠道,若最后实在是没能帮助到你,还望见谅!并非所有的解答都能解决每个人的问题,在此希望屏幕前的你能够给予宝贵的理解,而不是立刻指责或者抱怨!如果你有更优解,那建议你出教程写方案,一同学习!共同进步。

  ok,以上就是我这期的Bug修复内容啦,如果还想查找更多解决方案,你可以看看我专门收集Bug及提供解决方案的专栏《全栈Bug调优(实战版)》,都是实战中碰到的Bug,希望对你有所帮助。到此,咱们下期拜拜。

码字不易,如果这篇文章对你有所帮助,帮忙给 bug菌 来个一键三连(关注、点赞、收藏) ,您的支持就是我坚持写作分享知识点传播技术的最大动力。

同时也推荐大家关注我的硬核公众号:「猿圈奇妙屋」 ;以第一手学习bug菌的首发干货,不仅能学习更多技术硬货,还可白嫖最新BAT大厂面试真题、4000G Pdf技术书籍、万份简历/PPT模板、技术文章Markdown文档等海量资料,你想要的我都有!

🫵 Who am I?

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bug菌¹

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

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

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

打赏作者

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

抵扣说明:

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

余额充值