使用gcc生成动态库及使用动态库的方法
-g编译的可执行性程序多了很多.debug开头的段
而没有加-g的没有
这里说的调试信息指的是 debug_* 相关信息,符号表是指 symtab 和 dynsym。gdb 对这两种信息进行解析和加工,得到的信息在 gdb 内部统称为符号表。
调试信息需要带上 -g 编译选项才能产生。
其实符号表包括 symtab 和 dynsym 两种。在没有 -g 编译也会产生,在重定位过程中需要处理。
参考链接
在使用 GDB 调试的时候就不容易看到 libc 中的各种结构。所以我们需要加载符号表来方便调试。
Ubuntu 的软件维护者在编译对应的 ELF 文件时,会将符号表与 ELF 文件分离,将符号表命名为 “*-dbg.deb”。这样我们就可以通过手动下载符号表来方便调试。
如果是使用 “glibc all in one” 下载的 libc,会在 libc 等库放置的位置使用 “.debug” 文件夹存放好了 libc 的符号表,使用 gdb 可以自动加载。但是碰到 “glibc all in one” 没有的 libc 版本时就需要手动下载 debug 文件,并手动加载了。
在放置 libc 的目录下新建 ".debug"文件夹,将 debug 文件放入其中即可。
我们需要将 libc 等库的 debug 文件放入对应文件夹,并通过 set debug-file-directory $directories 命令将文件夹设为分离的 debug 文件目录,就可以让 gdb 加载 debug 文件。
GCC:GNU Compiler Collection(GUN 编译器集合),它可以编译C、C++、JAV、Fortran、Pascal、Object-C、Ada等语言。
gcc是GCC中的GUN C Compiler(C 编译器)
g++是GCC中的GUN C++ Compiler(C++编译器)
一个有趣的事实就是,就本质而言,gcc和g++并不是编译器,也不是编译器的集合,它们只是一种驱动器,根据参数中要编译的文件的类型,调用对应的GUN编译器而已,比如,用gcc编译一个c文件的话,会有以下几个步骤:
Step1:Call a preprocessor, like cpp.
Step2:Call an actual compiler, like cc or cc1.
Step3:Call an assembler, like as.
Step4:Call a linker, like ld
由于编译器是可以更换的,所以gcc不仅仅可以编译C文件
所以,更准确的说法是:gcc调用了C compiler,而g++调用了C++ compiler
不同版本的GCC实现了不同版本的c和c++标准库。这对代码的兼容性有一定影响。每个版本的gcc和标准库版本的对应关系可以在官方文档中找到。使用不同版本的标准库可能会导致代码编译和运行的行为发生不同,甚至会报错。因此,在编写代码时应该了解所使用的标准库版本,并避免使用已经废弃或不再维护的标准库。
export CC=gcc的路径
export CXX=g++的路径
通过设置环境变量LD_LIBRARY_PATH增加默认库文件搜索路径,会优先匹配我们提供目录中的libc
通过gcc 的-L参数指定glibc库(libc.so)的路径
在gcc的编译参数中指定 -Wl,–dynamic-linker=glibc中动态链接器的路径,如下:
-Wl,--dynamic-linker=/动态连接器的路径/ld-linux-x86-64.so.2
参考链接
dpkg -L +软件包的名字,可以知道这个软件包包含了哪些文件, 这个方法可以列出所有安装后留在系统里的文件,查询系统中已安装的软件包所安装的位置.
系统安装软件一般在/usr/share,可执行的文件在/usr/bin,配置文件可能安装到了/etc下等。
文档一般在 /usr/share
可执行文件 /usr/bin
配置文件 /etc
lib文件 /usr/lib
参考链接
gdb寻找单独的debug文件的路径是:
set debug-file-directory directories
Set the directories which GDB searches for separate debugging information files to directory. Multiple path components can be set concatenating them by a path separator.
show debug-file-directory
Show the directories GDB searches for separate debugging information files.
如前所述,如果将debuginfo文件直接放到/usr/lib/debug目录(或者通过set-debug-file-directory命令设置的根目录)下,也是可以的,但文件目录的组织结构必须和运行时的目录组织结构一样,这个地方有一个需要注意的地方,特别是对于so文件,在debug-root-directory目录下寻找对应的debuginfo文件时,和文件实际所在的位置不一定完全一致,而要看连接器能够找到的路径,即ldd所显示的路径。gdb是会到debug-root-directory/$LDD显示的目录下去寻找对应的debuginfo文件。而ldd显示出来的路径,可能是一个绝对路径,也可能是一个相对路径,者取决于你的操作系统中所设置的一些so查找路径,比如LD_LIBRARY_PATH设置为一个相对路径还是一个绝对路径,对于gdb来说,去debug-root-directory目录下寻找的路径也不一样。gdb会拿ldd显示出来的路径直接和debug-root-directory拼接一下。比如我当前的LD_LIBRARY_PATH设置为./fff,那么gdb就会去/usr/lib/debug/./fff目录下去读取liba.so所对应的debuginfo文件,因为ldd现实出来的liba.so的路径是./fff/liba.so。
在使用gcc编译时,如果采用带-g选项编译,即可在二进制文件中附加调试信息以便gdb进行源码级别的调试。如果二进制中存在调试信息,会去相关目录寻找源码,GDB首先在编译时目录中搜索,如果失败则在当前目录中搜索,即$cdir:$cwd,其中$cdir指的是编译时目录(compilation directory),$cwd指的是当前工作目录(current working directory)。
如果找到了源码文件则可以使用gdb的list命令来查看源码。
通过在ubuntu中安装带调试信息的libc,并下载libc源码,即可配置gdb跟入libc的库函数后进行源码级别的调试
不过如果我们gdb在默认寻找的目录中找不到源码文件,则无法进行源码调试。如果源码在其他目录可以在gdb中用directory或dir命令指定,或者在启动gdb时用-d参数指定,一样可以看到源码。
libc6-dbg是一个包含C标准库调试符号的调试信息包
sudo apt install libc6-dbg
sudo apt install libc6-dbg:i386
libc6-dev :当前gcc编译链接时使用的版本的libc库源码
然后在调试时用directory把目录指向对应子文件夹就可以了,比如我要调试malloc:
gdb -q ./可执行性文件 -d 下载的libc库源码文件夹路径/malloc
或者是在gdb中直接用directory
directory 下载的libc库源码文件夹路径/malloc