我尝试用汇编语言编写内核模块。有一次我需要一个全局变量。我在 .data(或 .bss)部分定义了一个双字,并在 init 函数中尝试将 1 添加到 var。我的程序 seccesfully make,但 insmod 看到我:
$ sudo insmod ./test.ko
insmod: ERROR: could not insert module ./test.ko: Invalid module format
这是我在 nasm 中的汇编代码:
[bits 64]
global init
global cleanup
extern printk
section .data
init_mess db "Hello!", 10, 0
g_var dd 0
section .text
init:
push rbp
mov rbp, rsp
inc dword [g_var]
mov rdi, init_mess
xor rax, rax
call printk
xor rax, rax
mov rsp, rbp
pop rbp
ret
cleanup:
xor rax, rax
ret
如果我在 C 代码中添加,一切正常:
static i = 0;
static int __init main_init(void) { i++; return init(); }
但是在这个 objdump -d test.ko
中为我写了一个非常稳定的代码:
0000000000000000 <init_module>:
0: 55 push %rbp
1: ff 05 00 00 00 00 incl 0x0(%rip) # 7 <init_module+0x7>
7: 48 89 e5 mov %rsp,%rbp
a: e8 00 00 00 00 callq f <init_module+0xf>
f: 5d pop %rbp
10: c3 retq
这是什么意思(包括 0x0(%rip))?我怎样才能访问内存?请帮我 :) (我的系统是archlinux x86_64)
我的正确制作模块的 C 代码:
#include <linux/module.h>
#include <linux/init.h>
MODULE_AUTHOR("Actics");
MODULE_DESCRIPTION("Description");
MODULE_LICENSE("GPL");
extern int init(void);
extern int cleanup(void);
static int __init main_init(void) { return init(); }
static void __exit main_cleanup(void) { cleanup(); }
module_init(main_init);
module_exit(main_cleanup);
和我的 Makefile:
obj-m := test.o
test-objs := inthan.o module.o
KVERSION = $(shell uname -r)
inthan.o: inthan.asm
nasm -f elf64 -o $@ $^
build:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
最佳答案
内核模式位于地址空间的“负”(即顶部)部分,其中不能使用 32 位绝对地址(因为它们未进行符号扩展)。正如您所注意到的,gcc 使用 rip-relative 地址来解决这个问题,该问题给出了当前指令指针的偏移量。您可以使用 DEFAULT REL
指令让 nasm 做同样的事情。查看relevant section in the nasm documentation .
关于linux - 在汇编程序中编写 linux 内核模块时的内存访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13711524/