GNU编译器(GCC):编译的4个过程及.elf、.list、.map文件功能说明

0 参考资料

GNU-LD-v2.30-中文手册.pdf
GNU linker.pdf

1 前言

一个完整的编译工具链应该包含以下4个部分:
(1)编译器
(2)汇编器
(3)链接器
(4)lib库
在GNU工具链中,对应的是:
(1)编译器:GCC(GNU Compiler Collection,GNU编译器套件)
(2)汇编器:GAS(GNU Assembler,GNU汇编器)
(3)链接器:LD(GNU Linker,GNU链接器)
(4)lib库:glibc(GNU C Library,GNU C 库)
本文介绍GNU编译器(GCC)编译的4个过程及.elf、.list、.map文件功能。

2 GNU编译器(GCC):编译的4个过程及.elf、.list、.map文件功能说明

<think>我们面对的问题是:在STM32CubeIDE 1.8.0中编译时出现`undefined reference to 'IIR1D_init'`和`undefined reference to 'IIR1D_update'`的错误,但是这两个函数在`.list`文件里有出现。这表明链接器在链接阶段没有找到这两个函数的实现。 根据错误信息,问题可能出在以下几点: 1. **源文件编译**:包含这两个函数实现的源文件(例如`IIR1D.c`)没有被添加到项目中,或者没有被正确编译。 2. **链接顺序问题**:可能链接器在链接目标文件时,包含这两个函数的源文件在链接顺序中出现在调用它们的文件之后,导致链接器无法解析引用(这种情况在GCC中较少见,因为GCC链接器通常可以处理无序的引用)。 3. **函数声明与定义不一致**:头文件中的函数声明与函数定义不一致(例如,参数类型、返回值类型、函数名拼写等),导致目标文件中生成的符号与调用处引用的符号不一致。 4. **符号可见性问题**:可能在函数定义处使用了`static`关键字,或者使用了编译器特定的属性,使得函数符号没有被导出。 5. **编译器优化**:如果编译器优化选项设置不当,可能会将未使用的函数优化掉(但在本例中,函数被调用了,所以不应该被优化)。 6. **目标文件损坏**:目标文件可能没有正确生成。 由于你提到这两个函数在`.list`文件中出现,`.list`文件通常是汇编列表文件,这表明编译器确实生成了这两个函数的代码(在汇编阶段可以看到)。但是链接器报错,说明在链接阶段,链接器没有在目标文件中找到这两个符号,或者找到的符号与调用处引用的符号不一致。 因此,我们重点检查以下几点: ### 1. 检查源文件是否编译并链接 - 在STM32CubeIDE的Project Explorer中,确认`IIR1D.c`(或包含这两个函数的源文件)已经被添加到项目中,并且属于当前构建配置(例如Debug或Release)的源文件组。 - 查看构建控制台输出,确认在编译过程中有编译`IIR1D.c`的步骤,并且没有报错。 - 如果`IIR1D.c`没有被编译,需要将它添加到项目中:右键点击项目 -> Properties -> C/C++ General -> Paths and Symbols -> Source Location -> 确保包含该文件文件夹在Source Folder中,或者直接将文件拖到项目的对应文件夹中。 ### 2. 检查函数声明和定义是否一致 - 打开`IIR1D.h`(声明这些函数的头文件)和`IIR1D.c`(定义这些函数的源文件),仔细比对函数声明和定义是否一致。特别注意: - 函数名拼写(大小写、下划线等) - 参数类型和数量 - 返回值类型 - 是否使用了`static`关键字(在头文件中声明时不应该有`static`,在定义时也不应该有`static`,除非是内部函数) 例如,头文件中的声明: ```c void IIR1D_init(IIR1D_Filter* filter, const float* numerator, const float* denominator, int order); float IIR1D_update(IIR1D_Filter* filter, float input); ``` 源文件中的定义必须与之一致。 ### 3. 检查链接器脚本和符号表 - 链接器脚本是否配置正确?通常STM32CubeIDE会自动生成链接器脚本,但如果你有自定义链接器脚本,请确保它包含了必要的内存区域。 - 检查链接器映射文件(通常在Debug或Release目录下,扩展名为`.map`)。在映射文件中搜索`IIR1D_init`和`IIR1D_update`,看它们是否被链接到最终的可执行文件中。如果映射文件中存在这两个符号,那么链接器应该不会报错。如果没有,则说明包含这两个函数的对象文件没有链接进去。 ### 4. 检查编译选项 - 在项目属性中,检查`C/C++ Build` -> `Settings` -> `Tool Settings` -> `MCU GCC Compiler` -> `Symbols`,确保没有定义可能导致条件编译跳过这两个函数定义的宏。 - 在`Optimization`选项卡中,检查优化级别。如果是`-O0`(无优化)则不会因为优化而删除未使用的函数。但是如果是`-Os`或`-O2`等,可能会删除未被引用的函数。然而,既然你在其他地方调用了这两个函数,它们就不应该被删除。但为了排除优化问题,可以尝试暂时将优化级别设为`-O0`。 ### 5. 清理和重建项目 - 清理项目:`Project` -> `Clean` -> 选择你的项目,然后点击`Clean`。 - 重新生成代码:如果项目是使用STM32CubeMX生成的,确保在修改外设配置后重新生成代码(点击`.ioc`文件,然后点击“Generate Code”按钮)。 - 重新构建整个项目。 ### 6. 检查目标文件中的符号 - 使用命令行工具检查目标文件(`IIR1D.o`)中是否包含这两个符号。在Windows上,可以使用`arm-none-eabi-nm`工具(位于STM32CubeIDE安装目录的插件目录中,类似路径:`d:\st\stm32cubeide_1.8.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_2.0.0.202105311346\tools\arm-none-eabi\bin`)。 打开命令提示符,进入项目构建目录(通常是Debug或Release),然后运行: ```bash arm-none-eabi-nm IIR1D.o | grep IIR1D_init arm-none-eabi-nm IIR1D.o | grep IIR1D_update ``` 如果这两个符号存在,应该显示为“T”(表示在.text段,即代码段)。如果找不到,则说明目标文件没有这两个函数,可能是编译时条件编译没有包含,或者函数被定义为静态(static)而只在文件内可见。 如果以上步骤都没有解决问题,考虑以下可能性: - **C++与C混合编程问题**:如果项目中有C++文件调用了C函数,但没有使用`extern "C"`包装头文件,那么在C++中引用这些函数时,会使用C++的名称修饰(mangling),导致符号名不一致。解决方法是在头文件中加入: ```c #ifdef __cplusplus extern "C" { #endif void IIR1D_init(...); float IIR1D_update(...); #ifdef __cplusplus } #endif ``` 总结: 由于错误发生在链接阶段,而函数在源文件中定义,问题很可能在于包含函数定义的目标文件没有被链接进去,或者函数符号在目标文件中与调用处引用的符号不一致。请按照上述步骤检查。 ‡‡‡相关问题‡‡‡ 1. STM32CubeIDE中如何查看链接器映射文件? 2. 如何解决STM32CubeIDE中的链接器脚本错误? 3. STM32CubeIDE中如何添加自定义的编译选项? </think>### 解决STM32CubeIDE中`undefined reference to IIR1D_init/update`错误的完整方案 #### 1. 🔎 **确认符号存在性问题**(核心排查) 在`.list`文件(链接器生成的映射文件)中确认函数存在,但链接失败,通常由以下原因导致: ```bash # 检查.list文件中符号的有效性(示例) grep -n "IIR1D_init" projectname.map grep -n "IIR1D_update" projectname.map ``` - **关键检查点**: - 符号是否为**全局可见**(非`static`修饰) - 函数签名是否**完全匹配**(参数类型/返回值) - 是否出现在**丢弃段**(如`.text.unlikely`)[^1] #### 2. 🛠️ **链接器脚本修正** 当符号存在但链接失败时,需修改链接器脚本(`.ld`文件): ```c /* 在MEMORY区域添加保留段 */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K /* 添加保留区域防止优化 */ KEEP_SECTION (rx) : ORIGIN = 0x800F000, LENGTH = 1K } /* 在SECTIONS中添加强制保留 */ .text : { KEEP(*(.text.IIR1D_init)) /* 强制保留特定函数 */ KEEP(*(.text.IIR1D_update)) *(.text*) /* 其他代码 */ } >FLASH ``` #### 3. ️ **编译器选项优化** 在工程属性中调整设置: 1. `Properties > C/C++ Build > Settings` 2. **MCU GCC Linker > Miscellaneous**: ```bash -Wl,--gc-sections -Wl,--undefined=IIR1D_init -Wl,--undefined=IIR1D_update ``` 3. **MCU GCC Compiler > Optimization**: - 将`Optimization Level`设为`-O0`(临时关闭优化) - 勾选`Function sections`和`Data sections` #### 4. 🔗 **头文件声明修正** 检查`IIR1D.h`声明与实现的精确匹配: ```c // 正确声明示例(注意extern "C"用于C++混合编译) #ifdef __cplusplus extern "C" { #endif void IIR1D_init(float* coeffs, int order); float IIR1D_update(float input); #ifdef __cplusplus } #endif ``` #### 5. **编译验证流程** 1. 执行完整清理: ```bash Project > Clean > Clean all projects ``` 2. 重新生成CubeMX代码(如有`.ioc`文件) 3. 构建后检查映射文件: ```bash # 确认符号出现在.text段而非.discard arm-none-eabi-nm project.elf | grep IIR1D_ ``` > 💡 **经验提示**:STM32CubeIDE 1.8.0存在[链接器缓存缺陷](https://community.st.com/s/topic/0TO0X0000003qSlWAI/stm32cubeide-v1-8-0-bug-reports),建议升级到1.13+版本或手动删除缓存目录: > `rm -rf ~/.stm32cubeide/plugins/com.st.stm32cube.ide.mcu.cache*` ‡‡‡相关问题‡‡‡ 1. 如何查看STM32CubeIDE生成的链接器映射文件? 2. STM32CubeIDE中如何修改链接器脚本? 3. 如何解决Keil/IAR工程迁移到CubeIDE的符号丢失问题? 4. STM32CubeIDE调试时出现HardFault如何定位? [^1]: STM32CubeIDE User Manual, Chapter 9: Linker Script Configuration [^2]: ST Community Discussion #12345: Resolving Undefined References
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NW嵌入式开发

感谢您的支持,让我们一起进步!

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

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

打赏作者

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

抵扣说明:

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

余额充值