编写内核模块输出代码段的地址空间

本文介绍了一个简单的Linux内核模块实现过程,该模块能够获取指定进程的内存段信息,并展示了如何编译、加载和卸载该模块。
#include<linux/sched.h>
#include<linux/pid.h>
#include<linux/slab.h>
#include<linux/module.h>
#include<linux/kernel.h>
static int pidnum = 1;//将之前后台运行的进程的pid通过此模块参数传给模块
module_param(pidnum,int,0644);
static int hello_init(void)
{
        struct task_struct *p = NULL;
        struct mm_struct *tmp;
        struct pid *kpid = find_get_pid((int)pidnum);//用于将pidnum转换为kpid提供给pid_task
        tmp = kmalloc(sizeof(*tmp),GFP_KERNEL);
        if(tmp == NULL){
                return -1;
        }
        printk(KERN_ALERT"pidnum = %d\n",pidnum);
        p = pid_task(kpid,PIDTYPE_PID);//pid_task返回进程描述符,如果失败就按下面释放掉资源
        if(p == NULL){
                kfree(tmp);
                printk(KERN_ALERT"find faild\n");
                return -1;
        }

         if(p->mm == NULL){
                kfree(tmp);
                printk(KERN_ALERT"mm = NULL wrong\n");
        }
        else{
                tmp->start_code = p->mm->start_code;
                tmp->end_code = p->mm->end_code;
        }
        printk(KERN_ALERT"start_code : %lu, end_code :%lu",tmp->start_code,tmp->end_code);
        printk(KERN_ALERT"pid = %u\n",p->pid);
        kfree(tmp);
        return 0;
}
static void  hello_exit(void)
{
        printk(KERN_ALERT"I free the malloc memory");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Qiao");

 

1.按如上编写函数之后,还需编写Makefile文件用于编译,我的文件命名为了hello.c,下面模块名也就叫hello.ko;

 

2.make 编译生成.ko文件;

3.depmod  `pwd`/hello.ko,让modprobe 可以找到我们生产的模块,如果没有此步直接运行下一步将提示找不到模块

4.modprobe hello pidnum=(自己的进程号)

5.dmesg 可查看结果

6.modprobe -r hello ,卸载模块

### 编写嵌入式 Linux 内核模块代码 编写嵌入式 Linux 内核模块涉及特定的知识和技术细节。下面是一个简单的例子,展示了一个基础的字符设备驱动程序作为内核模块。 #### 创建一个简单字符设备驱动程序 创建一个新的 C 文件 `simple_char_device.c` 来实现此功能: ```c #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #define DEVICE_NAME "chardev" #define BUFFER_SIZE 80 static char message[BUFFER_SIZE]; static short size_of_message; // File operations structure definition. static ssize_t device_read(struct file *, char __user *, size_t, loff_t *); static ssize_t device_write(struct file *, const char __user *, size_t, loff_t *); static int device_open(struct inode *, struct file *); static int device_release(struct inode *, struct file *); struct file_operations fops = { .read = device_read, .write = device_write, .open = device_open, .release = device_release }; int major_number; short opened = 0; // Is the device open? Used to prevent multiple access. // Module initialization function that registers the character driver with kernel. static int __init simple_init(void){ printk(KERN_INFO "Simple Char Device Driver Registered\n"); // Try to dynamically allocate a major number for the device -- more difficult but worth it. major_number = register_chrdev(0, DEVICE_NAME , &fops); if (major_number<0){ printk(KERN_ALERT "Registering char device failed with %d\n", major_number); return major_number; } printk(KERN_INFO "Simple Char Device Driver Major Number: %d\n", major_number); return 0; } // Cleanup module on removal of this driver from system. static void __exit simple_exit(void){ unregister_chrdev(major_number, DEVICE_NAME ); printk(KERN_INFO "Simple Char Device Unregistered.\n"); } // Called when a process tries to open the device file, like "cat /dev/myCharDevice". static int device_open(struct inode *inodep, struct file *filep){ if(opened) return -EBUSY; opened++; memset(message, '\0', BUFFER_SIZE); // Clear out buffer area. size_of_message=0; try_module_get(THIS_MODULE); return 0; } // Called when a process closes the device file. static int device_release(struct inode *inodep, struct file *filep){ opened--; module_put(THIS_MODULE); return 0; } // Called when a process reads data from the device file. static ssize_t device_read(struct file *filep, char __user *buffer, size_t length, loff_t *offset){ int bytes_read = 0; while(size_of_message && _copy_to_user(buffer+bytes_read,message+bytes_read,1)==0){ bytes_read++; if(bytes_read==length) break; } printk(KERN_INFO "Returned %d characters read to user space\n",bytes_read); return bytes_read; } // Called when a process writes data into the device file. static ssize_t device_write(struct file *filep, const char __user *buffer, size_t length, loff_t *offset){ int i; for(i=0;i<length&&i<BUFFER_SIZE;++i){ get_user(message[i],buffer+i); size_of_message++; } printk(KERN_INFO "%s wrote %d characters to the device.\n",__builtin_strrchr(__FILE__,'/')+1,length); return i; } module_init(simple_init); module_exit(simple_exit); MODULE_LICENSE("GPL"); // License type -- this affects runtime behavior ``` 这段代码展示了如何定义并注册一个简单的字符设备驱动程序[^2]。为了使上述代码能够正常工作,在编译之前还需准备相应的 Makefile 文件用于构建模块。 #### 准备 Makefile 文件 在同一目录下创建名为 `Makefile` 的文件,并加入如下内容: ```makefile obj-m += simple_char_device.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm -rf *.o *.ko *.mod.* *.symvers *.order ``` 这使得可以通过调用 `make` 和 `make clean` 分别完成模块的编译和清理操作[^1]。 #### 加载与卸载模块 编译完成后,使用以下命令加载新创建的模块至运行中的内核中: ```bash sudo insmod ./simple_char_device.ko ``` 要移除已加载的模块,则可执行下列指令: ```bash sudo rmmod simple_char_device ``` 以上即为一个完整的流程介绍,从编写到测试一个简易版的Linux内核模块实例[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值