当前位置: 首页 > 面试题库 >

如何使Linux共享库(库)自己运行?

柴修筠
2023-03-14
问题内容

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

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/>.

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


问题答案:

我写
了一篇
有关该主题的博客文章,在此我进行了更深入的介绍,因为我发现它很有趣。您可以在下面找到我的原始答案。

您可以使用-Wl,-e,entry_pointgcc选项指定链接器的自定义入口点,其中g entry_point库的“主”函数名称为。

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

链接器不希望与之链接-shared的文件作为可执行文件运行,并且必须提供一些更多信息才能使程序可运行。如果尝试立即运行该库,则会遇到分段错误。

.interp节是操作系统运行应用程序所需的结果二进制文件的一部分。如果-shared未使用,它将由链接器自动设置。如果要构建自己执行的共享库,则必须在C代码中手动设置此部分。看到这个问题。

解释器的工作是查找并加载程序所需的共享库,准备要运行的程序,然后运行它。对于Linux上的ELF格式(现代* nix普遍存在),使用该ld- linux.so程序。有关更多信息,请参见手册页。

下面的行使用GCC属性在.interp节中放置一个字符串。将其放在库的全局范围内,以明确告诉链接器您要在二进制文件中包含动态链接器路径。

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

查找路径的最简单方法ld-linux.soldd在任何普通应用程序上运行。我的系统的示例输出:

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)

指定解释器后,您的库应该是可执行的!仅有一个小缺陷:entry_point返回时将出现段错误。

使用编译程序时main,它不是执行该程序时要调用的第一个函数。main实际上是由另一个称为的函数调用的_start。此功能是负责建立argvargc等初始化。然后它调用main。当main返回时,_start调用exit与返回值main

堆栈中没有返回地址,_start因为它是第一个要调用的函数。如果尝试返回,则会发生无效读取(最终导致分段错误)。这正是我们的入口函数所发生的。将调用添加exit为进入函数的最后一行,以正确清理而不崩溃。

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



 类似资料:
  • 问题内容: 有什么方法可以从Java代码中调用库中的函数吗?通常,可以在Java程序中使用Linux 库吗? 问题答案: 答案是“ JNI” :) 这里有几个链接: 如何在Linux上为JNI应用程序编译动态库? http://learn-from-the-guru.blogspot.com/2007/12/java-native-interface-jni-tutorial-hell.html

  • 问题内容: 两个共享库liba.so和libb.so。liba.so使用libb.so。所有c文件都使用-fPIC编译。链接使用- shared。当我们在liba.so上调用dlopen时,它无法在libb.so中找到符号…我们得到“未定义符号”错误。我们可以dlopen libb.so没有错误。我们知道liba正在找到libb,因为我们没有得到文件未找到错误。删除libb.so时,出现文件未找到

  • 问题内容: 最近,我们被要求提供其中一个库的Linux版本,之前我们是在Linux下开发的,并已针对Windows发行,而在Windows上部署库通常要容易得多。我们遇到的问题是将导出的符号剥离为仅暴露界面中的符号。想要这样做的三个很好的理由 为了保护我们技术的专有方面,以免通过导出的符号被暴露。 防止用户遇到符号名称冲突的问题。 为了加快库的加载速度(至少有人告诉我)。 然后举一个简单的例子:

  • 问题内容: 我正在Linux下使用C ++开发共享库,并且我希望该库使用log4cxx进行日志记录。但是,我不确定该如何设置。为了使log4cxx正常工作,我需要创建一个记录器对象。我如何确保在加载库时创建了该对象? 我怀疑将记录器对象创建为全局变量,然后从我的库的任何源文件中使用它,在标头中将其声明为extern,将是最容易的。但是,一旦应用程序连接到库,如何自动创建记录器? 我知道在Windo

  • 问题内容: 谁能告诉我如何对共享库进行运行时调试? 我需要在运行时调试共享库中的一个函数,但另一个程序会调用它。如何使用共享库执行类似dbx的操作? 我在AIX上使用dbx。我想做的是gdb比dbx好吗? 问题答案: 您只需要使用可执行文件调用gdb(无论是您的文件还是第三方文件都没有关系)。这是一个示例,其中我调试 ls 命令并在(共享) c库中 设置断点。此示例使用了gdb 6.8,它支持延迟

  • 我试图从一个位于vars下的新脚本中获取信息,该脚本是从共享库Jenkins类调用的,但出错了。 > 需要-全局配置文件。 目标-能够在共享库中获取全局值,而无需从Jenkins文件发送参数。 文件结构 变量/全局变量。棒极了 shared_library类 詹金斯档案 因此,我可以看到管道中第一次打印的值,但对于第二次打印,我得到: 类:src没有这样的属性:globals。组织。詹金斯。共享图