Introdução a Linux Kernel Module em Assembly x64

Aproveitando para me familiarizar com assembly para x86_64, resolvi por em prática uma ideia antiga de fazer um LKM qualquer em Assembly. Enquanto não vem uma ideia de um módulo útil, mostrarei como é simples fazer puramente em assembly, usando a sintaxe AT&T e o GAS (GNU Assembler).

Antes de mais nada, a versão do kernel que estou usando é 2.6.32-5-amd64, pode ser que o código não funcione em versões mais recentes. (Os caras vivem mudando a API)

Basicamente o esqueleto do módulo precisa ter duas funções: init_module, e cleanup_module, respectivamente destinado à inicialização (insmod), e finalização do módulo (rmmod). [1]

Além disso, incluiremos informações que descrevam o módulo, aquelas informações que são vista usando `modinfo'. [2]

Vamos ao código!

	.section .rodata
init_msg: .string "<1>Modulo inicializado!\n"
exit_msg: .string "<1>Modulo finalizado!\n"
 
	.section .text
.global init_module
.global cleanup_module
 
init_module:
	leaq init_msg, %rdi
	callq printk
 
	xorq %rax, %rax
	ret
 
cleanup_module:
	leaq exit_msg, %rdi
	callq printk
 
	xorq %rax, %rax
	ret
 
	.section .modinfo, "aS", @progbits
__kernel_version:     .string "kernel_version=2.6.32"
__module_license:     .string "license=GPL"
__module_author:      .string "author=Felipe Pena"
__module_depends:     .string "depends="
__module_description: .string "description=Modulo de teste"

.oO(Ficou ruim esse highlight!)

Note que a string começa com <1>, isto serve para informar o tipo de mensagem, que no caso, se refere um ALERT. Essa numeração dentro menor e maior são adicionadas quando usando as macros em C: KERN_ALERT, KERN_WARNING etc.

O Kernel usa internamente mesma convenção que aplicações em user-level. Porém os registradores usandos na interface com o kernel são: %rdi, %rsi, %rdx, %r10, %r8 e %r9. [3]

Note que no final usamos a sintaxe do GAS para criar uma seção no ELF com as flags "aS", que significa que a seção possui dados que deverão estar no arquivo objeto (a), e que contém strings terminadas com zero (S). E o @progbits para dizer que a seção contém dados. [4]

Para compilar este código (o arquivo foi nomeado hello.S) e gerar o módulo usaremos o seguinte Makefile:

obj-m  := test.o
test-objs := hello.o
 
 
KDIR   := /lib/modules/$(shell uname -r)/build
PWD    := $(shell pwd)
 
default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
 
clean:
	rm -rf *.ko *.o *.order *.symvers *.mod.c .*.cmd .tmp_versions

E então vamos ao teste!

$ sudo insmod test.ko
$ dmesg | tail -1
[52634.041113] Modulo inicializado!
$ sudo modinfo test.ko 
filename:       test.ko
kernel_version: 2.6.32
license:        GPL
author:         Felipe Pena
depends:        
description:    Modulo de teste
depends:        
vermagic:       2.6.32-5-amd64 SMP mod_unload modversions 
$ sudo rmmod  test.ko 
$ dmesg | tail -1
[52736.374236] Modulo finalizado!

Para ver outros exemplos de LKM em assembly, até mesmo com versões antigas do Kernel veja o último link nas referências.

Referências

[1] http://tldp.org/LDP/lkmpg/2.4/html/x149.html
[2] http://linux.about.com/od/lkm_howto/a/hwtlkm11t01.htm
[3] http://www.x86-64.org/documentation/abi.pdf
[4] http://sourceware.org/binutils/docs/as/Section.html#Section
[5] http://rudy.mif.pg.gda.pl/~bogdro/linux/sys_tut_linux.html

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options