这是我在stackoverflow的第一个问题,所以我会尽力做好。
语境:
我想提供一个可以在每个Linux发行版上运行的程序(例如,将使用C ++ 11的程序,在没有C ++ 11程序库的系统上运行)。 为此,我想复制我的程序使用的所有库,并将它们放在一个带有可执行文件的文件夹中,以便它可以使用这些库而不是系统的库。
我有两个环境来testing: – Opensuse,(GNU libc)2.19 – Ubuntu,(Ubuntu EGLIBC 2.17-Oubuntu5.1)2.17
我在Opensuse下编译我的程序,并在Ubuntu下运行它。 该程序使用默认库时效果很好。
项目:
这里是main.c :
int main(int ac, char **av) { printf("Hello World !\n"); }
这里是Opensuse下的文件夹树(在没有main.c和exec.sh的Ubuntu下也一样):
+ project | +--- main.c +--- a.out +--- exec.sh +---+ lib | +--- libc.so.6 +--- ld-linux-x86-64.so.2
最后,当我用一个简单的编译启动程序时,这里是ldd和readelf:
> gcc main.c -o a.out > ldd ./a.out linux-vdso.so.1 (0x00007fff85f57000) libc.so.6 => /lib64/libc.so.6 (0x00007f1fdaaaf000) /lib64/ld-linux-x86-64.so.2 (0x00007f1dae75000) > readelf -d a.out | grep "library\|Library" 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
我已经做了一些研究,终于find了这个职位的人解释一下ld-linux.so。
这是我用来编译的脚本:
#!/bin/bash dir=`pwd` execName="a.out" libDir="/lib" linker="ld-linux-x86-64.so.2" gcc main.c -o ${execName} -Wl,--rpath=${dir}${libDir} -Wl,--dynamic-linker=${dir}${libDir}/${linker}
当我启动我的a.out编译与我的Opensuse脚本我得到以下几点:
> ./a.out Hello World ! > ldd ./a.out linux-vdso.so.1 (0x00007f3222e27000) libc.so.6 => /path/to/project/lib/libc.so.6 (0x00007f3222a7e000) /path/to/project/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x000073222e2b000) > readelf -d a.out | grep "library\|Library" 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000001d (RUNPATH) Library runpath: [/path/to/project/lib]
问题:
现在,当我在Ubuntu上启动这个可执行文件a.out(在Opensuse下编译)时,我得到了以下输出:
> ./a.out ./a.out: Permission denied. > ldd ./a.out linux-vdso.so.1 (0x00007fff5b5fe000) libc.so.6 => /path/to/project/lib/libc.so.6 (0x00007f47df480000) /path/to/project/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f47df82a000) > readelf -d a.out | grep "library\|Library" 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000001d (RUNPATH) Library runpath: [/path/to/project/lib]
当我启动可执行文件时,我一直拒绝这个权限,我不知道为什么。
我把我的a.out和我的lib文件夹从Opensuse转移到Ubuntu与Filezilla,和a.out不是一个可执行文件后,传输,所以我需要做的:
chmod 755 a.out
我在Opensuse和Ubuntu下有相同的树。在lib文件夹中的2个库是Opensuse的默认库
任何关于拒绝许可的帮助,或其他方式来做我想做的事情都会受到欢迎。 在此先感谢您的帮助!
注意:我不能使用LD_PRELOAD,因为你需要root来使用它,它不能用于我想要做的事情。 另外我想避免静态编译,但如果这是唯一的解决scheme,我会考虑它
有很多事情可能是错误的。 这里有一些建议。
你已经提到过,无论你用什么来复制你的a.out
改变这个文件的权限。 库也需要特定的权限,所以请检查这些权限。
这些库中的许多通常实际上是对真正的二进制文件的符号链接。 如果您只复制链接而不是底层的二进制文件,则不起作用。
如您所知, libc
不仅仅是一个文件。 例如,在我的Linux机器上,如果我运行ldd /lib64/libc.so.6
我得到这个结果:
/lib64/ld-linux-x86-64.so.2 (0x0000003531200000) linux-vdso.so.1 => (0x00007ffe2c78c000)
除非你也复制了所有需要的库,否则它将不起作用。
-R
作为链接器 -L
标志告诉链接器它可以在哪里找到库,但是还有一个-R
标志,告诉结果可执行文件在运行时在哪里找到库。 我不清楚你是否需要这个。
您可以按照更简单的方式编译应用程序,而不依赖于共享对象。 在这种情况下,你的应用程序将被静态编译,你应该使用标志-static
。
看看我的例子:
$ cat main.c #include <stdio.h> int main(int ac, char **av) { printf("Hello World !\n"); } $ gcc main.c -o main -static $ ldd main not a dynamic executable
任何有关权限的帮助被拒绝
这一部分很简单:不仅必须使用chmod
使a.out
可执行,而且/path/to/project/lib/ld-linux-x86-64.so.2
必须可执行。
注意:我不能使用LD_PRELOAD,因为你需要root来使用它
你错了:你绝对不需要root来使用LD_PRELOAD
(除非你在set-uid binary上使用它)。
通过在strace实用程序下运行应用程序来重现权限错误,并分析日志以隔离真正的运行时问题。
$ strace -fv ./a.out