调试问题记录
1. undefined reference to `__aeabi_dcmpun'
__aeabi_dcmpun这个符号的实现位于libgcc, 但是Linker文件中已包含了libgcc, 为何还提示找不到符号?
问题在于几个lib库的顺序安排,打开linker.ld文件,调整文件末尾的库文件列表顺序,如下:
/DISCARD/ : { libgcc.a ( * ) libc.a ( * ) libnosys.a ( * ) /*libm.a ( * )*/ /*libg.a ( * )*/ }
调整为
/DISCARD/ : { libc.a ( * ) libnosys.a ( * ) libgcc.a ( * ) /*libm.a ( * )*/ /*libg.a ( * )*/ }
即可完成编译。
2.lib库相互引用,互相依赖(交叉引用)链接解决办法
Linux GCC中,如果lib a依赖b,b又依赖a,链接的时候无论a放在前,还是b放在前,都会提示 undefined reference to `xxx'。
解决办法一:
链接的时候a链接两次,即: -la -lb -la
解决办法二:
在相互依赖的库间加上 -Wl,--start-group -Wl,--end-group,如果当前的库找不到定义,会在当前的group中从头到尾查询,以找出其定义。
$(CC) -g -o $(TARGET) $(OBJ) $(LIB_FLAG) -Wl,--start-group -lssl -lcrypto -losip2 -leXosip2 -losipparser2 -lpthread -lmd5 -Wl,--end-group
3.关于newlib中的libgloss和libnosys
Newlib由三部分构成:libgloss、libc、libm,三者在Newlib源代码中的存储位置如下。
- newlib-*.*.*
- libgloss
- newlib
- libc
- libm
libc(同libg)是标准C库,libm是标准数学库,而libgloss是提供启动代码和底层I/O支持的。
例如write.c源文件定义了write函数,当程序中引用了printf等标准输出函数时,最终printf会调用write函数进行输出,如果没有定义write函数,那么链接就失败了。kill.c源文件定义了kill系统函数,getpid.c源文件定义了getpid系统函数,等等。
libgloss目录下除了和处理器相关的子目录外,还有个很特别的子目录,那就是libnosys目录,这个目录下的源文件重新定义了libgloss的所有函数,但是所有函数都是空的,都是stub
函数,完全是为了链接通过而定义的。如果程序并不实际使用系统函数,但是某些代码引用了系统函数,那么可以引入libnosys,以便通过编译。
libgloss和libnosys库文件位于编译器的安装目录,例如./gcc-arm-10.2-2020.11-mingw-w64-i686-aarch64-none-elf/lib/gcc/aarch64-none-elf/10.2.1
libnosys库是一个单一的库文件libnosys.a, 编译时直接指定-lnosys即可。
libgloss除了一个librdimon.a库文件外,还包含了若干启动代码目标文件(crt*.o),编译时如果指定了-lrdimon还提示有符号未定义的话,需要把启动代码目标文件也链接进去。
另外gcc提供了-spec选项,通过该选项可实现libnosys和librdimon的选择 切换 。
4. linker文件中指定常数填充
.progend : { . = ALIGN(0x4); *(.text2) LONG(0xdeadbeef) LONG(0xdeadbeef) } >ILM