memdup_user函数功能描述:memdup_user( )函数的功能是根据给定的一段地址空间(这里由void __user *src
和size_t len
决定),再分配一个内存空间,并将原地址空间中的内容拷贝到新分配的内存空间中,这里需要注意原地址空间是用户空间。
memdup_user文件包含
#include<linux/string.h>
memdup_user函数定义
在内核源码中的位置:linux-3.19.3/mm/util.c
函数定义格式:
void *memdup_user(const void __user * src, size_t len)
memdup_user输入参数说明
src
:给定的地址空间的起始地址,它是一个用户空间的地址。len
:要拷贝的原地址空间的长度。
memdup_user返回参数说明
返回新分配的内存空间的起始地址。
memdup_user实例解析
编写测试文件:memdup_user.c
头文件及全局变量声明如下:
#include <linux/string.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
static int __init memdup_user_init(void);
static void __exit memdup_user_exit(void);
#define len 20
模块初始化函数:
int __init memdup_user_init(void)
{
struct mm_struct * mm ;
unsigned long mm_start ;
mm = current->mm; //获取当前进程的地址空间
mm_start = mm->mmap->vm_start; //mm_start为当前进程地址空间的起始地址
printk("mm_start = 0x%lx\n", mm_start);
// 调用函数,从mm_start开始的地址空间拷贝len个字节的内容
unsigned long * addr = (unsigned long *) memdup_user( mm_start, len);
printk("addr = 0x%lx\n", (unsigned long)addr); //输出所拷贝的目标起始地址
printk("*addr = %lx\n", *addr); //输出第一个字
printk("*addr+1 = %lx\n", *(addr+1)); //输出第四个字
unsigned long * temp = addr;
int i = 0;
for(; i<len/4; i ++, temp ++) //循环输出地址中的字内容
printk("%lx\n", *temp);
return 0;
}
模块退出函数:
void __exit memdup_user_exit(void)
{
printk("exit ok! \n");
}
模块初始化及退出函数调用:
module_init(memdup_user_init);
module_exit(memdup_user_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod memdup_user.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
结果分析:
在本测试程序中,取当前进程的地址空间作为本测试函数所需要的用户空间,参数src的取值为当前进程地址空间的起始地址,len的值设置为20。为了防止以字节为单位读取的内存中的内容不可读,这里以字为单位读取。由输出结果可知,当前进程地址空间的起始地址为:mm_start = 0x7ff4dab26000;新分配的内存的起始地址为addr = 0xffff8800a165c520;新分配的内存空间第一个字的内容为*addr = 0x10102464c457f
,第二个字的内容为*(addr+1) = 0x0
。然后循环输出新内存空间中前len字节的内容(以字为单位输出),这些内容是由用户空间拷贝过去的,由输出结果可知它们依次为:0x10102464c457f,0x0, 0x7075646d003e0003,0x5d726573755f,0xffff8800a165cce0。