IT袋

当前位置:主页 > 经验教程 > 系统教程 >

Linux

Linux 下“Hello World”的幕后发生了什么(8)

时间:2023-09-17 20:02:06 来源:IT袋 作者:苏晓敏
导读:Linux,init 区域(或者也可能是 .ctors 区域)。 自行验证 :让我们使用 readelf 来看看这个: $ readelf -a /lib/x86_64-linux-gnu/libpthread.so.0... [10] .rela.plt RELA 00000000000051

Linux

init区域(或者也可能是.ctors区域)。

自行验证:让我们使用readelf来看看这个:

$ readelf -a /lib/x86_64-linux-gnu/libpthread.so.0
...
  [10] .rela.plt         RELA             00000000000051f0  000051f0
       00000000000007f8  0000000000000018  AI       4    26     8
  [11] .init             PROGBITS         0000000000006000  00006000
       000000000000000e  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         0000000000006010  00006010
       0000000000000560  0000000000000010  AX       0     0     16
...

这个库没有.ctors区域,只有一个.init。但是,.init区域都有些什么内容呢?我们可以使用objdump来反汇编这段代码:$ objdump -d /lib/x86_64-linux-gnu/libpthread.so.0 Disassembly of section .init: 0000000000006000

所以它在调用
__pthread_initialize_minimal。我在 glibc 中找到了这个函数的代码,尽管我不得不找到一个较早版本的 glibc,因为在更近的版本中,libpthread不再是一个独立的库。

我不确定这个set_tid_address系统调用是否实际上来自
__pthread_initialize_minimal,但至少我们知道了库可以通过.init区域在启动时运行代码。

这里有一份关于 .init 区域的 elf 手册的笔记:

$ man elf

.init这个区域保存着对进程初始化代码有贡献的可执行指令。当程序开始运行时,系统会安排在调用主程序入口点之前执行该区域中的代码。

在 ELF 文件中也有一个在结束时运行的.fini区域,以及其他可以存在的区域.ctors/.dtors(构造器和析构器)。

好的,关于动态链接就说这么多。

9、转到 _start

在动态链接完成后,我们进入到 Python 解释器中的_start。然后,它将执行所有正常的 Python 解析器会做的事情。

我不打算深入讨论这个,因为我在这里关心的是关于如何在 Linux 上运行二进制文件的一般性知识,而不是特别针对 Python 解释器。

10、写入字符串

不过,我们仍然需要打印出 “hello world”。在底层,Python 的print函数调用了 libc 中的某个函数。但是,它调用了哪一个呢?让我们来找出答案!

自行验证:运行ltrace -o out python3 hello.py

$ ltrace -o out python3 hello.py
$ grep hello out
write(1, "hello worldn", 12) = 12

看起来它确实在调用write函数。

我必须承认,我对ltrace总是有一些疑虑 —— 与我深信不疑的

相关阅读