以下引导文件 (vmlinux64) 适用于 Linux 内核 v2.6.21.7(发行版:Cavium-Octeon for MIPS64):
ELF HEADER:
------------------------------------------
Magic: 0x7f 0x45 0x4c 0x46 ("ELF")
Class: 64-bit
Encoding: Big-Endian
ELF version: 1
OS ABI: System V
ABI Version: 0
Type: ET_EXEC
Machine: MIPS
Version: 1
Entry Point: 0xffffffff804b0000
Program Headers Offset: 0x40
Section Headers Offset: 0x572C70
Flags: 0x808b0001
ELF Header Size: 0x40
Program Header Entry Size: 0x38
Program Header Entries: 1
Section Header Entry Size: 0x40
Section Header Entries: 0x21
.shstrtab Index: 0x20
有这些段和部分:
_______________________________________________________________________________________________
PROGRAM HEADERS:
_______________________________________________________________________________________________
Index Type Flags SizeInMem MemVirtAddress FileOffs SizeInFile
-----------------------------------------------------------------------------------------------
0 PT_LOAD Write+Read+Exec 0x5AB200 0xffffffff80100000 0x4000 0x56EAC7
_______________________________________________________________________________________________
SECTION HEADERS:
_______________________________________________________________________________________________
Index Name Type Flags MemVirtAddress FileOffs SizeInFile
-----------------------------------------------------------------------------------------------
0 K_NULL 0x0 0x0 0x0
1 .text K_PROGBITS Alloc+Exec 0xffffffff80100000 0x4000 0x30DFE8
2 __ex_table K_PROGBITS Alloc+ 0xffffffff8040dff0 0x311FF0 0x5EA0
3 __dbe_table K_PROGBITS Alloc+ 0xffffffff80413e90 0x317E90 0x0
4 .rodata K_PROGBITS Alloc+ 0xffffffff80414000 0x318000 0x48B68
5 .pci_fixup K_PROGBITS Alloc+ 0xffffffff8045cb68 0x360B68 0xB20
7 __ksymtab K_PROGBITS Alloc+ 0xffffffff8045d688 0x361688 0x8EA0
8 __ksymtab_gpl K_PROGBITS Alloc+ 0xffffffff80466528 0x36A528 0x2580
17 __ksymtab_strings K_PROGBITS Alloc+ 0xffffffff80468aa8 0x36CAA8 0xEBA8
18 __param K_PROGBITS Alloc+ 0xffffffff80477650 0x37B650 0x6E0
19 .data K_PROGBITS Alloc+Write 0xffffffff80478000 0x37C000 0x2FD20
20 .data.cacheline_aligned K_PROGBITS Alloc+Write 0xffffffff804a8000 0x3AC000 0x7280
21 .init.text K_PROGBITS Alloc+Exec 0xffffffff804b0000 0x3B4000 0x31270
22 .init.data K_PROGBITS Alloc+Write 0xffffffff804e1270 0x3E5270 0x3708
23 .init.setup K_PROGBITS Alloc+Write 0xffffffff804e4980 0x3E8980 0x5B8
24 .initcall.init K_PROGBITS Alloc+Write 0xffffffff804e4f38 0x3E8F38 0x6D8
25 .con_initcall.init K_PROGBITS Alloc+Write 0xffffffff804e5610 0x3E9610 0x10
27 .exit.text K_PROGBITS Alloc+Exec 0xffffffff804e5620 0x3E9620 0x30C0
28 .init.ramfs K_PROGBITS Alloc+ 0xffffffff804e9000 0x3ED000 0x185AC7
32 .shstrtab K_STRTAB 0x0 0x572AC7 0x1A7
6 .rio_route K_PROGBITS Write 0xffffffff8045d688 0x572AC7 0x0
9 __ksymtab_unused K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
10 __ksymtab_unused_gpl K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
11 __ksymtab_gpl_future K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
12 __kcrctab K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
13 __kcrctab_gpl K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
14 __kcrctab_unused K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
15 __kcrctab_unused_gpl K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
16 __kcrctab_gpl_future K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0
26 .security_initcall.init K_PROGBITS Write 0xffffffff804e5620 0x572AC7 0x0
29 .sbss K_PROGBITS Alloc+Write 0xffffffff8066f000 0x572AC7 0x0
30 .bss K_NOBITS Alloc+Write 0xffffffff80670000 0x572AC7 0x3AEF0
31 .cvmx_shared_bss K_NOBITS Alloc+Write 0xffffffff806aaef0 0x572AC7 0x310
_______________________________________________________________________________________________
请注意,此 ELF 文件有一个嵌入的 1558kB init.ramfs 部分,其中包含对操作系统至关重要的文件。这部分是 gzip 的,包含一个包含 1805 个文件和目录的 cpio 存档。
根据: Kernel.org 和 Wikipedia,Linux Kernel cpio 提取器将这个 init.ramfs 部分解压缩到内存中的某个位置。
我的问题是:
- 是什么决定了提取 cpio 存档内容的内存地址?
- 提取后,内核如何找到特定文件的数据的内存地址,...例如 /sbin/init 文件?
- cpio 存档的内容是否被提取到某种文件系统中,允许内核稍后找到这些文件......或者这些文件的内存地址是否在内核代码中硬编码?
回复:问题 1:我不认为 .init.ramfs 部分可以解压缩到 ELF 文件的部分标题中所述的 0xffffffff804e9000 内存地址,因为在下一部分之前只有 1560kB 可用空间(“. sbss") 从内存中的 0xffffffff8066f000 开始,而 ungzip 的 cpio 存档占用 4035kB。
进入文件系统。使用的文件系统类型是ramfs或tmpfs。在您提到的链接之一中对此进行了详细说明。
https://github.com/torvalds/linux/blob/v4.17/Documentation/filesystems/ramfs-rootfs-initramfs.txt
ramfs 和 tmpfs 的工作方式非常相似;这个问题没有太大区别。initramfs 使用哪种类型可能会有所不同,例如在内核版本之间(如果您需要知道,请阅读此内容)。在 initramfs 之外,一般规则是始终使用 tmpfs。tmpfs 限制最大空间使用量,以防止内存不足和系统崩溃。
“ramfs-rootfs-initramfs.txt”的第一部分解释了ramfs文件数据是在页面缓存中分配的,这与用于缓存来自物理文件系统的文件数据的结构相同。ramfs 文件页面也可以换出到交换设备,就像进程内存一样。
我可以告诉你,页面缓存非常接近最低级别的分配器,即内核页面分配器。页面分配器在启动时被交给所有可用的物理 RAM 区域;这些将排除初始内核部分。可用的物理内存区域由引导加载程序/固件传递给内核。如命令所示,您应该在内核日志早期的一系列行中看到这些区域
dmesg
。稍后在内核日志中,当页面分配器被交给不再需要的 init mem 时,您可以看到该消息,包括已释放的 init.ramfs 部分。(IIRC 在页面分配器之前有一些单独的非常早期的分配器,但这不是引导 IMO 中最令人兴奋的细节)。
页面缓存从内存中的 inode 链接,也就是vnodes。通过内存中的dentry 缓存查找vnode 。 dentry = 缓存中的目录条目。
它可以解压缩到 RAM 中任何地方的临时缓冲区,例如使用页面分配器。也就是说,我假设提取过程是流式传输的。也就是说,它可以使用与
gzip -d | cpio --extract
. 在将文件从存档复制到 tmpfs 时,这种方法避免了需要一个缓冲区来保存整个未压缩的 cpio 存档。