ldd 脚本分析

news/2024/10/21 13:40:27/

文章目录

    • 1. 背景
    • 2. 查看ldd源码
    • 3. ldd 源码分析
    • 4. ldd 指令移植
    • 5. 总结

ldd 脚本分析

1. 背景

在开发某嵌入式平台时,发现没有动态库依赖查看工具ldd,后来几经搜索与源码分析,将相关记录一下。

2. 查看ldd源码

  • ldd 指令本质

    • ldd 本质不是一个可执行程序,而是 shell脚本,可以使用 file ldd进行确认

      # 查看ldd指令的路径
      which ldd
      # 显示如下:
      /usr/bin/ldd# 查看ldd文件类型
      file /usr/bin/ldd 
      # 显示如下:
      /usr/bin/ldd: Bourne-Again shell script, ASCII text executable
      
  • ldd 源码

    • 可以在 usr/bin目录下查看源码 cat /usr/bin/ldd

    • 也可以下载 glibc 源码,编译后,在安装目录的 bin 目录下有对应的源码

3. ldd 源码分析

这里我们使用 cat /usr/bin/ldd指令查看源码

TEXTDOMAIN=libc
TEXTDOMAINDIR=/usr/share/localeRTLDLIST="/lib/ld-linux.so.2 /lib64/ld-linux-x86-64.so.2 /libx32/ld-linux-x32.so.2"
warn=
bind_now=
verbose=

其中第4行指定了 ld动态库的列表,最终是通过这个列表中的某一个来显示可执行程序的动态库依赖的。

 while test $# -gt 0; docase "$1" in--vers | --versi | --versio | --version)echo 'ldd (Ubuntu GLIBC 2.31-0ubuntu9.9) 2.31'printf $"Copyright (C) %s Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
" "2020"printf $"Written by %s and %s.
" "Roland McGrath" "Ulrich Drepper"exit 0;;--h | --he | --hel | --help)echo $"Usage: ldd [OPTION]... FILE...--help              print this help and exit--version           print version information and exit-d, --data-relocs       process data relocations-r, --function-relocs   process data and function relocations-u, --unused            print unused direct dependencies-v, --verbose           print all information
"printf $"For bug reporting instructions, please see:\\n%s.\\n" \"<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>"exit 0;;-d | --d | --da | --dat | --data | --data- | --data-r | --data-re | \--data-rel | --data-relo | --data-reloc | --data-relocs)warn=yesshift;;-r | --f | --fu | --fun | --func | --funct | --functi | --functio | \--function | --function- | --function-r | --function-re | --function-rel | \--function-relo | --function-reloc | --function-relocs)warn=yesbind_now=yesshift;;-v | --verb | --verbo | --verbos | --verbose)verbose=yesshift;;-u | --u | --un | --unu | --unus | --unuse | --unused)unused=yesshift;;--v | --ve | --ver)echo >&2 $"ldd: option \`$1' is ambiguous"exit 1;;--)           # Stop option processing.shift; break;;-*)echo >&2 'ldd:' $"unrecognized option" "\`$1'"echo >&2 $"Try \`ldd --help' for more information."exit 1;;*)break;;esac

上面就是对 ldd命令行参数进行分析,其中 $#表示所有命令行的参数,匹配到对应选项后,会把对应变量设置为yes下面是翻译后的提示

wangzhonglai@shell:~/learn/c_test$ ldd --help
用法:ldd [选项]… 文件…--help              印出这份说明然后离开--version           印出版本信息然后离开-d, --data-relocs       进程数据重寻址-r, --function-relocs   进程数据和函数重寻址-u, --unused            印出未使用的直接依赖关系-v, --verbose           印出所有信息
add_env="LD_TRACE_LOADED_OBJECTS=1 LD_WARN=$warn LD_BIND_NOW=$bind_now"
add_env="$add_env LD_LIBRARY_VERSION=\$verify_out"
add_env="$add_env LD_VERBOSE=$verbose"
if test "$unused" = yes; thenadd_env="$add_env LD_DEBUG=\"$LD_DEBUG${LD_DEBUG:+,}unused\""
fi

上面代码设置了环境变量,用于ld.so解析可执行文件时使用

try_trace() (output=$(eval $add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit $rc)rc=$?printf '%s' "${output%x}"return $rc
)

eval指令是一个bash内置命令,用于将参数作为命令执行。在这段代码中,eval被用于执行ldd命令,并将add_env和"$@"作为参数传递给它。这样做的好处是可以动态地构建命令行参数,从而实现更灵活的命令执行。

case $# in
0)echo >&2 'ldd:' $"missing file arguments"echo >&2 $"Try \`ldd --help' for more information."exit 1;;
1)single_file=t;;
*)single_file=f;;
esac

上述指令用于判断 ldd 后面跟的文件个数,是单个还是多个,并设置对应的标记。

result=0
for file do# We don't list the file name when there is only one.test $single_file = t || echo "${file}:"case $file in*/*) :;;*) file=./$file;;esacif test ! -e "$file"; thenecho "ldd: ${file}:" $"No such file or directory" >&2result=1elif test ! -f "$file"; thenecho "ldd: ${file}:" $"not regular file" >&2result=1elif test -r "$file"; thenRTLD=ret=1for rtld in ${RTLDLIST}; doif test -x $rtld; thendummy=`$rtld 2>&1`if test $? = 127; thenverify_out=`${rtld} --verify "$file"`ret=$?case $ret in[02]) RTLD=${rtld}; break;;esacfifidonecase $ret in1)# This can be a non-ELF binary or no binary at all.nonelf "$file" || {echo $" not a dynamic executable" >&2result=1};;0|2)try_trace "$RTLD" "$file" || result=1;;*)echo 'ldd:' ${RTLD} $"exited with unknown exit code" "($ret)" >&2exit 1;;esacelseecho 'ldd:' $"error: you do not have read permission for" "\`$file'" >&2result=1fi
doneexit $result

上述代码 其中 for file do 这个语句表示遍历所有的 $file,等价于 for file in "$@",相当于对终端输入的参数进行遍历。

第5-9行判断是否是绝对路径,不是绝对路径的话,以当前路径寻找文件。

第11-17行,先判断文件是否存在,是否是一个普通文件,是否可读,满足条件之后,进行后续测试。

第20-30行对 $RTLDLIST ld.so 列表进行查询,确认可以使用的 ld.so,保存在 "$RTLD"中。

verify_out=${rtld} --verify "$file"会使用ld.so对二进制文件进行校验,例如使用/lib/ld-linux.so.2 --verify /usr/bin/cat会对 cat 指令进行分析,检测当前系统中加载的所有动态库是否存在缺失的符号、函数或变量,可以帮助我们解决动态库加载出错的问题。

第31-52行会对上面校验的结果进行确认,只有正确的情况下(也就是 $ret 为 0|2 的时候),会调用 try_trace函数进行解析,try_trace函数使用了一个环境变量LD_TRACE_LOADED_OBJECTS,并且将环境变量设置为 true

在 Linux 系统上,动态链接器(ld.so)用于在程序运行时加载和解析库文件,以及为这些库提供符号链接。当您运行一个程序时,系统会自动查找它所依赖的共享库,以及这些库所依赖的其他库。使用 LD_TRACE_LOADED_OBJECTS=1 环境变量可以显示某个程序运行时所加载的所有共享库(也就是动态链接库)的路径。

4. ldd 指令移植

经过上述分析,ldd指令最终是设置了一个LD_TRACE_LOADED_OBJECTS=1,然后使用 xx_ld.so进行显示可执行程序的动态依赖。因此,我们可以在RTLDLIST链表中添加我们实际依赖的交叉编译环境下的ld.so,比如ld-linux-armhf.so.3

5. 总结

  1. 本文介绍了 ldd指令的源码位置以及查看方法;
  2. 本文分析了ldd脚本文件的实际执行流程;
  3. 本文介绍了在交叉编译环境下移植ldd指令的方法。

http://www.ppmy.cn/news/96040.html

相关文章

八大排序算法-直接插入排序、希尔排序、直接选择排序、冒泡排序、堆排序、快速排序、归并排序、基数排序(下)

目录 前言冒泡排序&#xff08;Bubble Sort&#xff09;一、概念二、实现思路三、图示过程四、案例分析1、图示过程2、第一趟排序示例 五、代码1、代码示例2、代码解释3、运行结果 六、复杂度 快速排序&#xff08;QuickSort&#xff09;一、概念二、实现思路三、图示过程四、代…

H743 USBHOST协议栈 CPU占用率高的问题。

经过查看&#xff0c;是因为USBHOST频繁的进入中断导致&#xff0c;单步执行发现&#xff0c;是因为发生了USB_OTG_HCINT_CHH或者USB_OTG_HCINT_NAK中断了&#xff0c;只在CHH中断服务函数里&#xff0c;给USB主线程发了1个消息&#xff0c;又引起了USBH_Process_OS主线程的频繁…

七、Django DRF框架GenericAPIView--搜索排序分页

上一章&#xff1a; 六、DRF框架APIView--request&response解析器&渲染器_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; 一、GenericAPIView介绍 APIView 继承 View GenericAPIView 继承 APIView。 GenericAPIView 功能&#xff1a; a.具备View的所有特性 …

达梦8逻辑备份导出导入dexp/dimp

逻辑导出&#xff08;dexp&#xff09;和逻辑导入&#xff08;dimp&#xff09;是 DM 数据库的两个命令行工具&#xff0c;分别用来实现对 DM 数据库的逻辑备份和逻辑还原。逻辑备份和逻辑还原都是在联机方式下完成&#xff0c;联机方式是指数据库服务器正常运行过程中进行的备…

深度学习进阶篇-预训练模型[4]:RoBERTa、SpanBERT、KBERT、ALBERT、ELECTRA算法原理模型结构应用场景区别等详解

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

从代码角度理解DETR

一个cnn的backbone, 提图像的feature, 比如, HWC.同时对这个feature做position_embedding.然后二者相加 (在Transformer里面就是二者相加)输入encoder,输入decoder (这里有object queries.)然后接Prediction Heads, 比如分类和回归. 下面的代码参考自: https://github.com/fac…

Ovirt 开源虚拟化平台安装

ovirt官网 一、资源规划介绍 1.1、服务规划 ovirt版本 ovirt engine 4.3.10 ovirt node 4.3.10 ovirt.node01.opsvv.com 负责托管引擎服务 1.2、资源划分 1.2.1、节点划分 密码均为&#xff1a;12345678 Node02无法开启虚拟化&#xff0c;只演示加入集群节点使用 节点…

Mac下好用的日记、电子书阅读器、RSS订阅软件​

Mac下好用的日记笔记本、电子书阅读器和RSS订阅、播客订阅等软件推荐。我们收录到 Mac下好用的日记、电子书阅读器、RSS订阅软件​http://www.webhub123.com/#/home/detail?pLZPL-2ofIu 收录效果如下 ​也可以使用分组视图来查看各类软件网址 ​ 登录后可一键保存全部软件网址…