在我们学习U-Boot源码和调试过程中,是否经常遇到这样的场景?程序运行到某个函数时突然崩溃,屏幕上只有晦涩的寄存器值和内存地址,却不知道这段代码究竟对应源码的哪个位置。或者在研究U-Boot启动流程时,想追踪某个关键函数的实现,面对众多源码中的实现和条件编译不能精准确定对应代码位置?假设我们在学习U-Boot源码或者源码移植时,遇到一个函数实现,但是通过 grep 发现,结果包含众多编译条件下的函数实现。如何精准快速地定位到相应位置呢?我们以 board_init_f_init_reserve 函数中调用的 memset 函数为例。最基本的方法就是在源码目录下使用 grep 命令。要查找的模式包含:- * memset( - 星号后有一个或多个空格,然后是memset
arch/arm/lib/memset.S 中的汇编函数实现,以及各个编译条件下的C函数实现,比如lib/string.c、lib/efi_loader/efi_freestanding.c、lib/efi/efi_stub.c 等。实际上只要我们认真追踪每一个函数的实现的编译条件等总是能找到对应的实现源码。但是这样会花费我们大量的时间,下面我们将分享一套实用技巧,帮助你在U-Boot源码学习中高效定位问题。我们在学习或移植U-Boot源码时,肯定是存在一套可编译的或不同平台的源码,此时我们可以将其先编译得到编译后的二进制程序。在实际编译中,我们知道最后符号表中每一个符号都是独一无二的,不可能同名。arm-linux-gnueabi-objdump -d u-boot | grep -A 20 "<memset>:"
其中 87801740 就是 memset 函数在符号表中的地址。2)编译 U-Boot 时会生成 System.map 文件,包含所有符号的地址信息:# 查找函数地址grep "函数名" System.map
# 查找特定函数地址arm-linux-gnueabi-nm u-boot | grep memset
# 查看符号表arm-linux-gnueabi-readelf -s u-boot | grep memset
497: 00000000 0 FILE LOCAL DEFAULT ABS arch/arm/lib/memset.o7878: 87801741 158 FUNC GLOBAL DEFAULT 3 memset
这里我们必须用到 addr2line 工具,将程序地址转换为源码文件位置。arm-linux-gnueabi-addr2line -e u-boot 87801740
/Work/arm/uboot/u-boot-2025.04/out/../arch/arm/lib/memset.S:21
通过以上两步即可快速准确地定位到函数源码的实现位置。同样的当我们在调试U-Boot启动过程时,遇到程序崩溃,如果得到程序计数器指向的地址,我们同样可以使用 addrline 工具快速的定位到源码文件位置。
掌握U-Boot源码的定位技巧,提高学习和开发效率。随着经验的积累,你将能够在庞大的U-Boot代码库中自如导航,快速定位问题,提高开发效率。你在学习U-Boot源码时有哪些独门技巧?欢迎在评论区分享交流!