gcc 编译时指定动态链接器与libc

笔者在尝试使用多libc编译源代码时,遇到了一些问题,现已经解决,将自己的理解记录如下。

本文为使用多版本libc编译提供了一个新思路,对笔者的帮助较大,也希望与读者多多讨论。

程序如何动态链接? - libc 与 ld

通常我们编译的程序都采用动态链接的方式,在程序运行中查找公共链接库中的函数,并跳转执行。这对减小可执行文件的体积和提升程序可维护性非常有帮助。毕竟,我们都不想让一个简单的hello world程序就占用MB甚至10MB级别的空间(实测静态链接大小为800+KB,动态链接为20KB,空间占比40 : 1)。

glibc就是linux系统中常用的C语言库,其中包含我们常用的大多数函数,如printf, malloc等。它也负责程序的初始化、维护堆状态,以及程序推出后的部分事项等。

但是程序在运行时,是怎么找到glibc,以及其中函数的位置的呢?这依靠dynamic loader —— 动态链接器完成。dynamic loader通过动态链接库文件的符号表查询到对应函数和变量的地址,并返回给可执行文件,可执行文件就可以调用对应地址上的函数。glibc对应的动态链接器是ld,注意与GNU linker的ld不同,它也是以库的形式出现的(ld-version.so)。

传统方法 - patchelf

常见的修改ld和libc路径的方法是使用patchelf工具

  • --set-interpreter设置动态链接器路径
  • --replace-needed替换所需so的路径,如glibc等

注意两个命令必须都执行后才能完全替换,若glibc版本与ld版本不匹配将产生运行时错误SEGFAULT

在拥有源码的情况下,编译后再通过命令替换libc库比较费力。但该方法在仅拥有libc库,并且目标文件libc版本与本机默认版本不一致时非常有效。

编译时修改libc

其实在编译中,就可以修改libc位置。通过设置环境变量和链接参数就可以做到这一点。

  1. 通过设置环境变量LD_LIBRARY_PATH增加默认库文件搜索路径,会优先匹配我们提供目录中的libc

    export LD_LIBRARY_PATH=/your/libc/root/lib:$LD_LIBRARY_PATH
    
  2. 通过传递链接参数指定interpreter

    -Wl,-dynamic-linker,/your/libc/root/lib/ld-2.31.so
    
    • 注意上面是一整个参数,其中Wl表示将后面逗号分隔的参数传递给链接器(linker)

通过LDD可以查看链接结果

ldd test                                                                               
        linux-vdso.so.1 (0x00007ffed4beb000)
        libc.so.6 => /your/libc/root/lib/libc.so.6 (0x00007f606e155000)
        /your/libc/root/lib/ld-2.31.so => /lib64/ld-linux-x86-64.so.2 (0x00007f606e30f000)

你可能感兴趣的:(pwn,Linux,linux,编译)