2015-05-09 88 views
1

所有讨论都是针对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命令filereadelf来分析文件。它说它是一个共享对象(32位,用-m32编译)。但我可以在手机上执行Android中的可执行共享对象:

$./hello 

这真让我困惑。这个共享目标文件包含printf函数调用,不确定它是静态链接还是动态链接。但由于它可以通过ADB在Android上运行,因此我认为它是静态链接到libc的。

什么样的编译技术可以允许直接执行共享对象?

+0

您的'gcc'设置为ARM编译?我不认为你可以将x86可执行文件移植到ARMv7a设备上,并期望它可以正常工作。在x86安卓设备(例如模拟器)上尝试它,或尝试编译目标处理器的体系结构。 – initramfs

+0

@CPUTerminator,都是x86。 – drdot

+0

嗯,我没有太多可靠的依据,也许gcc使用的是不支持Android的指令/扩展。看看这个[链接](http://shareprogrammingtips.com/c-language-programming-tips/cross-compile-cc-based-programs-run-android-smart-phones/),而方法1似乎是与您的做法相同,它针对的是ARM体系结构。也许尝试方法2和/或3? – initramfs

回答

0

我觉得你的android和pc都是x86或arm,否则可执行文件不能在两个平台上运行。现在要共享库可执行文件,可以同时使用gcc的命令行选项-pie。详情请见answer

+0

我不问如何生成共享对象。我要求编译共享对象,以便它可以直接执行。 – drdot

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); 
} 

如果你编译它作为一个“正常”的共享对象并执行:

$ 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初始化步骤。