共享对象文件和可重定位文件有什么区别?

共享对象文件和可重定位文件有什么区别?

https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/

类型字段告诉我们该文件的用途是什么。有几种常见的文件类型。

CORE (value 4)
DYN (Shared object file), for libraries (value 3)
EXEC (Executable file), for binaries (value 2)
REL (Relocatable file), before linked into an executable file (value 1)

https://unix.stackexchange.com/a/476157/674表明内核模块是 REL。为什么是 REL 而不是 DYN?

DYN 和 REL 有什么区别?

谢谢。

答案1

系统 V ABI,其中包含 ELF 格式的规范。它说

不同目标文件的重定位条目对成员的解释略有不同r_offset

  • 在可重定位文件中,r_offset保存节偏移量。也就是说,重定位节本身描述了如何修改文件中的另一个节;重定位偏移指定第二部分内的存储单元。

  • 在可执行文件和共享目标文件中,r_offset保存虚拟地址。为了使这些文件的重定位条目对动态链接器更有用,节偏移(文件解释)让位于虚拟地址(内存解释)。

可重定位文件仍然是完全可重定位的,而共享对象则在链接过程中更进一步,并且已大部分被重定位。仅当共享对象的代码与位置无关时,共享对象才可重定位(例如它是用 GCC 的-fPIC选项构建的)。

内核模块需要可重定位而不与位置无关,因此它们作为可重定位文件提供。

答案2

Linux 不使用 ELF 方法来处理内核中的动态对象,相反,Linux 仍然使用 20 世纪 80 年代中期的基本方法来加载驱动程序,并且该方法已经适用于该a.out格式。有可重定位文件(类似于.o文件),它们链接到内核然后加载。

20 世纪 80 年代中期引入的方法就是这样工作的,要么通过调用执行以下操作的程序,要么通过让用户空间守护进程执行以下操作:

  • 获取驱动程序文件或通过多个文件.o链接的文件,并执行最终链接步骤(使用),将该驱动程序链接到加载地址 0。这是必需的,因为 COMMON 变量不会显示在输出中。.old -o driver -r *.oldsize

  • 现在调用size生成的文件来获取驱动程序所需的大小。

  • 打开模块加载驱动程序并使用ioctl告诉该驱动程序模块的大小。

  • 加载驱动程序的模块kmem_alloc()在内核中调用文本、数据和 bss 段,并返回.kmem_alloc()ioctl

  • 再次调用链接器 ( ld),但现在将驱动程序链接到模块加载驱动程序返回的地址。

  • 使用对模块加载驱动程序的另一个调用,告诉该驱动程序装入已链接到内核分配的地址的驱动程序变体,并将驱动程序内容放入分配的空间。

  • 加载的驱动程序现在可以使用了

如果您想查看使用 ELF 方法的内核,我建议查看 Solaris 内核。

为Solaris 加载的第一个文件是eg /platform/i86pc/kernel/amd64/unix,该文件被标记为excutable依赖于两个共享“库”的文件。您可以使用标准 ELF 工具列出它dump

dump -Lv /platform/i86pc/kernel/amd64/unix  

/platform/i86pc/kernel/amd64/unix:

  **** DYNAMIC SECTION INFORMATION ****
.dynamic:
[INDEX] Tag         Value
[1]     NEEDED          genunix
[2]     NEEDED          dtracestubs
[3]     HASH            0xfffffffffb8c1040
[4]     STRTAB          0xfffffffffb8e4e10
[5]     STRSZ           0xf584
[6]     SYMTAB          0xfffffffffb8c9fc0
[7]     SYMENT          0x18
[8]     CHECKSUM        0x4445
[9]     TEXTREL         0
[10]    RELA            0xfffffffffb8f4398
[11]    RELASZ          0x16470
[12]    RELAENT         0x18
[13]    FEATURE_1       PARINIT
[14]    SUNW_CAP        0xfffffffffb8a37a8
[15]    FLAGS           TEXTREL
[16]    FLAGS_1         [ NOHDR ]
[17]    SUNW_STRPAD     0x200
[18]    SUNW_LDMACH     EM_AMD64

file /platform/i86pc/kernel/unix        
/platform/i86pc/kernel/unix:       ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not stripped, no debugging information available

正如您在这里看到的,基本内核依赖的共享库是:genunixdtracestubs

因此,如果您想引导 Solaris 内核,则需要有一个了解 ELF 并能够加载和链接内核所依赖的共享对象的引导加载程序。

顺便说一句:Solaris 有一个内核动态链接器,因此动态加载驱动程序需要更少的步骤。

相关内容