O Linux não usa os métodos ELF para objetos dinâmicos no kernel, o Linux ainda usa um método básico para carregar drivers de meados dos anos 80 e que já funcionavam com o formato a.out
. Existem arquivos relocáveis (semelhantes a .o
files) que são vinculados ao kernel e carregados.
O método que foi introduzido em meados da década de 1980 funciona dessa maneira, seja chamando um programa que faz o seguinte ou tendo um daemon de espaço do usuário que faz o seguinte:
-
Pegue o arquivo .o
do driver ou um arquivo vinculado de vários .o
arquivos via ld -o driver -r *.o
e execute uma etapa final do link (usando ld
) que vincula esse driver ao endereço de carregamento 0. Isso é necessário, pois as variáveis COMMON não aparecem na saída size
.
-
Agora, chame size
no arquivo resultante para obter o tamanho necessário para o driver.
-
Abra um driver de carregamento do módulo e use um ioctl
para informar a esse driver o tamanho do módulo.
-
O driver de carregamento do módulo chama kmem_alloc()
no kernel para segmentos de texto, dados e bss e retorna os endereços retornados por kmem_alloc()
na estrutura de resultados de ioctl
.
-
Chame o vinculador ( ld
) novamente, mas agora vincule o driver aos endereços que foram retornados pelo driver de carregamento do módulo.
-
Use outra chamada para o driver de carregamento do módulo que instrui esse driver a fazer um "slurp" na variante do driver que foi vinculada aos endereços alocados pelo kernel e coloca o conteúdo do driver no espaço alocado.
-
O driver carregado agora pode ser usado
Se você gosta de olhar para um kernel que usa os métodos ELF, eu recomendo olhar para o kernel do Solaris.
O primeiro arquivo carregado para o Solaris é, por exemplo, /platform/i86pc/kernel/amd64/unix
e este arquivo está marcado como excutable
que depende de duas "bibliotecas" compartilhadas. Você pode listar isso com a ferramenta ELF padrão 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
Como você vê aqui, as bibliotecas compartilhadas, das quais o kernel básico depende, são: genunix
e dtracestubs
.
Então, se você gosta de inicializar um kernel do Solaris, você precisa ter um gerenciador de inicialização que saiba sobre o ELF e seja capaz de carregar e vincular os objetos compartilhados, do qual o kernel depende.
BTW: O Solaris possui um vinculador dinâmico no kernel, portanto, carregar dinamicamente um driver leva menos etapas.