共享标准 C 库是否首先由内核初始化?

Is shared standard C library first initialized by kernel?

我正在尝试了解链接器和加载器的操作,以及关于程序实际编译和执行方式的内存地址(物理或虚拟)。遇到了两条信息,形成了自己的理解版本

第一个信息:

W.5.1 SHARED OBJECTS In a typical system, a number of programs will be running. Each program relies on a number of functions, some of which will be standard C library functions, like printf(), malloc(), strcpy(), etc. and some are non-standard or user defined functions. If every program uses the standard C library, it means that each program would normally have a unique copy of this particular library present within it. Unfortunately, this result in wasted resources, degrade the efficiency and performance. **Since the C library is common, it is better to have each program reference the common, one instance of that library, instead of having each program contain a copy of the library. This is implemented during the linking process where some of the objects are linked during the link time whereas some done during the run time (deferred/dynamic linking). **

第二个信息:

C Library

Main Articles: See C Library, Creating a C Library One thing up front: When you begin working on your kernel, you do not have a C library available. You have to provide everything yourself, except a few pieces provided by the compiler itself. You will also have to port an existing C library or write one yourself. The C library implements the standard C functions (i.e., the things declared in , , etc.) and provides them in binary form suitable for linking with user-space applications. In addition to standard C functions (as defined in the ISO standard), a C library might (and usually does) implement further functionality, which might or might not be defined by some standard. The standard C library says nothing about networking, for example. For Unix-like systems, the POSIX standard defines what is expected from a C library; other systems might differ fundamentally. It should be noted that, in order to implement its functionality, the C library must call kernel functions. So, for your own OS, you can of course take a ready-made C library and just recompile it for your OS - but that requires that you tell the library how to call your kernel functions, and your kernel to actually provide those functions. A more elaborate example is available in Library Calls or, you can use an existing C Library or create your own C Library.

我的理解方式:

当计算机启动时,它首先无法访问 C 库,而是必须使用机器代码。但是在引导代码的帮助下,它最终会开始加载OS。在此示例中,我将假设一台计算机加载 linux OS。自然会加载 linux 内核。

当启动 linux 内核时,这也意味着标准 C 库(例如 printf 等基本函数)也被加载到低内存(分配给内核的 RAM 部分 space ).假设用户使用标准 C 库中的 printf() 编写了一个简单的代码。用户将编译此代码,在此过程中,链接器将为 printf() 创建一个 'reference',表示 printf() 函数驻留在低内存中的位置。 执行此代码时,加载程序会将保存在 HDD 中的此可执行文件加载到高端内存(分配给用户 space 的 RAM 部分)。当进程遇到 printf() 函数时,它将跳转到包含 printf() 函数开始的低内存地址。

我说的对吗?如果不是,我哪里错了?

你错了。

1.) 无需将libc放入内核。它不会影响任何低级系统或硬件相关组件。

2.) libc.so为普通动态库

现在更详细一些:

启动应用程序时,f.e。从 bash 控制台,bash 分叉并执行新进程。这是什么意思。实际上,这意味着 OS 创建地址 space 环境并从 ELF 文件加载 .text .data .bss,为堆栈保留虚拟 space。您可以在此处查看此映射:

sudo cat /proc/1118/maps 
00400000-00407000 r-xp 00000000 08:01 1845158                            /sbin/getty
00606000-00607000 r--p 00006000 08:01 1845158                            /sbin/getty
00607000-00608000 rw-p 00007000 08:01 1845158                            /sbin/getty
00608000-0060a000 rw-p 00000000 00:00 0 
00ff3000-01014000 rw-p 00000000 00:00 0                                  [heap]
...
7f728efd3000-7f728efd5000 rw-p 001bf000 08:01 466797                     /lib/x86_64-linux-gnu/libc-2.19.so
7f728efd5000-7f728efda000 rw-p 00000000 00:00 0 
7f728efda000-7f728effd000 r-xp 00000000 08:01 466799                     /lib/x86_64-linux-gnu/ld-2.19.so

7f728f1fe000-7f728f1ff000 rw-p 00000000 00:00 0 
7fffa122b000-7fffa124c000 rw-p 00000000 00:00 0                          [stack]
7fffa1293000-7fffa1295000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

但还有更多。加载这些段后,Linux 内核还会将 ld-linux.so 加载到内存中(您可以在映射中看到它)。这个东西叫动态链接器,其实ld-linux是负责所有动态库加载的。您可能知道,在编译应用程序时,您已经知道将使用的共享库列表。可以通过ldd命令查看

ldd /sbin/getty 
linux-vdso.so.1 =>  (0x00007fff4cfa6000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2af2832000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2af2c24000)

这些东西必须保存在 ELF 的某个地方(不知道具体在哪里)。因此,加载后,ld-linux 使用此列表并在预定义(标准)路径(如 /usr/lib 等)中找到所有需要的库。现在 ld-linux 只能 mmap 定位动态库的区域。这就是将 libc 加载到进程地址 space.

的方式

ah... then I guess what I presumed in my original question seems to be partially right: kernel having the original copy of library ready in RAM which can be shared with other processes(for text segments). thanks you for your insight

你比你想的还要对:) 看这个:linux-vdso.so.1 => (0x00007fff4cfa6000) 这几乎是一个"standard C library(basic functions like printf for example) ... also loaded on to low memory"。好吧,不是在低内存中:)和非标准(就 C 而言),大部分时间由 C 库而不是直接使用代码,但是是的:由内核加载到用户空间作为 linux 中的一组标准函数语境。 http://man7.org/linux/man-pages/man7/vdso.7.html