为什么独立的 C hello 程序在用作动态链接器时会崩溃

2024-05-25

以下程序:

#include <stdio.h>

int main(int argc, char *argv[])
{
  for (int j = 0; j < argc; j++)
    printf("%d: %s\n", j, argv[j]);
  return 0;
}

内置于静态链接的 PIE 中:

gcc -g -fpie main.c -static-pie -o ld.so

工作正常:

$ ./ld.so foo bar
0: ./ld.so
1: foo
2: bar

但是当我使用该程序作为 ELF 解释器时another程序:

$ gcc -g main.c -Wl,-I./ld.so -o a.out

它像这样崩溃:

gdb -q ./a.out
(gdb) run
Starting program: /tmp/a.out 

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7da84e2 in __ctype_init () at ctype-info.c:31
31    *bp = (const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS) + 128;
(gdb) bt
#0  0x00007ffff7da84e2 in __ctype_init () at ctype-info.c:31
#1  0x00007ffff7d9e3bf in __libc_init_first (argc=argc@entry=1, argv=argv@entry=0x7fffffffd728, envp=0x7fffffffd738) at ../csu/init-first.c:84
#2  0x00007ffff7d575cd in __libc_start_main (main=0x7ffff7d56e29 <main>, argc=1, argv=0x7fffffffd728, init=0x7ffff7d57ce0 <__libc_csu_init>, fini=0x7ffff7d57d70 <__libc_csu_fini>, rtld_fini=0x0, 
    stack_end=0x7fffffffd718) at ../csu/libc-start.c:244
#3  0x00007ffff7d56d6a in _start () at ../sysdeps/x86_64/start.S:120

这是为什么?

以上所有地址均在./ld.so本身,因此它在自己的初始化期间崩溃。事实上,控制永远不会达到a.out since ld.so exits.


调试时间比我预期的要长一些。

崩溃发生在:

Dump of assembler code for function __ctype_init:
   0x00007ffff7da84d0 <+0>:     mov    $0xffffffffffffffa0,%rax
   0x00007ffff7da84d7 <+7>:     mov    $0xfffffffffffffff0,%rcx
   0x00007ffff7da84de <+14>:    mov    %fs:(%rax),%rax
=> 0x00007ffff7da84e2 <+18>:    mov    (%rax),%rax
   0x00007ffff7da84e5 <+21>:    mov    0x40(%rax),%rsi

with $rax == 0. When ld.so本身会经历这段代码,$rax显然是非 NULL。显然期间出现了问题TLS设置,但是什么?

事实证明,GLIBC 初始化了它的_dl_phdr来自AT_PHDR在辅助向量中,然后迭代所有Phdrs 寻找一个PT_TLS type.

如果没有,则 GLIBC 假设没有TLS设置是必要的。

When ld.so直接运行,内核提供的 aux 向量指向Phdrs for ld.so, PT_TLS存在,一切正常。

但当ld.so runs 间接地作为翻译a.out,aux向量指向Phdrs for a.out(而不是为了ld.so——这是设计好的)。自从a.out没有任何线程局部变量,它没有PT_TLS段或者。

结论:目前还无法构建ELF口译员与-static-pie和 GLIBC,除非非常小心地避免线程本地存储。目前,避免线程本地存储似乎也不是一个选择:一个微不足道的问题int main() { return 0; }仍然有一个TLS尽管不使用但仍分段anything完全来自 GLIBC。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么独立的 C hello 程序在用作动态链接器时会崩溃 的相关文章

  • 编译器是否允许优化堆内存分配?

    考虑以下使用以下简单代码new 我知道没有delete 但这与这个问题无关 int main int mem new int 100 return 0 编译器是否允许优化new call 在我的研究中 g 5 2 0 https gcc g
  • g++、colorgcc 和 ccache

    尝试结合 ccache 和 colorgcc 下列的链接文本 http wiki tudos org Gcc stack 我的 g 是到 colorgcc 的软链接 colorgccrc 包含行 g ccache usr bin g 运行
  • gcc 和 ld 中与位置无关的可执行文件的 -fPIE 选项是什么?

    它将如何更改代码 例如函数调用 PIE是支持地址空间布局随机化 ASLR http en wikipedia org wiki Address space layout randomization在可执行文件中 在创建PIE模式之前 程序的
  • 为什么存在系统调用

    我一直在阅读有关系统调用及其在 Linux 中如何工作的内容 我还有更多的阅读要做 但我读过的一件事都没有回答 那就是 为什么我们需要系统调用 我知道系统调用是用户空间程序要求内核执行某些操作的请求 但我的问题基本上是 为什么用户空间程序本
  • VMA和ELF段之间的关系

    我需要确定 ELF 可执行文件的可加载段的 VMA VMA 可以从以下位置打印 proc pid maps VMA 之间的关系如下所示maps可加载段对我来说也很清楚 每个段由一个或多个 VMA 组成 内核使用什么方法从 ELF 段形成 V
  • MSVC 可能/不太可能等效

    GCC 编译器支持 builtin expect 语句 用于定义可能和不可能的宏 eg define likely expr builtin expect expr 1 define unlikely expr builtin expect
  • 如何让 gcc 生成合适的代码来检查缓冲区是否充满 NUL 字节?

    我正在实现一个解析磁带档案的程序 解析器逻辑的一部分是检查存档结束标记 该标记是一个充满 NUL 字节的 512 字节块 我为此编写了以下代码 希望 gcc 能对此进行很好的优化 int is eof block const char us
  • 链接器如何在没有 SONAME 的情况下找到共享库

    如果我创建一个没有这样的 SONAME 的共享库 gcc shared libfoo o o libfoo so 并链接到它 链接器如何找到我的共享库 是文件名libfoo so链接器将其视为默认 SONAME 吗 我想你是正确的 ld 手
  • RISC-V反汇编器与秒杀运行结果不符?

    我已经设置了一个 hello world 程序只是为了测试我的riscv32 unknown elf工具链 spike pk等等虽然我设法使用打印了 hello worldspike isa RV32 pk hello elf 我发现如果我
  • Cygwin 的软件包列表中没有 gcc4

    我必须在 Windows 上使用 NS 2 因此 我安装了 Cygwin 并下载了 NS 2 源代码并运行 install然后它说 Cygwin detected Note Cygwin install is still considere
  • ARM、VFP、浮点、惰性上下文切换

    我正在为 ARM 处理器 Cortex A9 编写操作系统 我正在尝试实现浮点寄存器的延迟上下文切换 这背后的想法是 浮点扩展最初对线程禁用 因此不需要在任务切换上保存浮点上下文 当线程尝试使用浮点指令时 会触发异常 然后 操作系统启用浮点
  • 使用 c11 标准和 clang 来使用 strcpy_s

    我正在运行 OS X Sierra 并尝试编译一个使用的 c 程序strcpy s 但是我安装的 clang 编译器使用的是 c99 标准 但是据我读到的 https embeddedgurus com barr code 2017 08
  • 从内存加载动态库

    是否可以从内存而不是从 mac gcc 上的文件系统加载库 在 Windows 中 我使用 MemoryModule 但它显然不跨平台兼容 首先 要做到这一点 我建议您阅读OS X ABI 动态加载器参考 https developer a
  • std::thread::id 的 std::operator== 中的分段错误

    我遇到了一个问题 我不确定如何解决 我相信这是 GCC 和 或 libstdc 中的问题 我正在运行 Ubuntu 14 04 LTS 和 GCC 4 8 2 19ubuntu1 libstdc 3 4 19 我相信 如何找到 Linux
  • 与 SSE 比较 16 字节字符串

    我有 16 字节的 字符串 它们可能更短 但您可能会假设它们在末尾用零填充 但您可能不会假设它们是 16 字节对齐的 至少不总是 如何编写一个例程将它们与 SSE 内在函数进行比较 是否相等 我发现这个代码片段可能会有帮助 但我不确定它是否
  • 为什么 GCC 不会在文件末尾生成任何有关换行符的警告?

    From C11 5 1 1 2 翻译阶段 第 2 段 非空的源文件应以换行符结尾 字符 其前面不得紧接反斜杠 发生任何此类拼接之前的字符 这意味着每个源文件都必须以换行符结尾 Example include
  • 在 gcc 中强制执行 C++98 标准

    我有一项学校作业应该用符合 C 98 的代码编写 我怎样才能强迫g 仅接受遵循此标准的代码 将要 std c 98做这个技巧还是我需要添加额外的标志 Per GCC 标准文档 http gcc gnu org onlinedocs gcc
  • 如何在 GCC 插件中添加内置函数?

    GCC 插件可以添加新的内置函数吗 如果是的话 该如何正确做呢 GCC 版本是 5 3 或更高版本 代码由C语言编写的插件编译和处理 中提到了gcc melt org 上 GCC 插件的基本原理 http starynkevitch net
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • GCC 如何运行其他程序?

    也许标题并没有那么准确地表达问题 我知道当我跑步时gcc foo cGCC 调用其他为其完成所有工作的子程序 使 gcc 主程序只是一个接口 但这到底是如何完成的呢 是否使用system or exec或者其他一些功能 我之所以想知道这个是

随机推荐