如何使自己的可运行在Linux共享对象(库)? [英] How to make a linux shared object (library) runnable on its own?

查看:77
本文介绍了如何使自己的可运行在Linux共享对象(库)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到的gcc -shared 创建一个可执行文件,我刚刚得到了奇怪的想法来检查时,我尝试运行它会发生什么......好结果是的段错误的为自己的库。于是,好奇有关,我想跑glibc的( /lib/x86_64-linux-gnu/libc.so.6 我的系统上)。果然,它没有崩溃,但为我提供了一些输出:

Noticing that gcc -shared creates an executable file, I just got the weird idea to check what happens when I try to run it ... well the result was a segfault for my own lib. So, being curious about that, I tried to "run" the glibc (/lib/x86_64-linux-gnu/libc.so.6 on my system). Sure enough, it didn't crash but provided me some output:

GNU C Library (Debian GLIBC 2.19-18) stable release version 2.19, by Roland McGrath et al.
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.4.
Compiled on a Linux 3.16.7 system on 2015-04-14.
Available extensions:
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

所以我的问题在这里是:什么是这背后的魔力呢?我不能只定义库中的符号 - 或者我可以

推荐答案

我写一篇博客文章的关于这个问题,我去更深入,因为我发现它耐人寻味。您可以在下面找到我原来的答复。

I wrote a blog post on this subject where I go more in depth because I found it intriguing. You can find my original answer below.

您可以指定一个自定义的切入点与 -Wl,-e,entry_point 选项,GCC,链接器,其中 entry_point 是图书馆的主函数的名称。

You can specify a custom entry point to the linker with the -Wl,-e,entry_point option to gcc, where entry_point is the name of the library's "main" function.

void entry_point()
{
    printf("Hello, world!\n");
}

链接器不指望一些与 -shared 来运行作为一个可执行的联系,必须给予该计划为可运一些更多的信息。如果您现在尝试运行库中,你会遇到一个分段错误。

The linker doesn't expect something linked with -shared to be run as an executable, and must be given some more information for the program to be runnable. If you try to run the library now, you will encounter a segmentation fault.

的.interp部分是由操作系统运行所需应用程序产生的二进制的一部分。它如果 -shared 不使用连接器自动设置。您必须在构建您希望通过自身执行的共享库在C code手动设置本节。见<一href=\"http://stackoverflow.com/questions/4488937/how-to-set-the-dynamic-linker-path-for-a-shared-library\">this问题。

The .interp section is a part of the resulting binary that is needed by the OS to run the application. It's set automatically by the linker if -shared is not used. You must set this section manually in the C code if building a shared library that you want to execute by itself. See this question.

该间preTER的任务是找到并加载一个程序,prepare程序运行所需的共享库,然后运行它。对于ELF格式(无处不在现代的* nix)在Linux上,则使用 ld-linux.so 程序。看到它的更多信息手册页

The interpreter's job is to find and load the shared libraries needed by a program, prepare the program to run, and then run it. For the ELF format (ubiquitous for modern *nix) on Linux, the ld-linux.so program is used. See it's man page for more info.

该生产线使用 GCC属性。将这个库中的全球范围明确地告诉您要在您的二进制动态链接路径连接。

The line below puts a string in the .interp section using GCC attributes. Put this in the global scope of your library to explicitly tell the linker that you want to include a dynamic linker path in your binary.

const char interp_section[] __attribute__((section(".interp"))) = "/path/to/ld-linux";

找到路径 ld-linux.so 最简单的方法是运行 LDD 在任何正常的应用。从我的系统输出示例:

The easiest way to find the path to ld-linux.so is to run ldd on any normal application. Sample output from my system:

jacwah@jacob-mint17 ~ $ ldd $(which gcc)
    linux-vdso.so.1 =>  (0x00007fff259fe000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faec5939000)
    /lib64/ld-linux-x86-64.so.2 (0x00007faec5d23000)

在您指定的跨preTER你的库应该是可执行的!这里有一个轻微的缺陷:它会出现段错误时, entry_point 返回

Once you've specified the interpreter your library should be executable! There's just one slight flaw: it will segfault when entry_point returns.

在编译程序主,它不是在执行时,它被称为第一个函数。 实际上是由一个名为 _start 另一个函数调用。此功能是负责建立的argv ARGC 等的初始化。然后调用。当的回报, _start 通话退出的返回值的

When you compile a program with main, it's not the first function to be called when executing it. main is actually called by another function called _start. This function is responsible for setting up argv and argc and other initialisation. It then calls main. When main returns, _start calls exit with the return value of main.

有在堆栈没有回信地址_start ,因为它是被调用的第一个函数。如果试图返回,一个无效的读操作(最终导致段故障)。这正是在我们入口点函数发生。加入退出通话作为你的入口函数的最后一行妥善清理,而不是崩溃。

There's no return address on stack in _start as it's the first function to be called. If it tries to return, an invalid read occurs (ultimately causing a segmentation fault). This is exactly what is happening in our entry point function. Add a call to exit as the last line of your entry function to properly clean up and not crash.

example.c

#include <stdio.h>
#include <stdlib.h>

const char interp_section[] __attribute__((section(".interp"))) = "/path/to/ld-linux";

void entry_point()
{
    printf("Hello, world!\n");
    exit(0);
}

编译与的gcc example.c -shared -fPIC -Wl,-e,entry_point

这篇关于如何使自己的可运行在Linux共享对象(库)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆