c - 链接到目录后执行程序时崩溃

标签 c linux gcc x86 dynamic-linking

场景是我尝试通过 /proc 将程序重新链接到一个目录,其中这些目录为 elf 可执行文件。

首先,我创建一个名为 test 的目录

$ mkdir test

链接到 hello 二进制文件

# ln /bin/ping test
# exit

打开目标二进制文件的文件描述符

$ exec 3< test

你知道,这个描述符现在应该可以通过 /proc 访问

$ ls -l /proc/$$/fd/3
lr-x------ 1 febri febri 64 Jul 17 11:09 /proc/2930/fd/3 -> /home/febri/test

删除之前创建的目录

$ rm -rf test

/proc 链接应该仍然存在,但现在将被标记为已删除。

$ ls -l /proc/$$/fd/3 
lr-x------ 1 febri febri 64 Jul 17 11:09 /proc/2930/fd/3 -> /home/febri/test (deleted)

将目录替换为示例有效负载,例如:

$ cat hello.c
#include <stdio.h>

int main(int argc, char ** argv) {
printf("hello!\n");
return 0;
}
$ gcc -w -fPIC -shared -o test hello.c
$ ls -l test
-rwxrwxr-x 1 febri febri 6894 Jul 17 11:20 test
$ file test 
test: ELF 32-bit LSB  shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=361c522d3d9db35ad24de9f3162f80f8a26c9c5b, not stripped

所以,我运行链接的程序,输出是:

$ ./test
Segmentation fault (core dumped)

我的问题是:

为什么程序执行时崩溃?谁能解释一下吗?

最佳答案

事实上,您弄乱的目录和/或符号链接(symbolic link)与您面临的段错误完全无关。让我们看一下用于编译 hello.c 的命令行选项:

  • -w:禁止所有警告。这是一种不好的做法,迟早会成为每一个错误的根源。我还没有找到抑制任何警告的充分理由。无论如何,这对于这种情况并不重要,因为编译 hello world 程序不会产生任何警告。

  • -fPIC:生成]位置无关代码]( https://en.wikipedia.org/wiki/Position-independent_code )。

  • -shared:生成shared library而不是可执行文件。

因此,您正在尝试执行一个共享库,但该库并不打算被执行!然而,GCC 用可执行位标记输出文件。这根本没有任何意义...直到您遇到 HP-UX 的 mmap() 实现。

看起来,由于 one of HP-UX's features (设计缺陷),整个 Unix(类)系列继承了共享库被标记为可执行文件的约定,尽管其中大多数将 SIGSEGV 如果您确实尝试执行它们。

从操作系统的角度来看,段错误的实际原因是 Executable and Linkable Format 方式的人为因素。设计于 20 世纪 80 年代末。

奇怪的是,共享库确实可以在执行时避免SEGV。不过,黑巫毒如the GNU C Library's ,应执行此操作。进行这种仪式的后果是令人痛苦的。例如,您无法初始化 C 运行时,因此必须使用直接的 read()write() 而不是 stdio。其他运行时支持的子系统,例如 malloc() 和类似的子系统,也是没有问题的。另外,(因为没有运行时支持)没有 main()。您必须定义自己的入口点,并显式调用 _exit(0)

tl;dr:目录和符号链接(symbolic link)与该问题无关。您正在尝试执行共享库,并且由于这不是预期的行为,因此您将收到 SIGSEGV 信号。

关于c - 链接到目录后执行程序时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38418577/

相关文章:

c - 运行简单 shell 程序时出现段错误

linux - 关于 solaris 中的 grep

linux - curl调用之间的区别

c++ - 结构的 cudaMalloc 和相同结构的元素

c - 缓冲区溢出漏洞 : Why does "jmp esp" need to be located in a DLL?

c - C 中的 "for"循环后面是否需要 "{}"?

c - Linux <-> Windows 存储字符串地址

gcc - 与 Boost.Filesystem 链接时出现问题

c - 单一源代码与多个文件 + 库

apache - 在 Unix 网络服务器上运行的 Ubuntu 编译程序