恰巧我正在研究这种类型的东西。 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);
}
如果你编译它作为一个“正常”的共享对象并执行:
$ gcc libexecutable.c -Wall -Wextra -fPIC -shared -o libexecutable.so
$ ./libexecutable.so
Erreur de segmentation
你可以看到它出现segfaults。但是现在,如果你定义一个解释器(适应它的路径是什么readelf --program报头之前给你),并告诉链接什么是你的切入点:
$ 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初始化步骤。
您的'gcc'设置为ARM编译?我不认为你可以将x86可执行文件移植到ARMv7a设备上,并期望它可以正常工作。在x86安卓设备(例如模拟器)上尝试它,或尝试编译目标处理器的体系结构。 – initramfs
@CPUTerminator,都是x86。 – drdot
嗯,我没有太多可靠的依据,也许gcc使用的是不支持Android的指令/扩展。看看这个[链接](http://shareprogrammingtips.com/c-language-programming-tips/cross-compile-cc-based-programs-run-android-smart-phones/),而方法1似乎是与您的做法相同,它针对的是ARM体系结构。也许尝试方法2和/或3? – initramfs