使用汇编语言编写x86_64 Linux内核模块

11

我尝试用nasm编写一个简单的内核模块(版本为v3.6),但是insmod告诉我:

$ sudo insmod  ./hello.ko
insmod: ERROR: could not insert module ./hello.ko: Invalid module format
$ echo $?
1

我使用以下方式编译我的代码:

$ nasm -f elf64 -o hello.m hello.asm
$ ld -m elf_x86_64 -r -o hello.ko hello.m

以及我的模块代码:

section .modinfo
    __mod_kernel_version db "kernel_version=3.6.8", 0
    __mod_license        db "license=GPL", 0
    __mod_author         db "author=actics", 0
    __mod_description    db "description=hello world module in nasm", 0


section .data
    init_mess    db "init_module", 10, 0
    cleanup_mess db "cleanup_module", 10, 0


section .text
    global init_module
    global cleanup_module

    extern printk

init_module:
    push rbp
    mov rbp, rsp

    xor rax, rax
    mov rdi, init_mess
    call printk

    xor rax, rax
    mov rsp, rbp
    pop rbp
    ret

cleanup_module:
    push rbp
    mov rbp, rsp

    xor rax, rax
    mov rdi, cleanup_mess
    call printk

    xor rax, rax
    mov rsp, rbp
    pop rbp
    ret
请帮忙。在互联网上我找到一个链接,其中包含适用于2.4版本的相同代码,但是它也不起作用。 我的系统是带有3.6.8内核的archlinux。
更新: 在nasm论坛中,我找到了一个有趣的解决方案的帖子。对我来说它有效,如果我的模块返回0并退出 :) 但是,如果我尝试添加“extern printk”,insmod会向我发出以下消息:
ERROR: could not insert module hello.ko: Invalid parameters

我做错了什么?我的代码:

[bits 64]

global init_module
global cleanup_module

;extern printk

section .modinfo
    __mod_description8  db   'description=Simple module',0
    align 16,db 0
    __mod_author7       db   'author=That´s me',0
    __mod_license6      db   'license=GPL',0
    align 16,db 0
    __module_depends    db   'depends=',0
    align 32,db 0
    __mod_vermagic5     db   'vermagic=3.6.8-1-ARCH SMP preempt mod_unload modversions ',0   ;from a .ko module of my system

section __versions
    ____versions      db   0xdf, 0xbc, 0xbf, 0x8c, 0, 0, 0, 0, "module_layout"   ;from a .ko module of my system
    align 64,db 0

section .data
    init_mess    db "init_module", 10, 0
    cleanup_mess db "cleanup_module", 10, 0


section .text

init_module:
    xor rax, rax
    ret

cleanup_module:
    xor rax, rax
    ret

section .gnu.linkonce.this_module
    times 24 db 0
__name:         db  'Simple', 0
    times (0x168 - 24 - 7) db 0
__init_module:      dq  init_module
    times 0x2ac db 0
__cleanup_module:   dq  cleanup_module
    times 1152 db 0

这段代码可以使用以下命令编译运行:

nasm -f elf64 hello.asm -o hello.o

但是如果我取消注释 printk,代码将无法正常工作!

3个回答

16
我写了一个小的C语言包装器,使用标准的模块宏并将其与写在汇编语言中的主模块代码链接。使用正常的内核构建系统进行构建。
module.c:
    #include <linux/module.h>
    MODULE_AUTHOR("A. U. Thor");
    MODULE_DESCRIPTION("Description");
    MODULE_LICENSE("GPL");
    extern int asm_init(void);
    int main_init(void)
    {
        return asm_init();
    }
    module_init(main_init);

main.asm:

    [bits 64]
    global asm_init
    asm_init:
        xor rax, rax
        ret

Makefile:

obj-m += test.o
test-objs := module.o main.o
$(KBUILD_EXTMOD)/main.o: main.asm
        nasm -f elf64 -o $@ $^

obj-m += memory_asm.o
memory_asm-objs := module.o main.o
$(KBUILD_EXTMOD)/main.o: $(src)/main.asm
    nasm -f elf64 -o $@ $^ && echo "" > $(src)/.main.o.cmd

使用以下命令进行构建: make -C <path_to_kernel_src> M=$PWD


Jester,谢谢你,这是一个非常好的解决方案。在我的情况下它可以工作,但有一些问题。我会尽力做好的。 - Alexander Lavrukov
一切工作正常。但我们只能在module.c中定义include和MODULE宏。我不使用extern,因为在asm文件中我将函数命名为init_module。 - Alexander Lavrukov

0

将Makefile更改为:

obj-m += memory_asm.o
memory_asm-objs := module.o main.o
$(KBUILD_EXTMOD)/main.o: $(src)/main.asm
    nasm -f elf64 -o $@ $^ && echo "" > $(src)/.main.o.cmd

-2

你必须使用gcc编译它,并将其与内核目录链接...


欢迎来到SO!感谢您抽出时间回答这个问题。您能否提供更多关于您解决方案的细节?例如,为什么您的解决方案比被接受的答案更好?此外,该问题是7年前提出并回答的。在回答时,请务必查看原始问题的日期。请阅读如何回答 - above_c_level

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接