echo $PATH which perf nano ~/.bashrc == nano /home/wyc/.bashrc export PATH="/usr/bin/:$PATH" LD_LIBRARY_PATH 作用:LD_LIBRARY_PATH 用于指定动态链接库的搜索路径。在运行一个可执行文件时,Linux 系统会根据这个环境变量来查找程序所需的共享库。系统首先会在这个路径中查找,如果没有找到,再去默认的库路径(如 /lib 和 /usr/lib)查找。 优先加载:如果 LD_LIBRARY_PATH 中指定了多个路径,系统会按照它们的顺序逐个查找。因此,你可以通过调整这个变量来控制库的加载顺序,确保优先使用特定的版本。 用途: 多版本支持:允许同一程序使用不同版本的库。 自定义路径:在非标准目录中查找库文件。 LD_PRELOAD 作用:LD_PRELOAD 用于强制加载指定的共享库,即使该库不在程序的默认依赖中。它会在程序启动时优先加载你指定的库,覆盖系统中已有的相同函数。 功能替换:如果你在 LD_PRELOAD 中指定了一个库,并且这个库中实现了某些与标准库同名的函数(如 malloc 或 printf),程序将使用你提供的版本,而不是系统库中的版本。 用途: 功能扩展:在不修改程序代码的情况下,添加或替换某些功能。 调试和分析:允许开发人员监控和调试程序的函数调用。 性能优化:可以替换标准函数实现,以改善性能。 为什么需要 LD_PRELOAD? 虽然 LD_LIBRARY_PATH 可以影响库的加载顺序,但它并不能直接替换或修改库中已存在的函数实现。以下是几个使用 LD_PRELOAD 的场景,进一步阐明其必要性: 函数覆盖:如果你想替换标准库函数(如 malloc、free、printf)的实现,你需要使用 LD_PRELOAD。LD_LIBRARY_PATH 只能指定库的搜索路径,但无法改变函数的具体实现。 动态注入:LD_PRELOAD 允许你在运行时将自定义的功能动态地注入到程序中。这对于调试和测试非常有用,例如你可以追踪内存分配或函数调用的次数。 临时性和灵活性:通过 LD_PRELOAD,你可以在不需要重新编译或修改程序的情况下,快速改变程序的行为。这种灵活性在开发和调试过程中非常重要。 小结 LD_LIBRARY_PATH:改变库的查找路径,以确保优先加载特定路径下的库文件。 LD_PRELOAD:在程序启动时强制加载指定的库,优先于其他库中的函数实现,从而实现功能的覆盖或注入。 一个很大的缺点是,不同发行版之间,同一发行版的不同版本之间,二进制常常不兼容。而导致这个问题的一个很大原因是, 几乎所有的 Linux 发行版都不允许在系统上同时存在多个版本的 glibc,就算允许,也必须通过 LD_LIBRARY_PATH 或 LD_PRELOAD 等方式来引入。 另外可执行程序默认会链接到系统的动态库而不是当前目录下的(实际上编译的时候可以使用 -rpath), 这使得我们很难把一个软件和它的所有依赖打包成一个独立的包。而为了解决这个问题,人们又搞出了 Docker、Flatpak、Snap、AppImage 这些方案…… 然而我想说的是,你们直接在编译的时候设一下 rpath 然后把 .so 全都打包进去不就行了么!实际上仅仅对 kernel 而言,二进制应该是可以兼容的。 不兼容不仅仅是库的问题, kernel的ABI兼容性也是一个问题, 即使你把glibc都一起打包, kernel太老不满足ABI最低要求也没用……