Linux does not use the ELF methods for dynamic objects in the kernel, Linux instead still uses a basic method to load drivers that is from the mid 1980s and that worked already with the a.out
format. There are relocatable files (similar to .o
files) that are linked for the kernel and then loaded.
The method that has been introduced in the mid 1980s work this way, either by calling a program that does the following or by having a user space daemon that does the following:
Take the driver .o
file or a file linked from several .o
files via ld -o driver -r *.o
and perform a final link step (using ld
) that links that driver to load address 0. This is needed since the COMMON variables do not show up in the size
output.
Now call size
on the resulting file to get the size needed by the driver.
Open a module loading driver and use an ioctl
to tell that driver the size of the module.
The module loading driver calls kmem_alloc()
in the kernel for text, data and bss segments and returns the addresses returned by kmem_alloc()
in the result structure of the ioctl
.
Call the linker (ld
) again but now link the driver to the addresses that have been returned by the module loading driver.
Use another call to the module loading driver that tells this driver to slurp in the driver variant that has been linked to the addresses allocated by the kernel and puts the driver content to the allocated space.
The loaded driver is now usable
If you like to look at a kernel that uses the ELF methods, I recommend to look at the Solaris kernel.
The first file that is loaded for Solaris is e.g. /platform/i86pc/kernel/amd64/unix
and this file is marked as an excutable
that depends on two shared "libraries". You can list this with the standard ELF tool 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
As you see here, the shared libraries, the basic kernel depends on are: genunix
and dtracestubs
.
So if you like to boot a Solaris kernel, you need to have a bootloader that knows about ELF and is able to load and link the shared objects, the kernel depends on.
BTW: Solaris has an in-kernel dynamic linker, so dynamically loading a driver takes less steps.