gpt4 book ai didi

c - 如何使 linux 共享对象(库)独立运行?

转载 作者:IT王子 更新时间:2023-10-29 00:27:31 25 4
gpt4 key购买 nike

注意到 gcc -shared 创建了一个可执行文件,我突然有了一个奇怪的想法来检查当我尝试运行它时发生了什么……好吧,结果是 segfault 用于我自己的库。因此,出于对此的好奇,我尝试“运行”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 符号——我可以吗?

最佳答案

我写了 a blog post在这个主题上,我进行了更深入的探讨,因为我发现它很有趣。您可以在下面找到我的原始答案。


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

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

链接器不希望用-shared 链接的东西作为可执行文件运行,必须提供更多信息才能使程序运行。如果您现在尝试运行该库,您将遇到段错误。

.interp 部分是操作系统运行应用程序所需的结果二进制文件的一部分。如果未使用 -shared,它会由链接器自动设置。如果构建一个你想自己执行的共享库,你必须在 C 代码中手动设置这个部分。参见 this question .

解释器的工作是找到并加载程序所需的共享库,准备要运行的程序,然后运行它。对于 Linux 上的 ELF 格式(现代 *nix 普遍存在),使用 ld-linux.so 程序。看到它是 man page了解更多信息。

下面的行使用 GCC attributes 在 .interp 部分放置了一个字符串。 .将它放在你的库的全局范围内,以明确告诉链接器你想在你的二进制文件中包含一个动态链接器路径。

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

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

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 使用 main 的返回值调用 exit

_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 编译。

关于c - 如何使 linux 共享对象(库)独立运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31484785/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com