关于STM32中__libc_init_array及-nostartfiles编译报错的技术问询
关于STM32项目中__libc_init_array和-nostartfiles的疑问解答
我来给你拆解一下这几个嵌入式开发里用GNU工具链时常见的问题:
1. __libc_init_array是什么?它的初始化作用?
__libc_init_array是GNU C标准库(比如嵌入式常用的newlib)提供的初始化函数,专门负责统筹C/C++程序的启动初始化工作,具体做这些事:
- 调用所有全局和静态对象的构造函数(如果是C++项目,这一步至关重要);
- 初始化标准库的内部结构,比如stdio的缓冲区、内存分配器(malloc/free)的堆空间;
- 设置标准库运行必需的全局变量,比如程序入口参数环境;
- 调用用户自定义的初始化函数(比如通过
attribute((constructor))修饰的函数)。
你在STM32的汇编启动文件里看到它,是因为默认的GNU工具链启动流程依赖它完成标准库初始化,让你的C代码能正常调用标准库函数。
2. __libc_init_array是否必不可少?
这得分情况判断:
- 如果你的项目完全不依赖标准库:比如不用
printf、malloc这类函数,也没有C++全局对象需要构造,所有硬件和系统初始化都是手写汇编或C代码完成的,那可以删掉bl __libc_init_array指令,它不是必须的; - 如果你的项目用到了标准库或者C++特性:那这个函数必不可少——跳过它的话,要么标准库函数会因未初始化崩溃(比如malloc找不到堆空间),要么C++全局对象的构造函数不会执行,导致程序逻辑出错。
3. 使用-nostartfiles参数编译时出现找不到_init()的原因?
-nostartfiles是GCC的链接参数,作用是告诉链接器不要使用默认的系统启动文件(比如crt0.o、crti.o这类)。而默认启动文件里通常会实现_init()和_fini()两个函数:
_init()是老版本标准库的初始化入口,用来替代现在的__libc_init_array;- 当你用
-nostartfiles跳过默认启动文件后,若自己的启动汇编里没实现_init(),但标准库的某些模块(比如旧版newlib)还会引用这个函数,链接器就会报找不到_init()的错误。
解决这个问题的常见方法:
- 若还是想用
__libc_init_array,可以在自己的启动文件里加一个空的_init()函数(或者让它直接调用__libc_init_array),满足链接器的符号需求; - 改用
-nostdlib参数代替-nostartfiles,这个参数会更彻底地跳过标准库的启动文件和默认库,但需要手动指定所有需要链接的库和初始化逻辑; - 确保使用的标准库版本以
__libc_init_array而非_init()作为初始化入口,然后在启动文件里只保留bl __libc_init_array,同时通过链接参数屏蔽对_init()的引用。
内容的提问来源于stack exchange,提问作者user9471855
相关产品推荐
相关产品推荐

