执行共享对象文件

时间:2015-05-09 04:36:32

标签: android c linux

所有讨论都针对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静态链接。

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

2 个答案:

答案 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初始化步骤,具体取决于您的需求。