所有讨论都针对x86。
如果我写了一个简单的hello程序,如下面的那个:
#include <stdio.h>
int main(){
printf("Hello\n");
return 0;
}
使用ubuntu
在我的电脑上编译它$gcc -shared -mPIC -o hello_new hello.c
然后当我尝试执行hello_new
时,它会给我分段错误。将此二进制文件移动到Android手机时出现相同的错误。 (但我可以将它编译为带有静态链接libc的二进制文件并在Android手机上运行它)
是的,我想直接执行共享对象。
原因如下:
我最近得到了别人编译的linux文件。当我使用linux命令file
和readelf
来分析文件时。它说它是一个共享对象(32位,用-m32编译)。但我可以在手机上像android中的可执行文件一样执行共享对象:
$./hello
这让我很困惑。此共享对象文件包含printf函数调用,不确定它是静态链接还是动态链接。但由于它可以通过ADB在Android上运行,我认为它与libc静态链接。
什么样的编译技术可以让人直接执行共享对象?
答案 0 :(得分:0)
我认为你的android和pc都是x86或arm同时,否则可执行文件不应该在两个平台上运行。现在,为了使共享库可执行,您可以使用gcc的 -pie 命令行选项。详细信息可在此answer中找到。
答案 1 :(得分:0)
碰巧我正在研究这类事情。 可执行文件和linux下的共享对象之间的主要区别之一是可执行文件具有解释器和(有效)入口点。 例如,在最小程序上:
$ echo 'int main;' | gcc -xc -
如果你看一下它的精灵程序标题:
$ readelf --program-headers a.out
...
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
解释程序负责程序的执行,为实现这一点,它将执行一些初始化,如加载所需的共享对象。事实上,它非常类似于脚本shebang,但对于elf文件。 在这种情况下,/ lib64 / ld-linux-x86-64.so.2是amd64的加载器。你可以有多个加载器:例如,一个用于32位,一个用于64。
现在是切入点:
$ readelf --file-header a.out
ELF Header:
...
Entry point address: 0x4003c0
...
$ readelf -a a.out | grep -w _start
57: 00000000004003c0 0 FUNC GLOBAL DEFAULT 13 _start
默认情况下,您可以看到_start被定义为入口点。
因此,如果您考虑以下最小例子:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef INTERPRETER
const char interp[] __attribute__((section(".interp"))) = INTERPRETER;
#endif /* INTERPRETER */
void entry_point(void) {
fprintf(stderr, "hello executable shared object world !\n");
_exit(EXIT_SUCCESS);
}
如果您将其编译为&#34;正常&#34;共享对象并执行它:
$ gcc libexecutable.c -Wall -Wextra -fPIC -shared -o libexecutable.so
$ ./libexecutable.so
Erreur de segmentation
你可以看到它的段错误。但是现在如果你定义一个解释器(使它改为readelf --program-headers之前给你的路径)并告诉链接器你的入口点是什么:
$ gcc libexecutable.c -Wall -Wextra -fPIC -shared -o libexecutable.so -DINTERPRETER=\"/lib64/ld-linux-x86-64.so.2\" -Wl,-e,entry_point
$ ./libexecutable.so hello executable shared object world !
现在可以了。请注意,_exit()调用是必要的,以避免在执行结束时出现段错误。
但最后,请记住,因为您指定了自定义入口点,您将绕过可能需要或不需要的libc初始化步骤,具体取决于您的需求。