交叉编译armhf程序在树莓派运行时进入main()前出现段错误如何解决
问题根因
核心问题是你手动调用ld.gold执行链接操作时,缺失了C运行时必要的启动文件,同时默认使用了和Raspbian系统不匹配的动态链接器路径,具体原因如下:
- 缺失启动文件导致入口点异常:Linux ELF程序的默认入口是
_start符号,存放在crt1.o、crti.o启动文件中,你手动链接时只添加了crtbegin.o和crtend.o,遗漏了最基础的入口启动文件,导致ld无法找到有效入口,将ELF头的入口地址设为0x0,程序运行时直接跳转到非法地址触发段错误。你本地树莓派编译也出现相同问题,说明本地编译脚本也存在同样的手动调用ld缺失启动文件的问题。 - 动态链接器路径不匹配:未指定
--dynamic-linker参数时,交叉工具链的ld会默认使用工具链自带libc对应的解释器路径/usr/lib/libc.so.1,和Raspbian系统标准路径/lib/ld-linux-armhf.so.3不一致,错误的动态链接器无法正确完成共享库加载、栈初始化操作,导致程序在进入main之前就崩溃在libc初始化逻辑中。
解决方案
方案1(推荐,避免手动链接坑)
不要直接调用ld做最终链接,改用交叉编译器(gcc/g++)驱动整个链接流程,编译器会自动补全所有必要的启动文件、正确的动态链接器路径、默认链接参数,无需手动处理crt相关文件。参考链接指令:
$TOOLCHAIN/gcc-arm-8.3-2019.03/bin/arm-linux-gnueabihf-g++ \ -std=c++11 --sysroot=$RASPBIAN_ROOT \ -mcpu=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard \ -D_GLIBCXX_USE_CXX11_ABI=0 \ -o bin/linux/armhf/debug/executable obj/linux/armhf/debug/File.o 其他目标文件 \ -L ../localdependency \ -L $RASPBIAN_ROOT/opt/vc/lib \ -L $RASPBIAN_ROOT/usr/lib/arm-linux-gnueabihf \ -L $RASPBIAN_ROOT/lib \ -L $RASPBIAN_ROOT/usr/lib \ -lbcm_host -lvcos -lvchiq_arm -lcurl -lxml2 \ -lpthread -lz -lm -ldl
方案2(需坚持手动调用ld时使用)
严格按照启动文件顺序补全所有缺失的crt文件,同时指定正确的动态链接器路径:
- 在链接参数最开头添加:
$RASPBIAN_ROOT/usr/lib/arm-linux-gnueabihf/crt1.o $RASPBIAN_ROOT/usr/lib/arm-linux-gnueabihf/crti.o - 在链接参数最后添加:
$RASPBIAN_ROOT/usr/lib/arm-linux-gnueabihf/crtn.o - 保留
--dynamic-linker=/lib/ld-linux-armhf.so.3参数 - 严格遵循启动文件顺序:
crt1.o → crti.o → crtbegin.o → 你的目标文件 → 依赖库 → crtend.o → crtn.o,顺序错误也会导致启动异常
验证方法
- 执行
readelf -h executable查看ELF头的Entry point address字段,正常应为非0的有效地址 - 执行
readelf -l executable | grep interpreter查看解释器路径,必须为/lib/ld-linux-armhf.so.3 - 运行程序验证是否可正常进入main函数执行业务逻辑
内容的提问来源于stack exchange,提问作者vesperto
相关产品推荐
相关产品推荐

