内核模块加载之虚拟内核空间

内核模块加载之虚拟内核空间


前面讲过,在32位平台的linux下,0-3G是用户程序可访问的,后面1G是内核空间专用的。
那么我们可以来做实验感受一下。
当然,写个普通的main函数就能够到达输出0-3G的空间地址,然而内核空间的地址不是用户程序能够访问的,要不就乱套了(其他进程也共享了这片内核空间)。
不过,我们可以有办法来输出,那就是利用加载内核模块的方法。
首先,我们看看输出用户空间的代码,简单的main函数即可。

#include <stdio.h>

#include <malloc.h>

#include <unistd.h>



int bss_var;

int data_var0 = 1;



int main(int argc,char **argv)

{

	printf("The user space's address division of a process as follow:\n");

	printf("Data segment:\n");

	printf("address of \"main\" function:%p\n",main);

	

	int stack_var0=2;

	printf("Stack segment:\n");

	printf("initial end of stack:%p\n",&stack_var0);

	int stack_var1=3;

	printf("new end of stack:%p\n",&stack_var1);

	

	printf("Data segment:\n");

	printf("address of data_var:%p\n",&data_var0);

	static int data_var1=4;

	printf("new end of data_var:%p\n",&data_var1);

	

	printf("BSS:\n");

	printf("address of bss_var:%p\n",&bss_var);



	char *str=(char *)malloc(sizeof(char)*10);

	printf("initial heap end:%p\n",str);

	char *buf=(char *)malloc(sizeof(char)*10);

	printf("new heap end:%p\n",buf);



/*	char *b=sbrk((ptrdiff_t)0);

	printf("Heap location:\n");

	printf("initial end fo head:%p\n",b);

	brk(b+4);

	b=sbrk((ptrdiff_t)0);



	printf("new end of heap:%p\n",b);

*/

	return 0;

}



输出:
The user space's address division of a process as follow:

Data segment:

address of "main" function:0x8048454

Stack segment:

initial end of stack:0xbf99c66c

new end of stack:0xbf99c668

Data segment:

address of data_var:0x804a01c

new end of data_var:0x804a020

BSS:

address of bss_var:0x804a02c

initial heap end:0x8b3f008

new heap end:0x8b3f018

我们可以用个图来表示一下,用户空间的大概格局。






 BSS和数据段通常是在一起的,而代码段和栈(通常我们说堆栈就是说的
是栈)往往独立存放,且栈是向下生长的,堆向上生长,但是,她们几乎不会碰头,你可以看看上面的输出就知道它们间的距离有多大了。

这个矩形从0x000000开始,到0xBFFFFFF结束
0xC0000000-0xFFFFFFFF是内核空间,你没办法在用户程序中输出这里面的地址,不过前面讲了,我们可以利用内核模块加载的办法来访问之。。



下面是访问内核空间的办法,也即要靠加载模块。翻篇了。。



下面说说模块编程和应用程序编程的比较:





                          用户应用程序              内核模块程序


使用函数            libc库                     内核函数
运行空间        	用户空间	 		     内核空间
运行权限	       普通用户				超级用户
入口函数		 main()				modules_init()	
出口函数		exit()					modules_exit()
编译			gcc -c                                                Makefile

链接			gcc								 insmod	
运行            直接运行							 insmod
调试		    GDB									kdbug 等工具




首先就是要会编写内核加载的Makefile文件



这里给出一个例子,然后说明

obj-m:=mymodule.o

KDIR:=/lib/modules/$(shell uname -r)/build

PWD:=$(shell pwd)

all:

	make -C $(KDIR) M=$(PWD) modules



clean:	

	rm -rf *.o *.ko *.mod.c *sym*  *.un*

	
   


第一行是定义要生成的目标文件,不过后来也会生成.ko的文件。

第二行是头文件路径:在内核编程的时候会用到内核中的头文件,这些在平时
编程中的include里面没有,须字节找到路径。
在找这个路径的时候我犯了很多错误。
首先要注意的是,原始的路径是在/usr/src/kernle/$(uname -r)/include
但在lib/modules/$(uname -r)/这个文件夹下面会有一个链接文件build是链接到上面这个路径的,所以,可以就用这个build链接文件即可。
再次药注意的是,如果这个build文件是红色的,那代表你没有链接成功,我就是在这一步出了问题,报告老是找不到头文件,就是因为链接没有成功,这时先删除掉原理的build,重新建立build 

touch build
ln -s ../../usr/src/kernel/$(uname -r)/include

成功后会显示这个文件的颜色是绿色的。。


第三行是源文件所在路径名,用pwd命令找到即可。


后面的都是make 用的命令,具体可以自己添加即可。



Makefile写完后,写模块程序,写完后,就可以
make all 
这时会生成.ko文件。加载 insmod *.ko(root权限)。
成功后,可以用dmesg命令看到程序的运行结果。



上面说了那么多,下面开始编写访问内核空间的模块程序。。。


#include <linux/module.h>

#include <linux/init.h>

#include <linux/slab.h>

#include <linux/mm.h>

#include <linux/vmalloc.h>



unsigned long pagemem;

unsigned char *kmallocmem;

unsigned char *vmallocmem;



MODULE_LICENSE("GPL");



static int __init mmshow_init(void)

{

	printk("mmshow module is working\n");



	pagemem = __get_free_page(GFP_KERNEL);

	if(!pagemem)

		goto gfp_fail;

	printk(KERN_INFO "pagemem = 0x%lx\n",pagemem);



	kmallocmem = kmalloc(100 * sizeof(char),GFP_KERNEL);

	if(!kmallocmem)

		goto kmalloc_fail;

	printk(KERN_INFO "kmallocmem = 0x%p\n",kmallocmem);



	vmallocmem = vmalloc(1000000 * sizeof(char));

	if(!vmallocmem)

		goto vmalloc_fail;

	printk(KERN_INFO "vmallocmem = 0x%p\n",vmallocmem);



	return 0;



gfp_fail:

	free_page(pagemem);

kmalloc_fail:

	kfree(kmallocmem);

vmalloc_fail:

	vfree(vmallocmem);



	return -1;

}





static void __exit mmshow_exit(void)

{

	free_page(pagemem);

	kfree(kmallocmem);

	vfree(vmallocmem);



	printk("mmshow module is leaving\n");

}





module_init(mmshow_init);

module_exit(mmshow_exit);


程序中用到了内核函数和内核结构(在文件mm中有详细的说明)

这里简单说明_get_free_page(),kmalloc()vmalloc()都是用来申请内核空间的。_get_free_page每次可以申请到完整的一页,其他两个则不一定。

用上面的方法加载后输出结果dmseg

mmshow module is working

pagemem = 0xde7fa000

kmallocmem = 0xf49a64c0

vmallocmem = 0xfc209000


可以看到输出的地址实在0xC0000000-0xFFFFFFFF的内核空间的。
即我们的目的达到了,对内核空间有了感性的认识。

下面就开始来学习mm中的数据结构和函数吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值